From 066809a99a6f3ca1c88f688277c119015be279ed Mon Sep 17 00:00:00 2001 From: Sayan Nandan <17377258+sntdevco@users.noreply.github.com> Date: Sun, 13 Oct 2019 19:15:15 +0530 Subject: [PATCH 1/2] Sync repo with rust-lang --- .gitattributes | 2 +- .gitignore | 3 + .gitmodules | 2 +- .mailmap | 24 +- CODE_OF_CONDUCT.md | 39 +- CONTRIBUTING.md | 7 +- Cargo.lock | 4366 +++++----- Cargo.toml | 1 + README.md | 31 +- RELEASES.md | 112 +- config.toml.example | 11 +- src/bootstrap/Cargo.toml | 2 +- src/bootstrap/README.md | 8 +- src/bootstrap/bin/main.rs | 3 - src/bootstrap/bin/rustc.rs | 199 +- src/bootstrap/bin/rustdoc.rs | 8 +- src/bootstrap/bootstrap.py | 49 +- src/bootstrap/builder.rs | 403 +- src/bootstrap/builder/tests.rs | 153 +- src/bootstrap/cc_detect.rs | 2 +- src/bootstrap/channel.rs | 2 +- src/bootstrap/check.rs | 82 +- src/bootstrap/compile.rs | 235 +- src/bootstrap/config.rs | 8 +- src/bootstrap/dist.rs | 229 +- src/bootstrap/doc.rs | 141 +- src/bootstrap/flags.rs | 6 +- src/bootstrap/install.rs | 3 +- src/bootstrap/lib.rs | 23 +- src/bootstrap/mk/Makefile.in | 9 + src/bootstrap/native.rs | 27 +- src/bootstrap/sanity.rs | 4 - src/bootstrap/test.rs | 108 +- src/bootstrap/tool.rs | 81 +- src/build_helper/lib.rs | 5 +- src/ci/azure-pipelines/auto.yml | 31 +- src/ci/azure-pipelines/master.yml | 2 +- .../azure-pipelines/steps/install-clang.yml | 2 +- .../azure-pipelines/steps/install-sccache.yml | 4 +- .../steps/install-windows-build-deps.yml | 79 +- src/ci/azure-pipelines/steps/run.yml | 20 +- src/ci/azure-pipelines/try.yml | 2 +- src/ci/docker/armhf-gnu/Dockerfile | 2 +- .../dist-i586-gnu-i586-i686-musl/Dockerfile | 1 - src/ci/docker/dist-various-1/Dockerfile | 6 +- .../dist-various-1/install-mips-musl.sh | 2 +- .../dist-various-1/install-mipsel-musl.sh | 2 +- .../dist-various-2/build-wasi-toolchain.sh | 2 +- src/ci/docker/dist-x86_64-linux/build-curl.sh | 6 +- .../docker/dist-x86_64-linux/build-openssl.sh | 2 +- .../build-netbsd-toolchain.sh | 2 +- src/ci/docker/i686-gnu-nopt/Dockerfile | 3 + src/ci/docker/i686-gnu/Dockerfile | 3 + src/ci/docker/scripts/android-sdk-manager.py | 8 +- src/ci/docker/scripts/freebsd-toolchain.sh | 2 +- src/ci/docker/scripts/musl-toolchain.sh | 26 - src/ci/docker/scripts/musl.sh | 26 +- src/ci/docker/scripts/sccache.sh | 2 +- src/ci/docker/x86_64-gnu-tools/Dockerfile | 3 + src/ci/install-awscli.sh | 2 +- src/ci/run.sh | 18 + src/doc/book | 2 +- src/doc/embedded-book | 2 +- src/doc/grammar.md | 813 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/doc/rustc-guide | 2 +- src/doc/rustc-ux-guidelines.md | 2 +- src/doc/rustc/src/codegen-options/index.md | 2 +- src/doc/rustc/src/command-line-arguments.md | 7 + src/doc/rustc/src/linker-plugin-lto.md | 1 + .../src/lints/listing/allowed-by-default.md | 2 +- src/doc/rustdoc/src/unstable-features.md | 63 +- .../src/compiler-flags/report-time.md | 80 + .../src/language-features/or-patterns.md | 36 + .../src/language-features/param-attrs.md | 27 - .../src/language-features/plugin.md | 16 +- .../src/language-features/track-caller.md | 5 + src/etc/generate-deriving-span-tests.py | 2 + src/etc/installer/exe/rust.iss | 6 +- src/etc/installer/msi/rust.wxs | 2 +- src/etc/lldb_batchmode.py | 5 +- src/etc/wasm32-shim.js | 108 +- src/grammar/.gitignore | 3 - src/grammar/lexer.l | 350 - src/grammar/parser-lalr-main.c | 193 - src/grammar/parser-lalr.y | 1982 ----- src/grammar/raw-string-literal-ambiguity.md | 64 - src/grammar/testparser.py | 66 - src/grammar/tokens.h | 99 - src/liballoc/alloc.rs | 1 - src/liballoc/borrow.rs | 12 +- src/liballoc/boxed.rs | 215 +- src/liballoc/collections/binary_heap.rs | 3 + src/liballoc/collections/btree/map.rs | 5 +- src/liballoc/collections/btree/node.rs | 6 +- src/liballoc/collections/btree/set.rs | 266 +- src/liballoc/collections/linked_list.rs | 15 +- src/liballoc/collections/linked_list/tests.rs | 47 +- src/liballoc/collections/mod.rs | 31 +- src/liballoc/collections/vec_deque.rs | 106 +- src/liballoc/lib.rs | 16 +- src/liballoc/macros.rs | 2 +- src/liballoc/raw_vec.rs | 209 +- src/liballoc/raw_vec/tests.rs | 6 +- src/liballoc/rc.rs | 205 +- src/liballoc/slice.rs | 17 +- src/liballoc/str.rs | 6 +- src/liballoc/string.rs | 29 +- src/liballoc/sync.rs | 210 +- src/liballoc/tests/btree/map.rs | 3 + src/liballoc/tests/btree/set.rs | 139 +- src/liballoc/tests/lib.rs | 2 +- src/liballoc/tests/str.rs | 10 +- src/liballoc/tests/string.rs | 14 +- src/liballoc/tests/vec.rs | 66 +- src/liballoc/tests/vec_deque.rs | 14 +- src/liballoc/vec.rs | 121 +- src/libarena/lib.rs | 2 +- src/libcore/any.rs | 101 +- src/libcore/ascii.rs | 9 + src/libcore/benches/slice.rs | 26 + src/libcore/bool.rs | 44 + src/libcore/cell.rs | 92 +- src/libcore/char/convert.rs | 16 +- src/libcore/char/decode.rs | 50 +- src/libcore/char/methods.rs | 33 - src/libcore/clone.rs | 6 + src/libcore/cmp.rs | 140 +- src/libcore/convert.rs | 57 +- src/libcore/default.rs | 6 + src/libcore/fmt/builders.rs | 13 +- src/libcore/fmt/mod.rs | 24 +- src/libcore/future/future.rs | 3 +- src/libcore/hash/mod.rs | 14 +- src/libcore/hint.rs | 38 +- src/libcore/intrinsics.rs | 53 +- src/libcore/iter/adapters/chain.rs | 45 +- src/libcore/iter/adapters/flatten.rs | 137 +- src/libcore/iter/adapters/mod.rs | 621 +- src/libcore/iter/adapters/zip.rs | 8 +- src/libcore/iter/sources.rs | 10 +- src/libcore/iter/traits/accum.rs | 8 +- src/libcore/iter/traits/collect.rs | 5 +- src/libcore/iter/traits/double_ended.rs | 27 +- src/libcore/iter/traits/iterator.rs | 449 +- src/libcore/lib.rs | 11 +- src/libcore/macros.rs | 323 +- src/libcore/marker.rs | 10 +- src/libcore/mem/maybe_uninit.rs | 29 +- src/libcore/mem/mod.rs | 35 +- src/libcore/num/f32.rs | 2 +- src/libcore/num/f64.rs | 2 +- src/libcore/num/mod.rs | 112 +- src/libcore/num/wrapping.rs | 8 + src/libcore/ops/function.rs | 8 - src/libcore/option.rs | 37 +- src/libcore/panicking.rs | 1 - src/libcore/pin.rs | 59 +- src/libcore/prelude/v1.rs | 37 +- src/libcore/ptr/mod.rs | 214 +- src/libcore/ptr/non_null.rs | 2 +- src/libcore/ptr/unique.rs | 8 + src/libcore/result.rs | 81 + src/libcore/slice/mod.rs | 104 +- src/libcore/slice/rotate.rs | 221 +- src/libcore/str/mod.rs | 131 +- src/libcore/sync/atomic.rs | 33 +- src/libcore/task/poll.rs | 28 + src/libcore/tests/bool.rs | 7 + src/libcore/tests/cmp.rs | 24 +- src/libcore/tests/iter.rs | 173 + src/libcore/tests/lib.rs | 4 + src/libcore/tests/num/dec2flt/mod.rs | 1 + src/libcore/tests/num/flt2dec/estimator.rs | 7 +- src/libcore/tests/num/flt2dec/mod.rs | 16 +- src/libcore/tests/num/flt2dec/random.rs | 23 +- .../tests/num/flt2dec/strategy/dragon.rs | 1 + .../tests/num/flt2dec/strategy/grisu.rs | 1 + src/libcore/tests/slice.rs | 57 + src/libcore/time.rs | 36 +- src/libcore/unicode/mod.rs | 5 - src/libcore/unicode/printable.py | 2 +- src/libcore/unicode/tables.rs | 401 +- src/libcore/unicode/unicode.py | 17 +- src/libfmt_macros/Cargo.toml | 2 +- src/libfmt_macros/lib.rs | 15 +- src/libproc_macro/Cargo.toml | 3 + src/libproc_macro/bridge/client.rs | 8 + src/libproc_macro/bridge/mod.rs | 1 + src/libproc_macro/lib.rs | 20 +- src/libproc_macro/quote.rs | 4 +- src/librustc/Cargo.toml | 12 +- src/librustc/arena.rs | 19 +- src/librustc/cfg/construct.rs | 528 -- src/librustc/cfg/graphviz.rs | 123 - src/librustc/cfg/mod.rs | 60 - src/librustc/dep_graph/dep_node.rs | 40 +- src/librustc/dep_graph/dep_tracking_map.rs | 87 - src/librustc/dep_graph/graph.rs | 44 +- src/librustc/dep_graph/mod.rs | 2 - src/librustc/dep_graph/serialized.rs | 4 +- src/librustc/error_codes.rs | 368 +- src/librustc/hir/check_attr.rs | 119 +- src/librustc/hir/def.rs | 30 +- src/librustc/hir/def_id.rs | 39 +- src/librustc/hir/intravisit.rs | 77 +- src/librustc/hir/itemlikevisit.rs | 21 +- src/librustc/hir/lowering.rs | 3570 +------- src/librustc/hir/lowering/expr.rs | 1493 ++++ src/librustc/hir/lowering/item.rs | 1466 ++++ src/librustc/hir/map/blocks.rs | 22 +- src/librustc/hir/map/collector.rs | 34 +- src/librustc/hir/map/def_collector.rs | 111 +- src/librustc/hir/map/definitions.rs | 100 +- src/librustc/hir/map/hir_id_validator.rs | 2 +- src/librustc/hir/map/mod.rs | 461 +- src/librustc/hir/mod.rs | 316 +- src/librustc/hir/pat_util.rs | 121 +- src/librustc/hir/print.rs | 119 +- src/librustc/hir/ptr.rs | 7 +- src/librustc/hir/upvars.rs | 4 +- src/librustc/ich/hcx.rs | 88 +- src/librustc/ich/impls_hir.rs | 124 +- src/librustc/ich/impls_syntax.rs | 106 +- src/librustc/ich/impls_ty.rs | 95 +- src/librustc/infer/canonical/canonicalizer.rs | 10 +- src/librustc/infer/canonical/mod.rs | 30 +- .../infer/canonical/query_response.rs | 49 +- src/librustc/infer/canonical/substitute.rs | 8 +- src/librustc/infer/combine.rs | 11 +- src/librustc/infer/equate.rs | 44 +- src/librustc/infer/error_reporting/mod.rs | 138 +- .../infer/error_reporting/need_type_info.rs | 261 +- .../nice_region_error/different_lifetimes.rs | 22 +- .../nice_region_error/find_anon_type.rs | 8 +- .../nice_region_error/named_anon_conflict.rs | 32 +- .../nice_region_error/outlives_closure.rs | 2 +- .../nice_region_error/placeholder_error.rs | 67 +- .../error_reporting/nice_region_error/util.rs | 46 +- src/librustc/infer/error_reporting/note.rs | 4 +- src/librustc/infer/freshen.rs | 2 +- src/librustc/infer/fudge.rs | 2 +- src/librustc/infer/glb.rs | 7 +- src/librustc/infer/lattice.rs | 2 +- .../infer/lexical_region_resolve/mod.rs | 2 +- src/librustc/infer/lub.rs | 7 +- src/librustc/infer/mod.rs | 137 +- src/librustc/infer/nll_relate/mod.rs | 16 +- src/librustc/infer/opaque_types/mod.rs | 74 +- src/librustc/infer/outlives/obligations.rs | 10 +- src/librustc/infer/outlives/verify.rs | 4 +- .../infer/region_constraints/leak_check.rs | 8 +- src/librustc/infer/region_constraints/mod.rs | 2 +- src/librustc/infer/resolve.rs | 4 +- src/librustc/infer/sub.rs | 46 +- src/librustc/infer/type_variable.rs | 10 +- src/librustc/lib.rs | 18 +- src/librustc/lint/builtin.rs | 17 +- src/librustc/lint/context.rs | 91 +- src/librustc/lint/internal.rs | 59 +- src/librustc/lint/levels.rs | 19 +- src/librustc/lint/mod.rs | 121 +- src/librustc/macros.rs | 24 +- src/librustc/middle/borrowck.rs | 31 - src/librustc/middle/cstore.rs | 22 +- src/librustc/middle/dependency_format.rs | 378 +- src/librustc/middle/diagnostic_items.rs | 123 + src/librustc/middle/exported_symbols.rs | 7 +- src/librustc/middle/expr_use_visitor.rs | 509 +- src/librustc/middle/lang_items.rs | 63 +- src/librustc/middle/lib_features.rs | 2 +- src/librustc/middle/mem_categorization.rs | 108 +- src/librustc/middle/reachable.rs | 32 +- src/librustc/middle/region.rs | 112 +- src/librustc/middle/resolve_lifetime.rs | 170 +- src/librustc/middle/stability.rs | 56 +- src/librustc/middle/weak_lang_items.rs | 6 +- src/librustc/mir/cache.rs | 10 +- src/librustc/mir/interpret/allocation.rs | 337 +- src/librustc/mir/interpret/error.rs | 60 +- src/librustc/mir/interpret/mod.rs | 123 +- src/librustc/mir/interpret/pointer.rs | 14 +- src/librustc/mir/interpret/value.rs | 42 +- src/librustc/mir/mod.rs | 641 +- src/librustc/mir/mono.rs | 12 +- src/librustc/mir/tcx.rs | 25 +- src/librustc/mir/traversal.rs | 2 +- src/librustc/mir/visit.rs | 97 +- src/librustc/query/mod.rs | 79 +- src/librustc/session/config.rs | 244 +- src/librustc/session/config/tests.rs | 14 +- src/librustc/session/mod.rs | 137 +- src/librustc/traits/auto_trait.rs | 6 +- src/librustc/traits/chalk_fulfill.rs | 5 +- src/librustc/traits/codegen/mod.rs | 29 +- src/librustc/traits/coherence.rs | 36 +- src/librustc/traits/error_reporting.rs | 638 +- src/librustc/traits/fulfill.rs | 81 +- src/librustc/traits/mod.rs | 79 +- src/librustc/traits/object_safety.rs | 202 +- src/librustc/traits/on_unimplemented.rs | 19 +- src/librustc/traits/project.rs | 53 +- src/librustc/traits/query/dropck_outlives.rs | 16 +- .../traits/query/evaluate_obligation.rs | 9 +- src/librustc/traits/query/method_autoderef.rs | 10 +- src/librustc/traits/query/normalize.rs | 44 +- src/librustc/traits/query/outlives_bounds.rs | 9 +- .../traits/query/type_op/ascribe_user_type.rs | 8 +- src/librustc/traits/query/type_op/eq.rs | 8 +- .../query/type_op/implied_outlives_bounds.rs | 8 +- src/librustc/traits/query/type_op/mod.rs | 21 +- .../traits/query/type_op/normalize.rs | 38 +- src/librustc/traits/query/type_op/outlives.rs | 8 +- .../traits/query/type_op/prove_predicate.rs | 8 +- src/librustc/traits/query/type_op/subtype.rs | 8 +- src/librustc/traits/select.rs | 170 +- src/librustc/traits/specialize/mod.rs | 2 +- .../traits/specialize/specialization_graph.rs | 95 +- src/librustc/traits/structural_impls.rs | 32 +- src/librustc/traits/util.rs | 47 +- src/librustc/ty/_match.rs | 2 +- src/librustc/ty/cast.rs | 2 +- src/librustc/ty/codec.rs | 27 +- src/librustc/ty/context.rs | 512 +- src/librustc/ty/error.rs | 146 +- src/librustc/ty/fast_reject.rs | 9 +- src/librustc/ty/flags.rs | 45 +- src/librustc/ty/fold.rs | 29 +- .../ty/inhabitedness/def_id_forest.rs | 18 +- src/librustc/ty/inhabitedness/mod.rs | 37 +- src/librustc/ty/instance.rs | 66 +- src/librustc/ty/layout.rs | 208 +- src/librustc/ty/mod.rs | 246 +- src/librustc/ty/outlives.rs | 6 +- src/librustc/ty/print/mod.rs | 27 +- src/librustc/ty/print/obsolete.rs | 8 +- src/librustc/ty/print/pretty.rs | 291 +- src/librustc/ty/query/config.rs | 15 +- src/librustc/ty/query/job.rs | 4 +- src/librustc/ty/query/mod.rs | 9 +- src/librustc/ty/query/on_disk_cache.rs | 323 +- src/librustc/ty/query/plumbing.rs | 306 +- src/librustc/ty/relate.rs | 111 +- src/librustc/ty/structural_impls.rs | 36 +- src/librustc/ty/sty.rs | 238 +- src/librustc/ty/subst.rs | 218 +- src/librustc/ty/trait_def.rs | 7 +- src/librustc/ty/util.rs | 123 +- src/librustc/ty/walk.rs | 14 +- src/librustc/ty/wf.rs | 8 +- src/librustc/util/common.rs | 153 +- src/librustc/util/profiling.rs | 326 +- src/librustc_apfloat/ieee.rs | 20 +- src/librustc_apfloat/lib.rs | 39 +- src/librustc_apfloat/ppc.rs | 6 +- src/librustc_asan/build.rs | 4 + src/librustc_ast_borrowck/Cargo.toml | 22 - src/librustc_ast_borrowck/borrowck/README.md | 1167 --- .../borrowck/check_loans.rs | 680 -- .../borrowck/gather_loans/gather_moves.rs | 135 - .../borrowck/gather_loans/lifetime.rs | 113 - .../borrowck/gather_loans/mod.rs | 433 - .../borrowck/gather_loans/restrictions.rs | 179 - src/librustc_ast_borrowck/borrowck/mod.rs | 621 -- .../borrowck/move_data.rs | 730 -- src/librustc_ast_borrowck/dataflow.rs | 673 -- src/librustc_ast_borrowck/graphviz.rs | 146 - src/librustc_ast_borrowck/lib.rs | 22 - src/librustc_codegen_llvm/Cargo.toml | 4 - src/librustc_codegen_llvm/abi.rs | 14 +- src/librustc_codegen_llvm/allocator.rs | 4 +- src/librustc_codegen_llvm/asm.rs | 7 +- src/librustc_codegen_llvm/attributes.rs | 62 +- src/librustc_codegen_llvm/back/archive.rs | 3 +- src/librustc_codegen_llvm/back/lto.rs | 202 +- src/librustc_codegen_llvm/back/write.rs | 43 +- src/librustc_codegen_llvm/base.rs | 10 +- src/librustc_codegen_llvm/builder.rs | 39 +- src/librustc_codegen_llvm/callee.rs | 2 +- src/librustc_codegen_llvm/common.rs | 39 +- src/librustc_codegen_llvm/consts.rs | 84 +- src/librustc_codegen_llvm/context.rs | 7 +- .../debuginfo/create_scope_map.rs | 4 +- src/librustc_codegen_llvm/debuginfo/gdb.rs | 4 +- .../debuginfo/metadata.rs | 74 +- src/librustc_codegen_llvm/debuginfo/mod.rs | 57 +- src/librustc_codegen_llvm/error_codes.rs | 2 +- src/librustc_codegen_llvm/intrinsic.rs | 112 +- src/librustc_codegen_llvm/lib.rs | 37 +- src/librustc_codegen_llvm/llvm/ffi.rs | 2 + src/librustc_codegen_llvm/type_of.rs | 12 +- src/librustc_codegen_ssa/Cargo.toml | 4 +- src/librustc_codegen_ssa/back/archive.rs | 5 +- src/librustc_codegen_ssa/back/command.rs | 26 +- src/librustc_codegen_ssa/back/link.rs | 140 +- src/librustc_codegen_ssa/back/linker.rs | 124 +- .../back/symbol_export.rs | 14 +- src/librustc_codegen_ssa/back/write.rs | 126 +- src/librustc_codegen_ssa/base.rs | 45 +- src/librustc_codegen_ssa/callee.rs | 17 + src/librustc_codegen_ssa/common.rs | 7 +- .../debuginfo/type_names.rs | 16 +- src/librustc_codegen_ssa/error_codes.rs | 2 +- src/librustc_codegen_ssa/glue.rs | 4 +- src/librustc_codegen_ssa/lib.rs | 12 +- src/librustc_codegen_ssa/mir/analyze.rs | 29 +- src/librustc_codegen_ssa/mir/block.rs | 149 +- src/librustc_codegen_ssa/mir/constant.rs | 4 +- src/librustc_codegen_ssa/mir/mod.rs | 144 +- src/librustc_codegen_ssa/mir/operand.rs | 73 +- src/librustc_codegen_ssa/mir/place.rs | 74 +- src/librustc_codegen_ssa/mir/rvalue.rs | 19 +- src/librustc_codegen_ssa/mir/statement.rs | 35 +- src/librustc_codegen_ssa/mono_item.rs | 4 +- src/librustc_codegen_ssa/traits/asm.rs | 2 + src/librustc_codegen_ssa/traits/backend.rs | 8 +- src/librustc_codegen_ssa/traits/builder.rs | 5 +- src/librustc_codegen_ssa/traits/debuginfo.rs | 4 +- src/librustc_codegen_ssa/traits/intrinsic.rs | 5 +- src/librustc_codegen_ssa/traits/statics.rs | 6 +- src/librustc_codegen_ssa/traits/type_.rs | 2 +- src/librustc_codegen_utils/Cargo.toml | 3 +- src/librustc_codegen_utils/codegen_backend.rs | 2 - src/librustc_codegen_utils/lib.rs | 1 - .../symbol_names/legacy.rs | 20 +- src/librustc_codegen_utils/symbol_names/v0.rs | 42 +- .../symbol_names_test.rs | 2 +- src/librustc_data_structures/Cargo.toml | 9 +- src/librustc_data_structures/fingerprint.rs | 2 +- .../graph/dominators/mod.rs | 2 +- .../graph/implementation/mod.rs | 6 +- .../graph/iterate/mod.rs | 208 +- .../graph/iterate/tests.rs | 11 + src/librustc_data_structures/graph/mod.rs | 12 +- src/librustc_data_structures/graph/scc/mod.rs | 2 +- .../graph/vec_graph/mod.rs | 2 +- src/librustc_data_structures/lib.rs | 7 +- .../obligation_forest/graphviz.rs | 4 +- .../obligation_forest/mod.rs | 494 +- .../obligation_forest/node_index.rs | 20 - .../obligation_forest/tests.rs | 28 +- .../owning_ref/mod.rs | 8 +- src/librustc_data_structures/stable_hasher.rs | 168 +- src/librustc_data_structures/stable_map.rs | 99 + src/librustc_data_structures/stable_set.rs | 77 + src/librustc_data_structures/svh.rs | 6 +- src/librustc_data_structures/thin_vec.rs | 6 +- src/librustc_data_structures/tiny_list.rs | 56 +- .../tiny_list/tests.rs | 35 +- .../transitive_relation.rs | 16 +- .../vec_linked_list.rs | 2 +- src/librustc_data_structures/work_queue.rs | 4 +- src/librustc_driver/Cargo.toml | 6 +- src/librustc_driver/args.rs | 53 + src/librustc_driver/lib.rs | 224 +- src/librustc_driver/pretty.rs | 184 +- src/librustc_errors/Cargo.toml | 1 + .../annotate_snippet_emitter_writer.rs | 26 +- src/librustc_errors/diagnostic.rs | 112 +- src/librustc_errors/diagnostic_builder.rs | 123 +- src/librustc_errors/emitter.rs | 1120 ++- src/librustc_errors/lib.rs | 723 +- src/librustc_errors/styled_buffer.rs | 2 +- src/librustc_incremental/Cargo.toml | 2 +- .../assert_module_sources.rs | 12 +- .../persist/dirty_clean.rs | 35 +- src/librustc_incremental/persist/load.rs | 7 +- src/librustc_incremental/persist/save.rs | 8 + src/librustc_index/Cargo.toml | 14 + .../bit_set.rs | 4 +- .../bit_set/tests.rs | 0 src/librustc_index/lib.rs | 7 + .../indexed_vec.rs => librustc_index/vec.rs} | 2 +- src/librustc_interface/Cargo.toml | 6 +- src/librustc_interface/build.rs | 4 + src/librustc_interface/interface.rs | 18 +- src/librustc_interface/lib.rs | 1 - src/librustc_interface/passes.rs | 192 +- src/librustc_interface/profile/mod.rs | 297 - src/librustc_interface/profile/trace.rs | 304 - src/librustc_interface/queries.rs | 74 +- src/librustc_interface/util.rs | 237 +- src/librustc_lexer/Cargo.toml | 12 +- src/librustc_lexer/src/lib.rs | 320 +- src/librustc_lexer/src/unescape.rs | 36 +- src/librustc_lexer/src/unescape/tests.rs | 11 +- src/librustc_lint/Cargo.toml | 1 + src/librustc_lint/builtin.rs | 304 +- src/librustc_lint/error_codes.rs | 7 +- src/librustc_lint/lib.rs | 14 +- src/librustc_lint/nonstandard_style.rs | 25 +- src/librustc_lint/redundant_semicolon.rs | 52 + src/librustc_lint/types.rs | 187 +- src/librustc_lint/unused.rs | 154 +- src/librustc_llvm/build.rs | 17 +- src/librustc_lsan/build.rs | 4 + src/librustc_macros/Cargo.toml | 8 +- src/librustc_macros/src/hash_stable.rs | 12 +- src/librustc_macros/src/lib.rs | 3 +- src/librustc_macros/src/query.rs | 10 +- src/librustc_metadata/Cargo.toml | 1 + src/librustc_metadata/creader.rs | 239 +- src/librustc_metadata/cstore.rs | 32 +- src/librustc_metadata/cstore_impl.rs | 95 +- src/librustc_metadata/decoder.rs | 312 +- src/librustc_metadata/dependency_format.rs | 370 + src/librustc_metadata/encoder.rs | 642 +- src/librustc_metadata/error_codes.rs | 12 +- src/librustc_metadata/foreign_modules.rs | 2 +- src/librustc_metadata/index.rs | 10 +- src/librustc_metadata/lib.rs | 6 +- src/librustc_metadata/link_args.rs | 2 +- src/librustc_metadata/locator.rs | 35 +- src/librustc_metadata/native_libs.rs | 19 +- src/librustc_metadata/schema.rs | 162 +- src/librustc_mir/Cargo.toml | 5 +- src/librustc_mir/borrow_check/borrow_set.rs | 6 +- .../borrow_check/conflict_errors.rs | 164 +- .../borrow_check/error_reporting.rs | 144 +- src/librustc_mir/borrow_check/flows.rs | 7 +- src/librustc_mir/borrow_check/location.rs | 4 +- src/librustc_mir/borrow_check/mod.rs | 240 +- src/librustc_mir/borrow_check/move_errors.rs | 125 +- .../borrow_check/mutability_errors.rs | 136 +- .../borrow_check/nll/constraint_generation.rs | 30 +- .../borrow_check/nll/constraints/graph.rs | 2 +- .../borrow_check/nll/constraints/mod.rs | 6 +- .../borrow_check/nll/explain_borrow/mod.rs | 33 +- src/librustc_mir/borrow_check/nll/facts.rs | 19 +- .../borrow_check/nll/invalidation.rs | 2 +- .../borrow_check/nll/member_constraints.rs | 4 +- src/librustc_mir/borrow_check/nll/mod.rs | 93 +- .../nll/region_infer/error_reporting/mod.rs | 386 +- .../error_reporting/region_name.rs | 247 +- .../region_infer/error_reporting/var_name.rs | 2 +- .../borrow_check/nll/region_infer/mod.rs | 83 +- .../borrow_check/nll/region_infer/values.rs | 10 +- src/librustc_mir/borrow_check/nll/renumber.rs | 52 +- .../nll/type_check/constraint_conversion.rs | 8 +- .../nll/type_check/input_output.rs | 2 +- .../nll/type_check/liveness/local_use_map.rs | 30 +- .../nll/type_check/liveness/mod.rs | 52 +- .../nll/type_check/liveness/polonius.rs | 76 +- .../nll/type_check/liveness/trace.rs | 129 +- .../borrow_check/nll/type_check/mod.rs | 408 +- .../borrow_check/nll/type_check/relate_tys.rs | 8 +- .../borrow_check/nll/universal_regions.rs | 67 +- src/librustc_mir/borrow_check/path_utils.rs | 23 +- src/librustc_mir/borrow_check/place_ext.rs | 87 +- .../borrow_check/places_conflict.rs | 330 +- src/librustc_mir/borrow_check/prefixes.rs | 201 +- src/librustc_mir/borrow_check/used_muts.rs | 4 +- src/librustc_mir/build/block.rs | 2 +- src/librustc_mir/build/cfg.rs | 2 +- src/librustc_mir/build/expr/as_constant.rs | 2 +- src/librustc_mir/build/expr/as_place.rs | 159 +- src/librustc_mir/build/expr/as_rvalue.rs | 34 +- src/librustc_mir/build/expr/as_temp.rs | 2 - src/librustc_mir/build/expr/into.rs | 60 +- src/librustc_mir/build/expr/stmt.rs | 2 +- src/librustc_mir/build/matches/mod.rs | 124 +- src/librustc_mir/build/matches/simplify.rs | 26 +- src/librustc_mir/build/matches/test.rs | 114 +- src/librustc_mir/build/matches/util.rs | 10 +- src/librustc_mir/build/misc.rs | 5 +- src/librustc_mir/build/mod.rs | 76 +- src/librustc_mir/build/scope.rs | 167 +- src/librustc_mir/const_eval.rs | 84 +- src/librustc_mir/dataflow/at_location.rs | 2 +- .../dataflow/drop_flag_effects.rs | 19 +- src/librustc_mir/dataflow/generic.rs | 613 ++ src/librustc_mir/dataflow/generic/graphviz.rs | 413 + .../dataflow/impls/borrowed_locals.rs | 17 +- src/librustc_mir/dataflow/impls/borrows.rs | 20 +- .../dataflow/impls/indirect_mutation.rs | 164 + src/librustc_mir/dataflow/impls/mod.rs | 12 +- .../dataflow/impls/storage_liveness.rs | 42 +- src/librustc_mir/dataflow/mod.rs | 59 +- .../dataflow/move_paths/abs_domain.rs | 40 +- .../dataflow/move_paths/builder.rs | 295 +- src/librustc_mir/dataflow/move_paths/mod.rs | 81 +- src/librustc_mir/error_codes.rs | 214 +- src/librustc_mir/hair/constant.rs | 2 +- src/librustc_mir/hair/cx/block.rs | 10 +- src/librustc_mir/hair/cx/expr.rs | 35 +- src/librustc_mir/hair/cx/mod.rs | 24 +- src/librustc_mir/hair/mod.rs | 19 +- src/librustc_mir/hair/pattern/_match.rs | 547 +- src/librustc_mir/hair/pattern/check_match.rs | 512 +- src/librustc_mir/hair/pattern/mod.rs | 458 +- src/librustc_mir/hair/util.rs | 2 +- src/librustc_mir/interpret/cast.rs | 39 +- src/librustc_mir/interpret/eval_context.rs | 146 +- src/librustc_mir/interpret/intern.rs | 273 +- src/librustc_mir/interpret/intrinsics.rs | 173 +- .../interpret/intrinsics/type_name.rs | 34 +- src/librustc_mir/interpret/machine.rs | 21 +- src/librustc_mir/interpret/memory.rs | 125 +- src/librustc_mir/interpret/mod.rs | 4 +- src/librustc_mir/interpret/operand.rs | 171 +- src/librustc_mir/interpret/operator.rs | 127 +- src/librustc_mir/interpret/place.rs | 155 +- src/librustc_mir/interpret/snapshot.rs | 35 +- src/librustc_mir/interpret/step.rs | 17 +- src/librustc_mir/interpret/terminator.rs | 29 +- src/librustc_mir/interpret/traits.rs | 21 +- src/librustc_mir/interpret/validity.rs | 107 +- src/librustc_mir/interpret/visitor.rs | 2 +- src/librustc_mir/lib.rs | 13 +- src/librustc_mir/lints.rs | 4 +- src/librustc_mir/monomorphize/collector.rs | 104 +- src/librustc_mir/monomorphize/item.rs | 204 - src/librustc_mir/monomorphize/partitioning.rs | 32 +- src/librustc_mir/shim.rs | 110 +- src/librustc_mir/transform/add_call_guards.rs | 6 +- .../transform/add_moves_for_packed_drops.rs | 4 +- src/librustc_mir/transform/add_retag.rs | 57 +- .../transform/check_consts/mod.rs | 52 + .../transform/check_consts/ops.rs | 339 + .../transform/check_consts/qualifs.rs | 289 + .../transform/check_consts/resolver.rs | 350 + .../transform/check_consts/validation.rs | 593 ++ src/librustc_mir/transform/check_unsafety.rs | 235 +- .../transform/cleanup_post_borrowck.rs | 6 +- src/librustc_mir/transform/const_prop.rs | 590 +- src/librustc_mir/transform/copy_prop.rs | 58 +- src/librustc_mir/transform/deaggregator.rs | 10 +- src/librustc_mir/transform/dump_mir.rs | 4 +- src/librustc_mir/transform/elaborate_drops.rs | 64 +- src/librustc_mir/transform/erase_regions.rs | 10 +- src/librustc_mir/transform/generator.rs | 103 +- src/librustc_mir/transform/inline.rs | 72 +- src/librustc_mir/transform/instcombine.rs | 44 +- src/librustc_mir/transform/mod.rs | 135 +- src/librustc_mir/transform/no_landing_pads.rs | 4 +- src/librustc_mir/transform/promote_consts.rs | 82 +- src/librustc_mir/transform/qualify_consts.rs | 638 +- .../transform/qualify_min_const_fn.rs | 123 +- .../transform/remove_noop_landing_pads.rs | 12 +- src/librustc_mir/transform/rustc_peek.rs | 320 +- src/librustc_mir/transform/simplify.rs | 12 +- .../transform/simplify_branches.rs | 4 +- .../transform/uniform_array_move_out.rs | 203 +- src/librustc_mir/util/aggregate.rs | 8 +- src/librustc_mir/util/alignment.rs | 12 +- src/librustc_mir/util/borrowck_errors.rs | 4 +- src/librustc_mir/util/def_use.rs | 2 +- src/librustc_mir/util/elaborate_drops.rs | 25 +- src/librustc_mir/util/graphviz.rs | 2 +- src/librustc_mir/util/liveness.rs | 4 +- src/librustc_mir/util/patch.rs | 4 +- src/librustc_mir/util/pretty.rs | 9 +- src/librustc_msan/build.rs | 4 + src/librustc_passes/Cargo.toml | 2 + src/librustc_passes/ast_validation.rs | 42 +- .../middle => librustc_passes}/dead.rs | 124 +- .../middle => librustc_passes}/entry.rs | 102 +- src/librustc_passes/error_codes.rs | 320 +- src/librustc_passes/hir_stats.rs | 13 +- .../middle => librustc_passes}/intrinsicck.rs | 24 +- src/librustc_passes/layout_test.rs | 2 +- src/librustc_passes/lib.rs | 19 +- .../middle => librustc_passes}/liveness.rs | 369 +- src/librustc_passes/loops.rs | 40 +- src/librustc_passes/rvalue_promotion.rs | 662 -- src/librustc_plugin/Cargo.toml | 5 +- src/librustc_plugin/build.rs | 2 +- src/librustc_plugin/deprecated/Cargo.toml | 14 + src/librustc_plugin/deprecated/lib.rs | 8 + src/librustc_plugin/error_codes.rs | 11 +- src/librustc_plugin/lib.rs | 8 +- src/librustc_privacy/error_codes.rs | 28 +- src/librustc_privacy/lib.rs | 249 +- src/librustc_resolve/Cargo.toml | 1 - src/librustc_resolve/build_reduced_graph.rs | 1016 ++- src/librustc_resolve/check_unused.rs | 205 +- src/librustc_resolve/diagnostics.rs | 977 +-- src/librustc_resolve/error_codes.rs | 88 +- src/librustc_resolve/late.rs | 2095 +++++ src/librustc_resolve/late/diagnostics.rs | 777 ++ src/librustc_resolve/lib.rs | 3192 +------- src/librustc_resolve/macros.rs | 410 +- src/librustc_resolve/resolve_imports.rs | 369 +- src/librustc_save_analysis/Cargo.toml | 1 - src/librustc_save_analysis/dump_visitor.rs | 266 +- src/librustc_save_analysis/lib.rs | 52 +- src/librustc_save_analysis/sig.rs | 10 +- src/librustc_target/Cargo.toml | 1 + src/librustc_target/abi/call/mod.rs | 14 +- src/librustc_target/abi/call/x86.rs | 2 +- src/librustc_target/abi/mod.rs | 24 +- .../spec/aarch64_unknown_none.rs | 4 +- .../spec/aarch64_unknown_none_softfloat.rs | 37 + .../spec/aarch64_uwp_windows_msvc.rs | 24 + .../spec/aarch64_wrs_vxworks.rs | 5 +- src/librustc_target/spec/apple_base.rs | 16 + src/librustc_target/spec/apple_ios_base.rs | 33 +- src/librustc_target/spec/arm_wrs_vxworks.rs | 31 - .../spec/arm_wrs_vxworks_sf.rs | 25 - ...vxworks.rs => armv7_wrs_vxworks_eabihf.rs} | 8 +- src/librustc_target/spec/i586_wrs_vxworks.rs | 8 - src/librustc_target/spec/i686_apple_darwin.rs | 1 + src/librustc_target/spec/i686_unknown_uefi.rs | 98 + .../spec/i686_uwp_windows_msvc.rs | 22 + src/librustc_target/spec/i686_wrs_vxworks.rs | 2 +- .../spec/i686_wrs_vxworks_gnu.rs | 23 - src/librustc_target/spec/linux_kernel_base.rs | 26 + ...f.rs => mips64_unknown_linux_muslabi64.rs} | 19 +- .../spec/mips64el_unknown_linux_muslabi64.rs | 25 + src/librustc_target/spec/mod.rs | 25 +- .../spec/powerpc64_wrs_vxworks.rs | 3 +- .../spec/powerpc_wrs_vxworks.rs | 1 - .../spec/powerpc_wrs_vxworks_gnusf.rs | 26 - .../spec/powerpc_wrs_vxworks_gnuspesf.rs | 27 - .../spec/powerpc_wrs_vxworks_spe.rs | 1 - .../spec/sparc64_unknown_openbsd.rs | 22 + src/librustc_target/spec/vxworks_base.rs | 27 +- src/librustc_target/spec/wasm32_wasi.rs | 4 + .../spec/windows_uwp_msvc_base.rs | 33 + .../spec/x86_64_apple_darwin.rs | 1 + .../spec/x86_64_apple_ios_macabi.rs | 23 + .../spec/x86_64_linux_kernel.rs | 31 + .../spec/x86_64_uwp_windows_msvc.rs | 22 + .../spec/x86_64_wrs_vxworks.rs | 1 + src/librustc_traits/Cargo.toml | 2 - src/librustc_traits/chalk_context/mod.rs | 18 +- .../chalk_context/program_clauses/builtin.rs | 25 +- .../chalk_context/program_clauses/mod.rs | 2 +- .../chalk_context/resolvent_ops.rs | 8 +- src/librustc_traits/chalk_context/unify.rs | 2 +- src/librustc_traits/dropck_outlives.rs | 8 +- src/librustc_traits/evaluate_obligation.rs | 2 + src/librustc_traits/generic_types.rs | 16 +- src/librustc_traits/lowering/environment.rs | 10 +- src/librustc_traits/lowering/mod.rs | 4 +- src/librustc_traits/type_op.rs | 4 +- src/librustc_tsan/build.rs | 4 + src/librustc_typeck/Cargo.toml | 1 + src/librustc_typeck/astconv.rs | 73 +- src/librustc_typeck/check/_match.rs | 1066 +-- src/librustc_typeck/check/autoderef.rs | 2 +- src/librustc_typeck/check/callee.rs | 62 +- src/librustc_typeck/check/cast.rs | 18 +- src/librustc_typeck/check/closure.rs | 161 +- src/librustc_typeck/check/coercion.rs | 141 +- src/librustc_typeck/check/compare_method.rs | 33 +- src/librustc_typeck/check/demand.rs | 95 +- src/librustc_typeck/check/dropck.rs | 86 +- src/librustc_typeck/check/expr.rs | 515 +- .../check/generator_interior.rs | 60 +- src/librustc_typeck/check/intrinsic.rs | 13 +- src/librustc_typeck/check/method/confirm.rs | 12 +- src/librustc_typeck/check/method/mod.rs | 68 +- src/librustc_typeck/check/method/probe.rs | 16 +- src/librustc_typeck/check/method/suggest.rs | 209 +- src/librustc_typeck/check/mod.rs | 1023 ++- src/librustc_typeck/check/op.rs | 53 +- src/librustc_typeck/check/pat.rs | 1223 +++ src/librustc_typeck/check/regionck.rs | 98 +- src/librustc_typeck/check/upvar.rs | 73 +- src/librustc_typeck/check/wfcheck.rs | 211 +- src/librustc_typeck/check/writeback.rs | 55 +- src/librustc_typeck/check_unused.rs | 4 +- src/librustc_typeck/coherence/builtin.rs | 62 +- .../coherence/inherent_impls.rs | 12 +- .../coherence/inherent_impls_overlap.rs | 2 +- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/coherence/orphan.rs | 4 +- src/librustc_typeck/coherence/unsafety.rs | 2 +- src/librustc_typeck/collect.rs | 390 +- .../constrained_generic_params.rs | 20 +- src/librustc_typeck/error_codes.rs | 259 +- src/librustc_typeck/impl_wf_check.rs | 17 +- src/librustc_typeck/lib.rs | 25 +- .../outlives/implicit_infer.rs | 40 +- src/librustc_typeck/outlives/mod.rs | 10 +- src/librustc_typeck/outlives/utils.rs | 22 +- src/librustc_typeck/structured_errors.rs | 4 +- src/librustc_typeck/variance/constraints.rs | 30 +- src/librustc_typeck/variance/mod.rs | 8 +- src/librustc_typeck/variance/solve.rs | 2 +- src/librustc_typeck/variance/terms.rs | 12 +- src/librustdoc/Cargo.toml | 3 +- src/librustdoc/clean/auto_trait.rs | 10 +- src/librustdoc/clean/blanket_impl.rs | 11 +- src/librustdoc/clean/cfg.rs | 12 +- src/librustdoc/clean/cfg/tests.rs | 10 +- src/librustdoc/clean/inline.rs | 64 +- src/librustdoc/clean/mod.rs | 592 +- src/librustdoc/clean/simplify.rs | 119 +- src/librustdoc/config.rs | 86 +- src/librustdoc/core.rs | 125 +- src/librustdoc/doctree.rs | 84 +- src/librustdoc/externalfiles.rs | 48 +- src/librustdoc/fold.rs | 8 +- src/librustdoc/html/format.rs | 1190 +-- src/librustdoc/html/item_type.rs | 39 +- src/librustdoc/html/layout.rs | 39 +- src/librustdoc/html/markdown.rs | 321 +- src/librustdoc/html/markdown/tests.rs | 56 +- src/librustdoc/html/render.rs | 3064 +++---- src/librustdoc/html/render/cache.rs | 675 ++ src/librustdoc/html/sources.rs | 175 + src/librustdoc/html/static/main.js | 99 +- src/librustdoc/html/static/noscript.css | 8 + src/librustdoc/html/static/rustdoc.css | 19 +- src/librustdoc/html/static/storage.js | 19 +- src/librustdoc/html/static/themes/dark.css | 2 +- src/librustdoc/html/static/themes/light.css | 2 +- src/librustdoc/html/toc.rs | 37 +- src/librustdoc/lib.rs | 58 +- src/librustdoc/markdown.rs | 26 +- .../passes/calculate_doc_coverage.rs | 7 +- .../passes/check_code_block_syntax.rs | 39 +- src/librustdoc/passes/collapse_docs.rs | 4 +- .../passes/collect_intra_doc_links.rs | 33 +- src/librustdoc/passes/collect_trait_impls.rs | 5 +- src/librustdoc/passes/mod.rs | 96 +- src/librustdoc/passes/strip_hidden.rs | 2 +- src/librustdoc/test.rs | 294 +- src/librustdoc/visit_ast.rs | 126 +- src/librustdoc/visit_lib.rs | 24 +- src/libserialize/collection_impls.rs | 10 +- src/libserialize/json.rs | 21 +- src/libserialize/lib.rs | 2 + src/libserialize/tests/json.rs | 2 + src/libserialize/tests/opaque.rs | 2 + src/libstd/Cargo.toml | 36 +- src/libstd/backtrace.rs | 353 + src/libstd/collections/hash/map.rs | 80 +- src/libstd/collections/hash/set.rs | 12 +- src/libstd/collections/mod.rs | 2 +- src/libstd/env.rs | 14 +- src/libstd/error.rs | 49 +- src/libstd/f32.rs | 43 +- src/libstd/f64.rs | 66 +- src/libstd/ffi/c_str.rs | 46 +- src/libstd/ffi/os_str.rs | 10 +- src/libstd/fs.rs | 34 +- src/libstd/future.rs | 1 + src/libstd/io/buffered.rs | 46 +- src/libstd/io/mod.rs | 86 +- src/libstd/io/stdio.rs | 8 +- src/libstd/keyword_docs.rs | 9 +- src/libstd/lib.rs | 53 +- src/libstd/macros.rs | 22 +- src/libstd/net/addr.rs | 17 +- src/libstd/net/ip.rs | 237 +- src/libstd/net/tcp.rs | 3 +- src/libstd/net/udp.rs | 7 +- src/libstd/os/raw/mod.rs | 48 +- src/libstd/panicking.rs | 40 +- src/libstd/path.rs | 21 +- src/libstd/prelude/v1.rs | 19 - src/libstd/primitive_docs.rs | 18 +- src/libstd/process.rs | 8 +- src/libstd/rt.rs | 3 - src/libstd/sync/condvar.rs | 4 +- src/libstd/sync/mod.rs | 1 - src/libstd/sys/cloudabi/abi/cloudabi.rs | 1 + src/libstd/sys/cloudabi/mod.rs | 2 - src/libstd/sys/cloudabi/mutex.rs | 7 +- src/libstd/sys/cloudabi/rwlock.rs | 15 +- src/libstd/sys/cloudabi/shims/process.rs | 8 +- src/libstd/sys/cloudabi/thread.rs | 7 +- src/libstd/sys/sgx/abi/usercalls/alloc.rs | 12 +- src/libstd/sys/sgx/condvar.rs | 3 +- src/libstd/sys/sgx/mutex.rs | 4 +- src/libstd/sys/sgx/process.rs | 8 +- src/libstd/sys/sgx/rwlock.rs | 34 +- src/libstd/sys/sgx/waitqueue.rs | 11 +- src/libstd/sys/unix/process/mod.rs | 5 +- src/libstd/sys/unix/process/process_common.rs | 141 +- .../sys/unix/process/process_fuchsia.rs | 101 +- src/libstd/sys/unix/process/process_unix.rs | 90 +- src/libstd/sys/unix/process/zircon.rs | 35 +- src/libstd/sys/unix/time.rs | 1 + src/libstd/sys/vxworks/backtrace/mod.rs | 110 - .../sys/vxworks/backtrace/printing/dladdr.rs | 35 - .../sys/vxworks/backtrace/printing/mod.rs | 33 - .../vxworks/backtrace/tracing/backtrace_fn.rs | 39 - .../sys/vxworks/backtrace/tracing/gcc_s.rs | 99 - .../sys/vxworks/backtrace/tracing/mod.rs | 8 - src/libstd/sys/vxworks/fast_thread_local.rs | 25 - src/libstd/sys/vxworks/fs.rs | 2 +- src/libstd/sys/vxworks/os.rs | 23 +- src/libstd/sys/vxworks/process/mod.rs | 2 +- .../sys/vxworks/process/process_common.rs | 10 +- .../sys/vxworks/process/process_vxworks.rs | 13 +- src/libstd/sys/vxworks/process/rtp.rs | 298 - src/libstd/sys/vxworks/rand.rs | 21 +- src/libstd/sys/vxworks/rwlock.rs | 2 +- src/libstd/sys/vxworks/thread.rs | 4 +- src/libstd/sys/wasi/args.rs | 41 +- src/libstd/sys/wasi/ext/fs.rs | 10 +- src/libstd/sys/wasi/ext/io.rs | 8 +- src/libstd/sys/wasi/fd.rs | 280 +- src/libstd/sys/wasi/fs.rs | 186 +- src/libstd/sys/wasi/io.rs | 11 +- src/libstd/sys/wasi/mod.rs | 79 +- src/libstd/sys/wasi/os.rs | 33 +- src/libstd/sys/wasi/process.rs | 8 +- src/libstd/sys/wasi/stdio.rs | 11 +- src/libstd/sys/wasi/thread.rs | 54 +- src/libstd/sys/wasi/time.rs | 30 +- src/libstd/sys/wasm/args.rs | 4 +- src/libstd/sys/wasm/mod.rs | 222 +- src/libstd/sys/wasm/os.rs | 18 +- src/libstd/sys/wasm/process.rs | 8 +- src/libstd/sys/wasm/stdio.rs | 15 +- src/libstd/sys/wasm/time.rs | 5 +- src/libstd/sys/windows/c.rs | 2 +- src/libstd/sys/windows/fs.rs | 2 +- src/libstd/sys/windows/process.rs | 24 +- src/libstd/sys_common/backtrace.rs | 321 +- src/libstd/sys_common/mod.rs | 1 - src/libstd/sys_common/os_str_bytes.rs | 6 + src/libstd/sys_common/process.rs | 51 +- src/libstd/tests/env.rs | 2 +- src/libstd/thread/local.rs | 4 +- src/libstd/thread/mod.rs | 3 - src/libstd/time.rs | 105 +- src/libsyntax/Cargo.toml | 2 +- src/libsyntax/ast.rs | 242 +- src/libsyntax/attr/builtin.rs | 56 +- src/libsyntax/attr/mod.rs | 202 +- src/libsyntax/config.rs | 17 +- src/libsyntax/diagnostics/macros.rs | 55 +- src/libsyntax/diagnostics/metadata.rs | 93 - src/libsyntax/diagnostics/plugin.rs | 211 - src/libsyntax/early_buffered_lints.rs | 1 + src/libsyntax/entry.rs | 2 +- src/libsyntax/error_codes.rs | 80 +- src/libsyntax/ext/base.rs | 431 +- src/libsyntax/ext/build.rs | 408 +- src/libsyntax/ext/expand.rs | 552 +- src/libsyntax/ext/mbe.rs | 166 + src/libsyntax/ext/{tt => mbe}/macro_check.rs | 4 +- src/libsyntax/ext/{tt => mbe}/macro_parser.rs | 38 +- src/libsyntax/ext/{tt => mbe}/macro_rules.rs | 344 +- src/libsyntax/ext/{tt => mbe}/quoted.rs | 201 +- src/libsyntax/ext/{tt => mbe}/transcribe.rs | 88 +- src/libsyntax/ext/placeholders.rs | 193 +- src/libsyntax/ext/proc_macro.rs | 16 +- src/libsyntax/ext/proc_macro_server.rs | 28 +- src/libsyntax/feature_gate.rs | 2525 ------ src/libsyntax/feature_gate/accepted.rs | 254 + src/libsyntax/feature_gate/active.rs | 547 ++ src/libsyntax/feature_gate/builtin_attrs.rs | 595 ++ src/libsyntax/feature_gate/check.rs | 879 ++ src/libsyntax/feature_gate/mod.rs | 65 + src/libsyntax/feature_gate/removed.rs | 110 + src/libsyntax/json.rs | 33 +- src/libsyntax/lib.rs | 24 +- src/libsyntax/mut_visit.rs | 232 +- src/libsyntax/mut_visit/tests.rs | 10 +- src/libsyntax/parse/attr.rs | 88 +- src/libsyntax/parse/classify.rs | 2 +- src/libsyntax/parse/diagnostics.rs | 360 +- src/libsyntax/parse/lexer/mod.rs | 112 +- src/libsyntax/parse/lexer/tests.rs | 158 +- src/libsyntax/parse/lexer/tokentrees.rs | 40 +- src/libsyntax/parse/lexer/unicode_chars.rs | 7 +- src/libsyntax/parse/literal.rs | 12 +- src/libsyntax/parse/mod.rs | 93 +- src/libsyntax/parse/parser.rs | 7206 ++--------------- src/libsyntax/parse/parser/expr.rs | 1786 ++++ src/libsyntax/parse/parser/generics.rs | 302 + src/libsyntax/parse/parser/item.rs | 1912 +++++ src/libsyntax/parse/parser/module.rs | 332 + src/libsyntax/parse/parser/pat.rs | 953 +++ src/libsyntax/parse/parser/path.rs | 474 ++ src/libsyntax/parse/parser/stmt.rs | 475 ++ src/libsyntax/parse/parser/ty.rs | 450 + src/libsyntax/parse/tests.rs | 24 +- src/libsyntax/parse/token.rs | 47 +- .../parse/unescape_error_reporting.rs | 8 +- src/libsyntax/print/pprust.rs | 327 +- src/libsyntax/print/pprust/tests.rs | 12 +- src/libsyntax/ptr.rs | 7 +- src/libsyntax/source_map.rs | 178 +- src/libsyntax/source_map/tests.rs | 98 +- src/libsyntax/tests.rs | 50 +- src/libsyntax/tokenstream.rs | 174 +- src/libsyntax/tokenstream/tests.rs | 4 +- src/libsyntax/util/node_count.rs | 7 +- src/libsyntax/util/parser.rs | 6 +- src/libsyntax/visit.rs | 133 +- src/libsyntax_ext/asm.rs | 33 +- src/libsyntax_ext/assert.rs | 21 +- src/libsyntax_ext/cfg.rs | 10 +- src/libsyntax_ext/cmdline_attrs.rs | 30 + src/libsyntax_ext/compile_error.rs | 4 +- src/libsyntax_ext/concat.rs | 20 +- src/libsyntax_ext/concat_idents.rs | 22 +- src/libsyntax_ext/deriving/clone.rs | 16 +- src/libsyntax_ext/deriving/cmp/eq.rs | 14 +- src/libsyntax_ext/deriving/cmp/ord.rs | 57 +- src/libsyntax_ext/deriving/cmp/partial_eq.rs | 2 +- src/libsyntax_ext/deriving/cmp/partial_ord.rs | 19 +- src/libsyntax_ext/deriving/debug.rs | 20 +- src/libsyntax_ext/deriving/decodable.rs | 30 +- src/libsyntax_ext/deriving/encodable.rs | 41 +- src/libsyntax_ext/deriving/generic/mod.rs | 92 +- src/libsyntax_ext/deriving/generic/ty.rs | 40 +- src/libsyntax_ext/deriving/hash.rs | 2 +- src/libsyntax_ext/deriving/mod.rs | 32 +- src/libsyntax_ext/env.rs | 28 +- src/libsyntax_ext/error_codes.rs | 9 +- src/libsyntax_ext/format.rs | 96 +- src/libsyntax_ext/global_allocator.rs | 29 +- src/libsyntax_ext/global_asm.rs | 15 +- src/libsyntax_ext/lib.rs | 20 +- src/libsyntax_ext/log_syntax.rs | 6 +- src/libsyntax_ext/plugin_macro_defs.rs | 10 +- src/libsyntax_ext/proc_macro_harness.rs | 186 +- src/libsyntax_ext/source_util.rs | 75 +- src/libsyntax_ext/standard_library_imports.rs | 110 +- src/libsyntax_ext/test.rs | 83 +- src/libsyntax_ext/test_harness.rs | 289 +- src/libsyntax_ext/trace_macros.rs | 27 +- src/libsyntax_pos/Cargo.toml | 1 + src/libsyntax_pos/edition.rs | 5 - src/libsyntax_pos/hygiene.rs | 291 +- src/libsyntax_pos/lib.rs | 238 +- src/libsyntax_pos/symbol.rs | 199 +- src/libsyntax_pos/tests.rs | 20 + src/libterm/Cargo.toml | 6 +- src/libtest/Cargo.toml | 16 +- src/libtest/formatters/json.rs | 100 +- src/libtest/formatters/mod.rs | 11 + src/libtest/formatters/pretty.rs | 123 +- src/libtest/formatters/terse.rs | 11 +- src/libtest/lib.rs | 825 +- src/libtest/stats.rs | 2 +- src/libtest/tests.rs | 194 +- src/libunwind/Cargo.toml | 4 +- src/libunwind/build.rs | 26 +- src/libunwind/libunwind.rs | 10 +- src/llvm-project | 2 +- src/stage0.txt | 4 +- src/stdarch | 2 +- .../auxiliary/shared_generics_aux.rs | 1 + .../partitioning/shared-generics.rs | 1 + src/test/codegen/README.md | 2 + src/test/codegen/adjustments.rs | 2 +- src/test/codegen/c-variadic.rs | 29 +- src/test/codegen/fastcall-inreg.rs | 12 +- src/test/codegen/function-arguments.rs | 28 +- src/test/codegen/integer-cmp.rs | 28 + src/test/codegen/issue-45222.rs | 3 - .../codegen/iter-fold-closure-no-dupes.rs | 14 + .../codegen/iter-fold-closure-no-iterator.rs | 10 + .../codegen/non-terminate/infinite-loop-1.rs | 17 + .../codegen/non-terminate/infinite-loop-2.rs | 19 + .../non-terminate/infinite-recursion.rs | 14 + src/test/codegen/personality_lifetimes.rs | 9 +- src/test/codegen/refs.rs | 2 +- src/test/codegen/repeat-trusted-len.rs | 2 +- src/test/codegen/repr-transparent.rs | 34 +- src/test/codegen/scalar-pair-bool.rs | 12 +- src/test/codegen/union-abi.rs | 16 +- src/test/codegen/var-names.rs | 15 + .../issues => compile-fail}/issue-44415.rs | 0 src/test/compile-fail/two-panic-runtimes.rs | 1 + src/test/debuginfo/boxed-struct.rs | 16 +- .../debuginfo/function-arg-initialization.rs | 4 +- src/test/debuginfo/generator-objects.rs | 16 +- src/test/debuginfo/issue-22656.rs | 2 +- src/test/debuginfo/issue-57822.rs | 55 + .../incremental/hashes/call_expressions.rs | 18 +- .../incremental/hashes/closure_expressions.rs | 12 +- src/test/incremental/hashes/consts.rs | 12 +- src/test/incremental/hashes/for_loops.rs | 2 +- .../incremental/hashes/function_interfaces.rs | 14 +- src/test/incremental/hashes/if_expressions.rs | 16 +- .../hashes/indexing_expressions.rs | 14 +- src/test/incremental/hashes/inherent_impls.rs | 14 +- src/test/incremental/hashes/inline_asm.rs | 12 +- .../incremental/hashes/loop_expressions.rs | 16 +- src/test/incremental/hashes/panic_exprs.rs | 18 +- src/test/incremental/hashes/statics.rs | 20 +- .../incremental/hashes/struct_constructors.rs | 18 +- src/test/incremental/hashes/trait_defs.rs | 124 +- .../incremental/hashes/while_let_loops.rs | 18 +- src/test/incremental/hashes/while_loops.rs | 18 +- src/test/mir-opt/box_expr.rs | 15 +- .../const_prop/read_immutable_static.rs | 29 + src/test/mir-opt/const_prop/reify_fn_ptr.rs | 2 +- src/test/mir-opt/const_prop/slice_len.rs | 2 +- .../mir-opt/generator-storage-dead-unwind.rs | 26 +- src/test/mir-opt/match-arm-scopes.rs | 2 - .../mir-opt/no-spurious-drop-after-call.rs | 24 + src/test/mir-opt/retag.rs | 38 +- src/test/pretty/attr-literals.rs | 4 +- src/test/pretty/block-comment-wchar.pp | 5 +- src/test/pretty/delimited-token-groups.rs | 2 +- src/test/pretty/do1.rs | 2 +- src/test/pretty/dollar-crate.pp | 8 +- src/test/pretty/issue-4264.pp | 2 +- src/test/pretty/macro.rs | 2 +- src/test/pretty/match-block-expr.rs | 2 +- src/test/pretty/stmt_expr_attributes.rs | 2 - src/test/run-fail/overflowing-lsh-1.rs | 1 + src/test/run-fail/overflowing-lsh-2.rs | 1 + src/test/run-fail/overflowing-lsh-3.rs | 1 + src/test/run-fail/overflowing-lsh-4.rs | 1 + src/test/run-fail/overflowing-rsh-1.rs | 1 + src/test/run-fail/overflowing-rsh-2.rs | 1 + src/test/run-fail/overflowing-rsh-3.rs | 1 + src/test/run-fail/overflowing-rsh-4.rs | 1 + .../hotplug_codegen_backend/the_backend.rs | 9 +- src/test/run-make-fulldeps/issue-19371/foo.rs | 3 +- .../run-make-fulldeps/issue-64319/Makefile | 39 + src/test/run-make-fulldeps/issue-64319/bar.rs | 5 + src/test/run-make-fulldeps/issue-64319/foo.rs | 9 + .../run-make-fulldeps/libtest-json/Makefile | 12 +- src/test/run-make-fulldeps/libtest-json/f.rs | 3 +- .../{output.json => output-default.json} | 2 +- .../libtest-json/output-stdout-success.json | 10 + .../linker-output-non-utf8/Makefile | 23 - .../linker-output-non-utf8/exec.rs | 6 - .../linker-output-non-utf8/library.rs | 10 - src/test/run-make-fulldeps/lto-empty/Makefile | 12 + src/test/run-make-fulldeps/lto-empty/lib.rs | 1 + .../reproducible-build-2/Makefile | 26 + .../reproducible-build-2/linker.rs | 44 + .../reproducible-build-aux.rs | 28 + .../reproducible-build.rs | 116 + .../symbol-visibility/Makefile | 4 +- src/test/run-make-fulldeps/tools.mk | 2 +- .../run-pass-valgrind/cast-enum-with-dtor.rs | 2 - .../cleanup-auto-borrow-obj.rs | 2 - src/test/run-pass-valgrind/cleanup-stdin.rs | 2 - .../down-with-thread-dtors.rs | 1 - src/test/run-pass-valgrind/dst-dtor-1.rs | 2 - src/test/run-pass-valgrind/dst-dtor-2.rs | 2 - src/test/run-pass-valgrind/dst-dtor-3.rs | 2 - src/test/run-pass-valgrind/dst-dtor-4.rs | 2 - src/test/run-pass-valgrind/exit-flushes.rs | 1 - src/test/run-pass-valgrind/osx-frameworks.rs | 1 - src/test/rustdoc-js-std/vec-new.js | 1 + src/test/rustdoc-js/exact-match.js | 9 + src/test/rustdoc-js/exact-match.rs | 68 + src/test/rustdoc-js/module-substring.js | 9 + src/test/rustdoc-js/module-substring.rs | 68 + src/test/rustdoc-js/search-short-types.js | 2 + src/test/rustdoc-js/search-short-types.rs | 6 + .../rustdoc-ui/doc-test-doctest-feature.rs | 15 + .../doc-test-doctest-feature.stdout | 6 + .../rustdoc-ui/doc-test-rustdoc-feature.rs | 14 + .../doc-test-rustdoc-feature.stdout | 6 + src/test/rustdoc-ui/failed-doctest-output.rs | 1 + .../rustdoc-ui/failed-doctest-output.stdout | 14 +- src/test/rustdoc-ui/invalid-syntax.rs | 18 + src/test/rustdoc-ui/invalid-syntax.stderr | 40 + src/test/rustdoc/assoc-consts.rs | 2 +- src/test/rustdoc/async-fn.rs | 2 - src/test/rustdoc/async-move-doctest.rs | 6 +- src/test/rustdoc/auxiliary/issue-57180.rs | 16 + .../auxiliary/through-proc-macro-aux.rs | 20 + src/test/rustdoc/edition-flag.rs | 3 - src/test/rustdoc/inline_cross/assoc-items.rs | 6 +- .../inline_cross/auxiliary/impl_trait_aux.rs | 28 + .../inline_cross/auxiliary/proc_macro.rs | 7 + .../inline_cross/impl-inline-without-trait.rs | 2 +- src/test/rustdoc/inline_cross/impl_trait.rs | 40 + src/test/rustdoc/inline_cross/proc_macro.rs | 32 +- src/test/rustdoc/issue-57180.rs | 7 + src/test/rustdoc/manual_impl.rs | 8 +- src/test/rustdoc/proc-macro.rs | 3 +- src/test/rustdoc/rustc-macro-crate.rs | 1 + src/test/rustdoc/through-proc-macro.rs | 12 + src/test/rustdoc/variadic.rs | 2 +- src/test/ui-fulldeps/ast_stmt_expr_attr.rs | 2 +- .../ui-fulldeps/auxiliary/attr-plugin-test.rs | 3 +- .../auxiliary/issue-40001-plugin.rs | 3 +- .../auxiliary/lint-for-crate-rpass.rs | 3 +- .../ui-fulldeps/auxiliary/lint-for-crate.rs | 3 +- .../auxiliary/lint-group-plugin-test.rs | 3 +- .../ui-fulldeps/auxiliary/lint-plugin-test.rs | 3 +- .../ui-fulldeps/auxiliary/lint-tool-test.rs | 3 +- .../ui-fulldeps/auxiliary/llvm-pass-plugin.rs | 3 +- .../auxiliary/lto-syntax-extension-plugin.rs | 3 +- .../ui-fulldeps/auxiliary/macro-crate-test.rs | 1 - .../auxiliary/outlive-expansion-phase.rs | 3 +- src/test/ui-fulldeps/auxiliary/plugin-args.rs | 3 +- .../ui-fulldeps/auxiliary/rlib-crate-test.rs | 3 +- .../ui-fulldeps/auxiliary/roman-numerals.rs | 9 +- src/test/ui-fulldeps/compiler-calls.rs | 2 +- .../deriving-encodable-decodable-box.rs | 7 +- ...riving-encodable-decodable-cell-refcell.rs | 7 +- src/test/ui-fulldeps/deriving-global.rs | 3 +- src/test/ui-fulldeps/deriving-hygiene.rs | 3 +- src/test/ui-fulldeps/gated-plugin.rs | 3 +- src/test/ui-fulldeps/gated-plugin.stderr | 10 +- .../ui-fulldeps/hash-stable-is-unstable.rs | 2 + .../hash-stable-is-unstable.stderr | 9 +- .../internal-lints/ty_tykind_usage.rs | 8 +- .../internal-lints/ty_tykind_usage.stderr | 8 +- src/test/ui-fulldeps/issue-11881.rs | 9 +- src/test/ui-fulldeps/issue-15778-fail.rs | 1 + src/test/ui-fulldeps/issue-15778-fail.stderr | 9 + src/test/ui-fulldeps/issue-15778-pass.stderr | 8 + src/test/ui-fulldeps/issue-40001.stderr | 8 + .../lint-group-plugin-deny-cmdline.rs | 2 + .../lint-group-plugin-deny-cmdline.stderr | 12 +- src/test/ui-fulldeps/lint-group-plugin.stderr | 8 + .../lint-plugin-cmdline-allow.stderr | 8 + src/test/ui-fulldeps/lint-plugin-deny-attr.rs | 1 + .../ui-fulldeps/lint-plugin-deny-attr.stderr | 12 +- .../ui-fulldeps/lint-plugin-deny-cmdline.rs | 1 + .../lint-plugin-deny-cmdline.stderr | 10 +- .../ui-fulldeps/lint-plugin-forbid-attrs.rs | 1 + .../lint-plugin-forbid-attrs.stderr | 14 +- .../ui-fulldeps/lint-plugin-forbid-cmdline.rs | 2 +- .../lint-plugin-forbid-cmdline.stderr | 8 + src/test/ui-fulldeps/lint-plugin.stderr | 8 + .../lint-tool-cmdline-allow.stderr | 8 + src/test/ui-fulldeps/lint-tool-test.rs | 1 + src/test/ui-fulldeps/lint-tool-test.stderr | 26 +- src/test/ui-fulldeps/llvm-pass-plugin.stderr | 8 + .../ui-fulldeps/lto-syntax-extension.stderr | 8 + src/test/ui-fulldeps/macro-crate-rlib.rs | 1 + src/test/ui-fulldeps/macro-crate-rlib.stderr | 8 + src/test/ui-fulldeps/newtype_index.rs | 4 +- .../outlive-expansion-phase.stderr | 8 + src/test/ui-fulldeps/plugin-args-1.stderr | 8 + src/test/ui-fulldeps/plugin-args-2.stderr | 8 + src/test/ui-fulldeps/plugin-args-3.stderr | 8 + .../ui-fulldeps/plugin-attr-register-deny.rs | 1 + .../plugin-attr-register-deny.stderr | 16 +- src/test/ui-fulldeps/plugin-reexport.rs | 1 + src/test/ui-fulldeps/plugin-reexport.stderr | 12 +- src/test/ui-fulldeps/pprust-expr-roundtrip.rs | 62 +- .../ui-fulldeps/roman-numerals-macro.stderr | 8 + src/test/ui/.gitattributes | 1 + .../ui/{ => abi}/abi-sysv64-arg-passing.rs | 0 .../ui/{ => abi}/abi-sysv64-register-usage.rs | 0 src/test/ui/{ => abi}/abort-on-c-abi.rs | 2 + src/test/ui/{ => abi}/anon-extern-mod.rs | 0 .../anon-extern-mod-cross-crate-1.rs | 0 .../ui/{ => abi}/auxiliary/foreign_lib.rs | 0 src/test/ui/{ => abi}/c-stack-as-value.rs | 0 src/test/ui/{ => abi}/cabi-int-widening.rs | 0 .../anon-extern-mod-cross-crate-1.rs | 0 .../anon-extern-mod-cross-crate-2.rs | 0 .../anon-extern-mod-cross-crate-1.rs | 0 .../ui/{ => abi}/duplicated-external-mods.rs | 0 .../auxiliary/extern-crosscrate-source.rs | 0 .../ui/{ => abi}/extern/extern-call-deep.rs | 0 .../ui/{ => abi}/extern/extern-call-deep2.rs | 0 .../ui/{ => abi}/extern/extern-call-direct.rs | 0 .../{ => abi}/extern/extern-call-indirect.rs | 0 .../ui/{ => abi}/extern/extern-call-scrub.rs | 0 .../ui/{ => abi}/extern/extern-crosscrate.rs | 0 .../{ => abi}/extern/extern-pass-TwoU16s.rs | 0 .../{ => abi}/extern/extern-pass-TwoU32s.rs | 0 .../{ => abi}/extern/extern-pass-TwoU64s.rs | 0 .../ui/{ => abi}/extern/extern-pass-TwoU8s.rs | 0 .../ui/{ => abi}/extern/extern-pass-char.rs | 0 .../ui/{ => abi}/extern/extern-pass-double.rs | 0 .../ui/{ => abi}/extern/extern-pass-empty.rs | 0 .../ui/{ => abi}/extern/extern-pass-u32.rs | 0 .../ui/{ => abi}/extern/extern-pass-u64.rs | 0 .../{ => abi}/extern/extern-return-TwoU16s.rs | 0 .../{ => abi}/extern/extern-return-TwoU32s.rs | 0 .../{ => abi}/extern/extern-return-TwoU64s.rs | 0 .../{ => abi}/extern/extern-return-TwoU8s.rs | 0 .../foreign/auxiliary/foreign_lib.rs | 0 .../foreign/foreign-call-no-runtime.rs | 0 src/test/ui/{ => abi}/foreign/foreign-dupe.rs | 0 .../foreign/foreign-fn-with-byval.rs | 0 .../ui/{ => abi}/foreign/foreign-no-abi.rs | 0 .../ui/{ => abi}/invoke-external-foreign.rs | 0 src/test/ui/{ => abi}/lib-defaults.rs | 0 .../mir/mir_codegen_calls_variadic.rs | 0 .../{ => abi}/numbers-arithmetic/i128-ffi.rs | 0 .../ui/{ => abi}/segfault-no-out-of-stack.rs | 0 src/test/ui/{ => abi}/stack-probes-lto.rs | 0 src/test/ui/{ => abi}/stack-probes.rs | 0 .../{ => abi}/statics/static-mut-foreign.rs | 0 .../struct-enums}/struct-return.rs | 0 .../ui/{ => abi}/union/union-c-interop.rs | 0 src/test/ui/{ => abi}/variadic-ffi.rs | 0 src/test/ui/allocator/hygiene.rs | 31 + src/test/ui/anon-params-denied-2018.rs | 2 +- src/test/ui/anon-params-denied-2018.stderr | 24 +- .../ui/anonymous-higher-ranked-lifetime.rs | 11 - .../anonymous-higher-ranked-lifetime.stderr | 251 +- src/test/ui/array-break-length.rs | 4 +- src/test/ui/array-break-length.stderr | 8 +- src/test/ui/asm/asm-out-read-uninit.rs | 2 +- src/test/ui/asm/asm-out-read-uninit.stderr | 4 +- .../associated-const-array-len.stderr | 9 +- ...ssociated-const-generic-obligations.stderr | 2 + .../associated-const-in-trait.stderr | 5 +- ...iated-const-type-parameter-arrays-2.stderr | 8 +- ...ociated-const-type-parameter-arrays.stderr | 8 +- .../assoc-type-eq-with-dyn-atb-fail.rs | 32 + .../assoc-type-eq-with-dyn-atb-fail.stderr | 11 + .../bad-bounds-on-assoc-in-trait.stderr | 24 +- .../bounds-on-assoc-in-trait.rs | 2 +- .../ui/associated-type-bounds/duplicate.rs | 165 +- .../associated-type-bounds/duplicate.stderr | 224 +- src/test/ui/associated-type-bounds/fn-apit.rs | 1 + .../ui/associated-type-bounds/fn-dyn-apit.rs | 1 + .../ui/associated-type-bounds/fn-inline.rs | 1 + .../ui/associated-type-bounds/fn-where.rs | 1 + .../ui/associated-type-bounds/fn-wrap-apit.rs | 1 + .../ui/associated-type-bounds/inside-adt.rs | 41 +- .../associated-type-bounds/inside-adt.stderr | 61 +- .../associated-type-bounds/struct-bounds.rs | 1 + ...ociated-type-projection-from-supertrait.rs | 8 - ...ted-type-projection-from-supertrait.stderr | 8 +- ...s-binding-to-type-defined-in-supertrait.rs | 6 - ...nding-to-type-defined-in-supertrait.stderr | 20 +- .../associated-types-bound-failure.stderr | 12 +- .../associated-types-eq-3.stderr | 10 +- .../associated-types-eq-hr.stderr | 112 +- .../associated-types-issue-20346.stderr | 10 +- ...ated-types-multiple-types-one-trait.stderr | 20 +- .../associated-types-overridden-binding.rs | 4 +- ...associated-types-overridden-binding.stderr | 19 +- .../associated-types-path-2.stderr | 18 +- .../associated-types-ref-from-struct.rs | 4 - .../associated-types-unconstrained.rs | 2 +- .../associated-types-unconstrained.stderr | 2 +- .../ui/associated-types/cache/chrono-scan.rs | 2 + ...ject-fn-ret-contravariant.transmute.stderr | 1 + .../project-fn-ret-invariant.transmute.stderr | 1 + .../higher-ranked-projection.bad.stderr | 13 +- src/test/ui/associated-types/issue-64855-2.rs | 5 + src/test/ui/associated-types/issue-64855.rs | 8 + .../ui/associated-types/issue-64855.stderr | 9 + src/test/ui/ast-json/ast-json-ice.rs | 41 + src/test/ui/ast-json/ast-json-output.rs | 9 + src/test/ui/ast-json/ast-json-output.stdout | 1 + src/test/ui/async-await/argument-patterns.rs | 4 +- .../async-assoc-fn-anon-lifetimes.rs | 23 + src/test/ui/async-await/async-await.rs | 4 +- ...ync-block-control-flow-static-semantics.rs | 9 +- ...block-control-flow-static-semantics.stderr | 66 +- .../async-borrowck-escaping-block-error.fixed | 12 + .../async-borrowck-escaping-block-error.rs | 12 + ...async-borrowck-escaping-block-error.stderr | 22 + .../async-borrowck-escaping-closure-error.rs | 10 + ...ync-borrowck-escaping-closure-error.stderr | 21 + .../async-await/async-closure-matches-expr.rs | 2 +- src/test/ui/async-await/async-closure.rs | 2 +- src/test/ui/async-await/async-error-span.rs | 5 +- .../ui/async-await/async-error-span.stderr | 8 +- ...async-fn-elided-impl-lifetime-parameter.rs | 15 + src/test/ui/async-await/async-fn-nonsend.rs | 2 - .../ui/async-await/async-fn-nonsend.stderr | 64 +- .../ui/async-await/async-fn-path-elision.rs | 3 - .../async-await/async-fn-path-elision.stderr | 2 +- .../async-await/async-fn-send-uses-nonsend.rs | 2 - .../async-await/async-fn-size-moved-locals.rs | 5 +- .../async-fn-size-uninit-locals.rs | 103 + src/test/ui/async-await/async-fn-size.rs | 10 +- src/test/ui/async-await/async-matches-expr.rs | 2 - .../async-unsafe-fn-call-in-safe.rs | 2 - .../async-unsafe-fn-call-in-safe.stderr | 8 +- src/test/ui/async-await/async-with-closure.rs | 2 - .../2015-edition-error-various-positions.rs | 1 - ...015-edition-error-various-positions.stderr | 22 +- ...018-edition-error-in-non-macro-position.rs | 15 +- ...edition-error-in-non-macro-position.stderr | 42 +- .../await-keyword/2018-edition-error.rs | 4 +- .../await-keyword/2018-edition-error.stderr | 20 +- .../incorrect-syntax-suggestions.rs | 2 - .../incorrect-syntax-suggestions.stderr | 70 +- src/test/ui/async-await/await-unsize.rs | 2 - .../ui/async-await/bound-normalization.rs | 2 - ...nditional-and-guaranteed-initialization.rs | 2 - .../async-await/dont-print-desugared-async.rs | 1 - .../dont-print-desugared-async.stderr | 2 +- .../async-await/dont-suggest-missing-await.rs | 2 - .../dont-suggest-missing-await.stderr | 2 +- ...-for-async-fn-parameters-by-ref-binding.rs | 1 - .../drop-order-for-async-fn-parameters.rs | 1 - .../drop-order-for-locals-when-cancelled.rs | 8 +- ...order-for-temporary-in-tail-return-expr.rs | 95 + .../drop-order-locals-are-hidden.rs | 3 - .../drop-order-locals-are-hidden.stderr | 8 +- .../drop-order/drop-order-when-cancelled.rs | 7 +- .../edition-deny-async-fns-2015.rs | 2 - .../edition-deny-async-fns-2015.stderr | 28 +- .../ui/async-await/generics-and-bounds.rs | 2 - src/test/ui/async-await/issue-60709.rs | 3 - src/test/ui/async-await/issue-61452.rs | 1 - src/test/ui/async-await/issue-61452.stderr | 4 +- src/test/ui/async-await/issue-61793.rs | 3 - .../issue-61949-self-return-type.rs | 27 + .../issue-61949-self-return-type.stderr | 8 + src/test/ui/async-await/issue-62658.rs | 2 - ...-63832-await-short-temporary-lifetime-1.rs | 19 + ...ue-63832-await-short-temporary-lifetime.rs | 12 + .../issue-64130-non-send-future-diags.rs | 25 + .../issue-64130-non-send-future-diags.stderr | 23 + src/test/ui/async-await/issue-64391.rs | 14 + src/test/ui/async-await/issues/issue-51719.rs | 2 - .../ui/async-await/issues/issue-51719.stderr | 2 +- src/test/ui/async-await/issues/issue-51751.rs | 2 - .../ui/async-await/issues/issue-51751.stderr | 2 +- src/test/ui/async-await/issues/issue-53249.rs | 2 +- .../issues/issue-54752-async-block.rs | 3 - .../issues/issue-54752-async-block.stderr | 8 + src/test/ui/async-await/issues/issue-54974.rs | 2 - src/test/ui/async-await/issues/issue-55324.rs | 3 - src/test/ui/async-await/issues/issue-55809.rs | 2 - src/test/ui/async-await/issues/issue-58885.rs | 2 - src/test/ui/async-await/issues/issue-59001.rs | 3 - src/test/ui/async-await/issues/issue-59972.rs | 8 +- src/test/ui/async-await/issues/issue-60518.rs | 2 - .../issues/issue-60655-latebound-regions.rs | 1 - src/test/ui/async-await/issues/issue-60674.rs | 1 - src/test/ui/async-await/issues/issue-61187.rs | 4 +- .../ui/async-await/issues/issue-61187.stderr | 2 +- src/test/ui/async-await/issues/issue-61986.rs | 2 - .../ui/async-await/issues/issue-62009-1.rs | 4 +- .../async-await/issues/issue-62009-1.stderr | 5 +- .../ui/async-await/issues/issue-62009-2.rs | 2 +- .../ui/async-await/issues/issue-62517-1.rs | 21 + .../ui/async-await/issues/issue-62517-2.rs | 16 + .../issues/issue-63388-1.nll.stderr | 24 + .../ui/async-await/issues/issue-63388-1.rs | 18 + .../async-await/issues/issue-63388-1.stderr | 13 + .../issues/issue-63388-2.nll.stderr | 11 + .../ui/async-await/issues/issue-63388-2.rs | 18 + .../async-await/issues/issue-63388-2.stderr | 30 + .../ui/async-await/issues/issue-63388-3.rs | 17 + .../ui/async-await/issues/issue-63388-4.rs | 10 + .../ui/async-await/issues/issue-64391-2.rs | 20 + src/test/ui/async-await/issues/issue-64433.rs | 30 + src/test/ui/async-await/issues/issue-64477.rs | 20 + src/test/ui/async-await/issues/issue-64964.rs | 22 + .../issues/non-async-enclosing-span.rs | 11 + .../issues/non-async-enclosing-span.stderr | 11 + .../move-part-await-return-rest-struct.rs | 2 - .../move-part-await-return-rest-tuple.rs | 2 - .../async-await/multiple-lifetimes/elided.rs | 2 - .../async-await/multiple-lifetimes/fn-ptr.rs | 2 - .../ui/async-await/multiple-lifetimes/hrtb.rs | 5 +- .../async-await/multiple-lifetimes/named.rs | 2 - .../multiple-lifetimes/partial-relation.rs | 2 - .../multiple-lifetimes/ret-impl-trait-fg.rs | 2 +- .../ret-impl-trait-no-fg.rs | 2 - .../ret-impl-trait-no-fg.stderr | 2 +- .../multiple-lifetimes/ret-impl-trait-one.rs | 2 +- .../async-await/multiple-lifetimes/ret-ref.rs | 2 - .../multiple-lifetimes/ret-ref.stderr | 6 +- .../multiple-lifetimes/variance.rs | 3 - ...utually-recursive-async-impl-trait-type.rs | 13 + ...lly-recursive-async-impl-trait-type.stderr | 19 + src/test/ui/async-await/nested-in-impl.rs | 15 + .../no-args-non-move-async-closure.rs | 8 - src/test/ui/async-await/no-async-const.rs | 2 - src/test/ui/async-await/no-async-const.stderr | 2 +- src/test/ui/async-await/no-const-async.rs | 4 +- src/test/ui/async-await/no-const-async.stderr | 8 +- .../no-move-across-await-struct.rs | 2 - .../no-move-across-await-struct.stderr | 2 +- .../async-await/no-move-across-await-tuple.rs | 2 - .../no-move-across-await-tuple.stderr | 2 +- .../no-non-guaranteed-initialization.rs | 4 +- .../no-non-guaranteed-initialization.stderr | 6 +- .../no-params-non-move-async-closure.rs | 8 + ...> no-params-non-move-async-closure.stderr} | 4 +- .../partial-initialization-across-await.rs | 8 +- ...partial-initialization-across-await.stderr | 18 +- .../recursive-async-impl-trait-type.rs | 2 - .../recursive-async-impl-trait-type.stderr | 6 +- .../async-await/return-ty-raw-ptr-coercion.rs | 25 + .../async-await/return-ty-unsize-coercion.rs | 45 + .../suggest-missing-await-closure.fixed | 2 +- .../suggest-missing-await-closure.rs | 2 +- .../async-await/suggest-missing-await.fixed | 2 - .../ui/async-await/suggest-missing-await.rs | 2 - .../async-await/suggest-missing-await.stderr | 2 +- .../suggest-switching-edition-on-await.rs | 45 + .../suggest-switching-edition-on-await.stderr | 43 + src/test/ui/async-await/unreachable-lint-1.rs | 12 + .../ui/async-await/unreachable-lint-1.stderr | 16 + src/test/ui/async-await/unreachable-lint.rs | 13 + .../ui/async-await/unresolved_type_param.rs | 6 +- .../async-await/unresolved_type_param.stderr | 4 +- src/test/ui/attributes/item-attributes.rs | 2 - src/test/ui/attributes/multiple-invalid.rs | 10 + .../ui/attributes/multiple-invalid.stderr | 21 + src/test/ui/attributes/obsolete-attr.rs | 6 +- src/test/ui/attributes/obsolete-attr.stderr | 4 +- src/test/ui/attributes/unknown-attr.rs | 8 +- src/test/ui/attributes/unknown-attr.stderr | 6 +- .../ui/attributes/unnamed-field-attributes.rs | 9 + src/test/ui/attrs-resolution-errors.rs | 40 + src/test/ui/attrs-resolution-errors.stderr | 32 + src/test/ui/attrs-resolution.rs | 37 + src/test/ui/auto-ref-slice-plus-ref.stderr | 6 +- src/test/ui/auto-trait-validation.stderr | 3 +- src/test/ui/auxiliary/cond_plugin.rs | 1 + src/test/ui/auxiliary/proc_macro_def.rs | 1 + .../ui/bind-by-move/bind-by-move-no-guards.rs | 13 - .../bind-by-move-no-guards.stderr | 11 - src/test/ui/block-expr-precedence.stderr | 8 + .../consider-removing-last-semi.stderr | 4 +- src/test/ui/block-result/issue-11714.stderr | 2 +- src/test/ui/block-result/issue-13428.stderr | 4 +- .../ui/borrowck/assign_mutable_fields.stderr | 8 +- src/test/ui/borrowck/borrowck-and-init.rs | 2 +- src/test/ui/borrowck/borrowck-and-init.stderr | 4 +- .../borrowck-anon-fields-variant.nll.stderr | 40 - .../borrowck/borrowck-anon-fields-variant.rs | 4 +- .../borrowck-anon-fields-variant.stderr | 12 +- src/test/ui/borrowck/borrowck-asm.rs | 2 +- src/test/ui/borrowck/borrowck-asm.stderr | 4 +- src/test/ui/borrowck/borrowck-block-unint.rs | 2 +- .../ui/borrowck/borrowck-block-unint.stderr | 4 +- .../ui/borrowck/borrowck-break-uninit-2.rs | 2 +- .../borrowck/borrowck-break-uninit-2.stderr | 4 +- src/test/ui/borrowck/borrowck-break-uninit.rs | 2 +- .../ui/borrowck/borrowck-break-uninit.stderr | 4 +- .../borrowck/borrowck-closures-mut-of-imm.rs | 4 - .../borrowck-closures-mut-of-imm.stderr | 9 +- .../borrowck-closures-mut-of-mut.stderr | 1 + .../borrowck/borrowck-closures-unique.stderr | 3 +- .../borrowck-describe-lvalue.nll.stderr | 366 - .../ui/borrowck/borrowck-describe-lvalue.rs | 12 +- .../borrowck/borrowck-describe-lvalue.stderr | 30 +- ...k-escaping-closure-error-2.polonius.stderr | 16 - .../ui/borrowck/borrowck-field-sensitivity.rs | 6 +- .../borrowck-field-sensitivity.stderr | 12 +- src/test/ui/borrowck/borrowck-if-no-else.rs | 2 +- .../ui/borrowck/borrowck-if-no-else.stderr | 4 +- src/test/ui/borrowck/borrowck-if-with-else.rs | 2 +- .../ui/borrowck/borrowck-if-with-else.stderr | 4 +- .../borrowck-init-in-called-fn-expr.rs | 2 +- .../borrowck-init-in-called-fn-expr.stderr | 4 +- .../ui/borrowck/borrowck-init-in-fn-expr.rs | 2 +- .../borrowck/borrowck-init-in-fn-expr.stderr | 4 +- src/test/ui/borrowck/borrowck-init-in-fru.rs | 2 +- .../ui/borrowck/borrowck-init-in-fru.stderr | 4 +- .../ui/borrowck/borrowck-init-op-equal.rs | 2 +- .../ui/borrowck/borrowck-init-op-equal.stderr | 4 +- .../ui/borrowck/borrowck-init-plus-equal.rs | 2 +- .../borrowck/borrowck-init-plus-equal.stderr | 4 +- .../borrowck-migrate-to-nll.edition.stderr | 15 - .../ui/borrowck/borrowck-migrate-to-nll.rs | 34 - .../borrowck-migrate-to-nll.zflag.stderr | 15 - .../ui/borrowck/borrowck-mutate-in-guard.rs | 7 +- .../borrowck/borrowck-mutate-in-guard.stderr | 27 +- src/test/ui/borrowck/borrowck-or-init.rs | 2 +- src/test/ui/borrowck/borrowck-or-init.stderr | 4 +- .../ui/borrowck/borrowck-partial-reinit-4.rs | 2 +- .../borrowck/borrowck-partial-reinit-4.stderr | 4 +- src/test/ui/borrowck/borrowck-return.rs | 2 +- src/test/ui/borrowck/borrowck-return.stderr | 4 +- .../ui/borrowck/borrowck-storage-dead.stderr | 4 +- .../ui/borrowck/borrowck-uninit-after-item.rs | 2 +- .../borrowck-uninit-after-item.stderr | 4 +- .../borrowck-uninit-field-access.stderr | 4 +- .../borrowck/borrowck-uninit-in-assignop.rs | 20 +- .../borrowck-uninit-in-assignop.stderr | 40 +- .../ui/borrowck/borrowck-uninit-ref-chain.rs | 8 +- .../borrowck/borrowck-uninit-ref-chain.stderr | 28 +- src/test/ui/borrowck/borrowck-uninit.rs | 2 +- src/test/ui/borrowck/borrowck-uninit.stderr | 4 +- .../borrowck/borrowck-union-uninitialized.rs | 4 +- .../borrowck-union-uninitialized.stderr | 8 +- .../borrowck-use-in-index-lvalue.stderr | 8 +- ...wck-use-uninitialized-in-cast-trait.stderr | 4 +- .../borrowck-use-uninitialized-in-cast.stderr | 4 +- src/test/ui/borrowck/borrowck-while-break.rs | 2 +- .../ui/borrowck/borrowck-while-break.stderr | 4 +- src/test/ui/borrowck/borrowck-while-cond.rs | 2 +- .../ui/borrowck/borrowck-while-cond.stderr | 4 +- src/test/ui/borrowck/borrowck-while.rs | 2 +- src/test/ui/borrowck/borrowck-while.stderr | 4 +- .../disallow-possibly-uninitialized.rs | 8 +- .../disallow-possibly-uninitialized.stderr | 16 +- src/test/ui/borrowck/issue-10876.rs | 2 +- ...-nested-closure-outlives-borrowed-value.rs | 7 + ...ted-closure-outlives-borrowed-value.stderr | 15 + ...-54499-field-mutation-marks-mut-as-used.rs | 6 +- ...99-field-mutation-marks-mut-as-used.stderr | 12 +- ...ssue-54499-field-mutation-of-never-init.rs | 6 +- ...-54499-field-mutation-of-never-init.stderr | 12 +- .../borrowck/issue-62107-match-arm-scopes.rs | 2 +- .../issue-62107-match-arm-scopes.stderr | 4 +- src/test/ui/borrowck/issue-64453.rs | 24 + src/test/ui/borrowck/issue-64453.stderr | 34 + .../ui/borrowck/move-error-snippets-ext.rs | 7 + src/test/ui/borrowck/move-error-snippets.rs | 23 + .../ui/borrowck/move-error-snippets.stderr | 15 + ...ref-mut-in-let-issue-46557.polonius.stderr | 59 - .../reassignment_immutable_fields.stderr | 8 +- ...gnment_immutable_fields_overlapping.stderr | 4 +- ...reassignment_immutable_fields_twice.stderr | 4 +- src/test/ui/borrowck/two-phase-across-loop.rs | 2 +- .../two-phase-multiple-activations.rs | 4 +- ...phase-surprise-no-conflict.polonius.stderr | 148 - .../two-phase-surprise-no-conflict.rs | 2 +- src/test/ui/break-outside-loop.rs | 6 +- src/test/ui/break-outside-loop.stderr | 21 +- src/test/ui/c-variadic/variadic-ffi-1.stderr | 4 +- .../ui/c-variadic/variadic-ffi-4.nll.stderr | 58 +- src/test/ui/c-variadic/variadic-ffi-4.rs | 11 +- src/test/ui/c-variadic/variadic-ffi-4.stderr | 198 +- .../c-variadic/variadic-ffi-no-fixed-args.rs | 6 + .../variadic-ffi-no-fixed-args.stderr | 8 + src/test/ui/cfg/cfg_stmt_expr.rs | 4 +- src/test/ui/chalkify/type_inference.stderr | 8 +- .../ui/check-static-values-constraints.stderr | 2 +- src/test/ui/class-cast-to-trait.stderr | 2 +- .../expect-fn-supply-fn.nll.stderr | 42 +- .../expect-fn-supply-fn.stderr | 42 +- .../expect-infer-var-appearing-twice.stderr | 14 +- src/test/ui/closure-expected.stderr | 4 +- .../ui/closures/closure-array-break-length.rs | 6 +- .../closure-array-break-length.stderr | 12 +- ...ds-cant-promote-superkind-in-struct.stderr | 8 +- .../ui/closures/closure-bounds-subtype.stderr | 12 +- src/test/ui/closures/closure-move-sync.rs | 2 + src/test/ui/closures/closure-move-sync.stderr | 20 +- src/test/ui/codemap_tests/bad-format-args.rs | 2 +- .../ui/codemap_tests/bad-format-args.stderr | 4 +- .../overlapping_inherent_impls.stderr | 2 +- ...coercion-missing-tail-expected-type.stderr | 4 +- src/test/ui/coercion/coercion-slice.rs | 2 +- src/test/ui/coercion/coercion-slice.stderr | 2 +- .../ui/coherence/auxiliary/coherence_lib.rs | 4 +- ...mpl-trait-for-trait-object-safe.old.stderr | 4 +- ...impl-trait-for-trait-object-safe.re.stderr | 4 +- ...rence-overlap-upstream-inherent.old.stderr | 2 +- ...erence-overlap-upstream-inherent.re.stderr | 2 +- .../coherence-overlap-upstream.old.stderr | 2 +- .../coherence-overlap-upstream.re.stderr | 2 +- ...ence-projection-conflict-orphan.old.stderr | 2 +- ...rence-projection-conflict-orphan.re.stderr | 2 +- ...ke_err_fundamental_struct_tuple.old.stderr | 2 +- ...ike_err_fundamental_struct_tuple.re.stderr | 2 +- .../coherence_copy_like_err_struct.old.stderr | 2 +- .../coherence_copy_like_err_struct.re.stderr | 2 +- .../coherence_copy_like_err_tuple.old.stderr | 2 +- .../coherence_copy_like_err_tuple.re.stderr | 2 +- .../coherence/coherence_inherent.old.stderr | 4 +- .../ui/coherence/coherence_inherent.re.stderr | 4 +- .../coherence_inherent_cc.old.stderr | 4 +- .../coherence/coherence_inherent_cc.re.stderr | 4 +- .../ui/coherence/conflicting-impl-with-err.rs | 16 + .../conflicting-impl-with-err.stderr | 15 + .../impl-foreign[foreign]-for-foreign.rs | 17 + .../impl-foreign[foreign]-for-foreign.stderr | 12 + .../impl-foreign[foreign]-for-local.rs | 16 + ...]-foreign[foreign[t]_local]-for-foreign.rs | 14 + ...[t]-foreign[foreign]-for-fundamental[t].rs | 20 + ...foreign[foreign]-for-fundamental[t].stderr | 19 + .../impl[t]-foreign[foreign]-for-t.rs | 16 + .../impl[t]-foreign[foreign]-for-t.stderr | 11 + ...[t]-foreign[fundamental[t]]-for-foreign.rs | 20 + ...foreign[fundamental[t]]-for-foreign.stderr | 19 + ...eign[fundamental[t]]-for-fundamental[t].rs | 19 + ...[fundamental[t]]-for-fundamental[t].stderr | 19 + ...pl[t]-foreign[fundamental[t]]-for-local.rs | 17 + .../impl[t]-foreign[fundamental[t]]-for-t.rs | 19 + ...pl[t]-foreign[fundamental[t]]-for-t.stderr | 19 + ...reign[fundamental[t]_local]-for-foreign.rs | 20 + ...n[fundamental[t]_local]-for-foreign.stderr | 19 + .../impl[t]-foreign[local]-for-foreign.rs | 16 + ...pl[t]-foreign[local]-for-fundamental[t].rs | 20 + ...]-foreign[local]-for-fundamental[t].stderr | 19 + .../impl[t]-foreign[local]-for-local.rs | 15 + .../coherence/impl[t]-foreign[local]-for-t.rs | 16 + .../impl[t]-foreign[local]-for-t.stderr | 11 + ...reign[local_fundamental[t]]-for-foreign.rs | 19 + .../impl[t]-foreign[t]-for-foreign.rs | 16 + .../impl[t]-foreign[t]-for-foreign.stderr | 11 + .../impl[t]-foreign[t]-for-fundamental.rs | 20 + .../impl[t]-foreign[t]-for-fundamental.stderr | 19 + .../coherence/impl[t]-foreign[t]-for-local.rs | 15 + .../ui/coherence/impl[t]-foreign[t]-for-t.rs | 16 + .../coherence/impl[t]-foreign[t]-for-t.stderr | 11 + .../coherence/re-rebalance-coherence-rpass.rs | 14 - src/test/ui/collections-const-new.rs | 8 +- src/test/ui/commandline-argfile-badutf8.args | 2 + src/test/ui/commandline-argfile-badutf8.rs | 13 + .../ui/commandline-argfile-badutf8.stderr | 2 + src/test/ui/commandline-argfile-missing.rs | 16 + .../ui/commandline-argfile-missing.stderr | 2 + src/test/ui/commandline-argfile.args | 2 + src/test/ui/commandline-argfile.rs | 13 + .../reordered-type-param.stderr | 2 + .../cfg-arg-invalid-6.rs | 3 + .../cfg-arg-invalid-6.stderr | 2 + .../cfg-attr-cfg-2.stderr | 5 +- .../cfg-attr-crate-2.rs | 2 +- .../cfg-attr-crate-2.stderr | 2 +- .../cfg-attr-multi-invalid-1.rs | 3 +- .../cfg-attr-multi-invalid-1.stderr | 2 +- .../cfg-attr-multi-invalid-2.rs | 3 +- .../cfg-attr-multi-invalid-2.stderr | 2 +- ...-attr-unknown-attribute-macro-expansion.rs | 2 +- ...r-unknown-attribute-macro-expansion.stderr | 2 +- .../cfg-generic-params.rs | 12 +- .../cfg-generic-params.stderr | 52 +- .../cfg-in-crate-1.stderr | 4 +- src/test/ui/conflicting-repr-hints.stderr | 1 + .../const-generics/apit-with-const-param.rs | 2 +- .../core-traits-no-impls-length-33.stderr | 4 +- .../array-wrapper-struct-ctor.rs | 2 + ...st-param-type-depends-on-type-param.stderr | 2 +- src/test/ui/const-generics/const-types.rs | 2 +- .../ui/const-generics/fn-const-param-call.rs | 20 + .../const-generics/fn-const-param-call.stderr | 8 + .../ui/const-generics/fn-const-param-infer.rs | 26 + .../fn-const-param-infer.stderr | 45 + .../foreign-item-const-parameter.rs | 10 + .../foreign-item-const-parameter.stderr | 27 + .../invalid-const-arg-for-type-param.stderr | 2 +- .../{ => issues}/issue-60263.rs | 0 .../{ => issues}/issue-60263.stderr | 0 .../issue-60818-struct-constructors.rs | 0 .../issue-60818-struct-constructors.stderr | 0 .../{ => issues}/issue-61336-1.rs | 0 .../{ => issues}/issue-61336-1.stderr | 0 .../{ => issues}/issue-61336-2.rs | 0 .../{ => issues}/issue-61336-2.stderr | 0 .../{ => issues}/issue-61336.rs | 0 .../{ => issues}/issue-61336.stderr | 0 .../{ => issues}/issue-61422.rs | 4 +- .../{ => issues}/issue-61422.stderr | 0 .../ui/const-generics/issues/issue-61432.rs | 17 + .../const-generics/issues/issue-61432.stderr | 8 + ...sue-62187-encountered-polymorphic-const.rs | 16 + ...62187-encountered-polymorphic-const.stderr | 16 + .../ui/const-generics/issues/issue-64519.rs | 21 + .../const-generics/issues/issue-64519.stderr | 8 + .../raw-ptr-const-param-deref.rs | 19 + .../raw-ptr-const-param-deref.stderr | 8 + .../ui/const-generics/raw-ptr-const-param.rs | 9 + .../const-generics/raw-ptr-const-param.stderr | 20 + .../slice-const-param-mismatch.rs | 14 + .../slice-const-param-mismatch.stderr | 38 + .../ui/const-generics/slice-const-param.rs | 19 + .../const-generics/slice-const-param.stderr | 8 + .../types-mismatch-const-args.rs | 19 + .../types-mismatch-const-args.stderr | 29 + .../ui/const-generics/unused-const-param.rs | 2 +- src/test/ui/consts/array-literal-index-oob.rs | 1 - .../ui/consts/array-literal-index-oob.stderr | 8 +- src/test/ui/consts/auxiliary/issue-63226.rs | 14 + src/test/ui/consts/const-err2.rs | 3 +- src/test/ui/consts/const-err2.stderr | 12 +- src/test/ui/consts/const-err3.rs | 30 + src/test/ui/consts/const-err3.stderr | 38 + src/test/ui/consts/const-err4.stderr | 2 +- .../const-pointer-values-in-various-types.rs | 1 + ...nst-pointer-values-in-various-types.stderr | 76 +- src/test/ui/consts/const-eval/const_fn_ptr.rs | 37 + .../ui/consts/const-eval/const_fn_ptr.stderr | 26 + .../ui/consts/const-eval/const_fn_ptr_fail.rs | 14 + .../const-eval/const_fn_ptr_fail.stderr | 6 + .../consts/const-eval/const_fn_ptr_fail2.rs | 20 + .../const-eval/const_fn_ptr_fail2.stderr | 29 + .../ui/consts/const-eval/const_let.stderr | 1 + .../ui/consts/const-eval/const_transmute.rs | 2 + src/test/ui/consts/const-eval/dangling.rs | 13 + src/test/ui/consts/const-eval/dangling.stderr | 16 + src/test/ui/consts/const-eval/double_check.rs | 1 + .../ui/consts/const-eval/double_check2.rs | 1 + .../ui/consts/const-eval/double_check2.stderr | 4 +- .../const-eval/feature-gate-const_fn_union.rs | 1 + .../feature-gate-const_fn_union.stderr | 2 +- .../ui/consts/const-eval/generic-slice.rs | 31 + .../ui/consts/const-eval/generic-slice.stderr | 30 + .../ui/consts/const-eval/issue-43197.stderr | 8 +- src/test/ui/consts/const-eval/issue-49296.rs | 1 + .../ui/consts/const-eval/issue-49296.stderr | 2 +- src/test/ui/consts/const-eval/issue-64908.rs | 20 + src/test/ui/consts/const-eval/issue-64970.rs | 15 + .../ui/consts/const-eval/issue-64970.stderr | 8 + .../const-eval/promoted_const_fn_fail.rs | 1 + .../const-eval/promoted_const_fn_fail.stderr | 2 +- .../promoted_const_fn_fail_deny_const_err.rs | 1 + ...omoted_const_fn_fail_deny_const_err.stderr | 2 +- .../ui/consts/const-eval/promoted_errors.rs | 8 +- .../consts/const-eval/promoted_errors.stderr | 30 +- .../ui/consts/const-eval/promoted_errors2.rs | 22 + .../consts/const-eval/promoted_errors2.stderr | 68 + .../ui/consts/const-eval/ref_to_int_match.rs | 1 + .../consts/const-eval/ref_to_int_match.stderr | 4 +- .../consts/const-eval/simd/insert_extract.rs | 53 + src/test/ui/consts/const-eval/strlen.rs | 12 +- .../consts/const-eval/transmute-const.stderr | 2 +- src/test/ui/consts/const-eval/ub-enum.rs | 3 + src/test/ui/consts/const-eval/ub-enum.stderr | 36 +- src/test/ui/consts/const-eval/ub-nonnull.rs | 10 +- .../ui/consts/const-eval/ub-nonnull.stderr | 41 +- src/test/ui/consts/const-eval/ub-ref.rs | 5 +- src/test/ui/consts/const-eval/ub-ref.stderr | 16 +- src/test/ui/consts/const-eval/ub-uninhabit.rs | 1 + .../ui/consts/const-eval/ub-uninhabit.stderr | 12 +- src/test/ui/consts/const-eval/ub-upvars.rs | 2 +- .../ui/consts/const-eval/ub-upvars.stderr | 2 +- src/test/ui/consts/const-eval/ub-wide-ptr.rs | 159 + .../ui/consts/const-eval/ub-wide-ptr.stderr | 147 + .../const-eval/union-const-eval-field.rs | 1 + .../const-eval/union-const-eval-field.stderr | 4 +- src/test/ui/consts/const-eval/union-ice.rs | 1 + .../ui/consts/const-eval/union-ice.stderr | 12 +- .../ui/consts/const-eval/union-ub-fat-ptr.rs | 131 - .../consts/const-eval/union-ub-fat-ptr.stderr | 115 - src/test/ui/consts/const-eval/union-ub.rs | 3 + src/test/ui/consts/const-eval/union-ub.stderr | 4 +- .../ui/consts/const-eval/union_promotion.rs | 1 + .../consts/const-eval/union_promotion.stderr | 2 +- src/test/ui/consts/const-eval/valid-const.rs | 3 +- .../const-extern-fn-call-extern-fn.rs | 23 + .../const-extern-fn-call-extern-fn.stderr | 21 + .../const-extern-fn-min-const-fn.rs | 13 + .../const-extern-fn-min-const-fn.stderr | 39 + .../const-extern-fn-requires-unsafe.rs | 10 + .../const-extern-fn-requires-unsafe.stderr | 19 + .../consts/const-extern-fn/const-extern-fn.rs | 35 + .../feature-gate-const_extern_fn.rs | 12 + .../feature-gate-const_extern_fn.stderr | 57 + src/test/ui/consts/const-if.rs | 5 + src/test/ui/consts/const-if.stderr | 15 + .../ui/consts/const-int-overflowing-rpass.rs | 8 + src/test/ui/consts/const-int-sign-rpass.rs | 6 + .../ui/consts/const-int-wrapping-rpass.rs | 8 + src/test/ui/consts/const-labeled-break.rs | 2 +- .../ui/consts/const-match-check.eval1.stderr | 4 +- .../ui/consts/const-match-check.eval2.stderr | 4 +- .../consts/const-match-check.matchck.stderr | 16 +- src/test/ui/consts/const-multi-ref.rs | 11 + src/test/ui/consts/const-multi-ref.stderr | 15 + .../ui/consts/const-pattern-irrefutable.rs | 6 +- .../consts/const-pattern-irrefutable.stderr | 30 +- .../consts/const-prop-read-static-in-const.rs | 12 + .../const-prop-read-static-in-const.stderr | 6 + src/test/ui/consts/const-size_of-cycle.stderr | 15 +- src/test/ui/consts/const_let_refutable.rs | 4 +- src/test/ui/consts/const_let_refutable.stderr | 12 +- src/test/ui/consts/issue-63226.rs | 12 + src/test/ui/consts/issue-64059-2.rs | 6 + src/test/ui/consts/issue-64059.rs | 5 + src/test/ui/consts/issue-64662.rs | 10 + src/test/ui/consts/issue-64662.stderr | 15 + src/test/ui/consts/match_ice.stderr | 3 + .../min_const_fn/min_const_fn.nll.stderr | 328 - .../ui/consts/min_const_fn/min_const_fn.rs | 4 +- .../consts/min_const_fn/min_const_fn.stderr | 18 +- .../min_const_fn/min_const_fn_dyn.nll.stderr | 31 - .../consts/min_const_fn/min_const_fn_dyn.rs | 4 +- .../min_const_fn/min_const_fn_dyn.stderr | 8 +- .../min_const_fn/min_const_fn_unsafe_bad.rs | 16 + ....stderr => min_const_fn_unsafe_bad.stderr} | 18 +- ...fn_unsafe.rs => min_const_fn_unsafe_ok.rs} | 23 +- .../consts/miri_unleashed/assoc_const.stderr | 4 +- .../miri_unleashed/enum_discriminants.rs | 110 + .../miri_unleashed/enum_discriminants.stderr | 24 + ...ure-gate-unleash_the_miri_inside_of_you.rs | 3 +- ...gate-unleash_the_miri_inside_of_you.stderr | 11 +- .../ui/consts/miri_unleashed/mutable_const.rs | 21 + .../miri_unleashed/mutable_const.stderr | 33 + .../miri_unleashed/mutable_references.rs | 9 +- .../miri_unleashed/mutable_references.stderr | 32 +- .../miri_unleashed/mutable_references_ice.rs | 4 +- .../mutable_references_ice.stderr | 8 +- src/test/ui/consts/packed_pattern.stderr | 8 + src/test/ui/consts/packed_pattern2.stderr | 8 + .../consts/promote_const_let.polonius.stderr | 29 - src/test/ui/consts/std/alloc.stderr | 2 +- src/test/ui/consts/too_generic_eval_ice.rs | 13 + .../ui/consts/too_generic_eval_ice.stderr | 43 + .../consts/uninhabited-const-issue-61744.rs | 4 +- .../uninhabited-const-issue-61744.stderr | 57 +- .../ui/consts/validate_never_arrays.stderr | 2 +- src/test/ui/consts/zst_no_llvm_alloc.rs | 19 + .../ui/continue-after-missing-main.nll.stderr | 10 +- .../ui/continue-after-missing-main.stderr | 10 +- src/test/ui/conversion-methods.stderr | 2 +- src/test/ui/copy-a-resource.stderr | 2 +- src/test/ui/custom_attribute.rs | 6 +- src/test/ui/custom_attribute.stderr | 6 +- src/test/ui/dead-code-ret.stderr | 4 +- src/test/ui/defaulted-never-note.rs | 3 +- src/test/ui/defaulted-never-note.stderr | 10 +- .../auxiliary/field-method-macro.rs | 23 + .../auxiliary/nested-fn-macro.rs | 11 + .../auxiliary/private-use-macro.rs | 11 + .../ui/definition-reachable/field-method.rs | 11 + src/test/ui/definition-reachable/nested-fn.rs | 11 + .../definition-reachable/private-non-types.rs | 21 + .../ui/definition-reachable/private-types.rs | 19 + .../ui/definition-reachable/private-use.rs | 10 + .../ui/deprecation/deprecation-in-future.rs | 2 +- .../ui/deprecation/deprecation-sanity.stderr | 2 +- .../ui/deprecation/derive_on_deprecated.rs | 6 + src/test/ui/derive-uninhabited-enum-38885.rs | 11 +- .../ui/derive-uninhabited-enum-38885.stderr | 14 +- src/test/ui/derived-errors/issue-30580.stderr | 2 +- src/test/ui/derived-errors/issue-31997.rs | 1 + src/test/ui/derived-errors/issue-31997.stderr | 2 +- .../derives/derive-assoc-type-not-impl.stderr | 2 +- src/test/ui/derives/derive-hygiene.rs | 121 + .../derives-span-Hash-enum-struct-variant.rs | 2 + ...rives-span-Hash-enum-struct-variant.stderr | 7 +- src/test/ui/derives/derives-span-Hash-enum.rs | 2 + .../ui/derives/derives-span-Hash-enum.stderr | 7 +- .../ui/derives/derives-span-Hash-struct.rs | 2 + .../derives/derives-span-Hash-struct.stderr | 7 +- .../derives/derives-span-Hash-tuple-struct.rs | 2 + .../derives-span-Hash-tuple-struct.stderr | 7 +- src/test/ui/derives/deriving-bounds.stderr | 24 +- src/test/ui/derives/deriving-copyclone.stderr | 36 +- .../issue-39802-show-5-trait-impls.stderr | 36 +- src/test/ui/did_you_mean/issue-40006.stderr | 5 +- src/test/ui/did_you_mean/issue-40396.rs | 21 +- src/test/ui/did_you_mean/issue-40396.stderr | 101 +- ...issue-43871-enum-instead-of-variant.stderr | 26 +- ...-identifier-not-instead-of-negation.stderr | 5 +- .../ui/did_you_mean/multiple-pattern-typo.rs | 7 - .../did_you_mean/multiple-pattern-typo.stderr | 8 - .../ui/did_you_mean/recursion_limit.stderr | 8 +- src/test/ui/drop/dropck_legal_cycles.rs | 30 +- src/test/ui/drop/dynamic-drop-async.rs | 4 +- ...dropck_trait_cycle_checked.polonius.stderr | 74 - .../dropck/dropck_trait_cycle_checked.stderr | 10 +- .../duplicate/duplicate-type-parameter.stderr | 14 +- src/test/ui/duplicate_entry_error.stderr | 2 +- .../edition-keywords-2015-2018-expansion.rs | 2 +- ...dition-keywords-2015-2018-expansion.stderr | 4 +- .../edition-keywords-2018-2015-parsing.rs | 4 +- .../edition-keywords-2018-2015-parsing.stderr | 8 +- .../edition-keywords-2018-2018-expansion.rs | 2 +- ...dition-keywords-2018-2018-expansion.stderr | 4 +- .../edition-keywords-2018-2018-parsing.rs | 4 +- .../edition-keywords-2018-2018-parsing.stderr | 8 +- src/test/ui/elided-test.stderr | 6 +- src/test/ui/empty/empty-macro-use.stderr | 2 +- src/test/ui/empty/empty-never-array.rs | 2 +- src/test/ui/empty/empty-never-array.stderr | 5 +- .../ui/empty/empty-struct-braces-expr.stderr | 12 + .../ui/empty/empty-struct-braces-pat-1.stderr | 3 + .../ui/empty/empty-struct-braces-pat-2.stderr | 6 + .../ui/empty/empty-struct-braces-pat-3.stderr | 6 + .../ui/empty/empty-struct-tuple-pat.stderr | 10 +- src/test/ui/enums-pats-not-idents.stderr | 1 + src/test/ui/error-codes/E0008.rs | 7 - src/test/ui/error-codes/E0008.stderr | 11 - src/test/ui/error-codes/E0023.rs | 5 +- src/test/ui/error-codes/E0023.stderr | 43 +- src/test/ui/error-codes/E0033-teach.rs | 3 +- src/test/ui/error-codes/E0033-teach.stderr | 7 +- src/test/ui/error-codes/E0033.rs | 3 +- src/test/ui/error-codes/E0033.stderr | 7 +- src/test/ui/error-codes/E0038.stderr | 5 +- src/test/ui/error-codes/E0044.rs | 2 +- src/test/ui/error-codes/E0044.stderr | 2 +- src/test/ui/error-codes/E0138.stderr | 2 +- src/test/ui/error-codes/E0152.stderr | 2 +- src/test/ui/error-codes/E0194.rs | 2 +- src/test/ui/error-codes/E0194.stderr | 8 +- src/test/ui/error-codes/E0214.stderr | 10 +- src/test/ui/error-codes/E0267.stderr | 4 +- src/test/ui/error-codes/E0268.stderr | 4 +- src/test/ui/error-codes/E0271.stderr | 8 +- src/test/ui/error-codes/E0275.stderr | 8 +- src/test/ui/error-codes/E0277-2.stderr | 8 +- src/test/ui/error-codes/E0277.stderr | 13 +- src/test/ui/error-codes/E0282.stderr | 5 +- src/test/ui/error-codes/E0283.stderr | 11 +- src/test/ui/error-codes/E0301.rs | 7 - src/test/ui/error-codes/E0301.stderr | 20 - src/test/ui/error-codes/E0302.rs | 8 - src/test/ui/error-codes/E0302.stderr | 17 - src/test/ui/error-codes/E0392.stderr | 2 +- src/test/ui/error-codes/E0401.rs | 2 +- src/test/ui/error-codes/E0401.stderr | 11 +- src/test/ui/error-codes/E0403.stderr | 2 +- src/test/ui/error-codes/E0423.stderr | 3 + src/test/ui/error-codes/E0601.rs | 2 +- src/test/ui/error-codes/E0601.stderr | 4 +- src/test/ui/error-codes/E0617.rs | 6 +- src/test/ui/error-codes/E0617.stderr | 20 +- ...E0621-does-not-trigger-for-closures.stderr | 1 + src/test/ui/error-codes/E0661.rs | 2 +- src/test/ui/error-codes/E0661.stderr | 9 +- src/test/ui/error-festival.stderr | 2 +- .../ui/error-should-say-copy-not-pod.stderr | 13 +- .../explicit-self-lifetime-mismatch.rs | 4 +- .../explicit-self-lifetime-mismatch.stderr | 4 +- src/test/ui/ext-nonexistent.stderr | 2 +- src/test/ui/extenv/issue-55897.rs | 2 +- src/test/ui/extenv/issue-55897.stderr | 8 +- src/test/ui/extern/extern-crate-visibility.rs | 4 +- .../ui/extern/extern-crate-visibility.stderr | 4 +- .../extern/extern-types-not-sync-send.stderr | 24 +- .../ui/extern/extern-types-unsized.stderr | 36 +- .../ui/extern/extern-wrong-value-type.stderr | 12 +- ...llow-unwind-when-calling-panic-directly.rs | 65 + ...sue-64655-extern-rust-must-allow-unwind.rs | 83 + .../ui/feature-gate-optimize_attribute.rs | 10 +- .../ui/feature-gate-optimize_attribute.stderr | 10 +- .../ui/feature-gate/allow-features-empty.rs | 2 - .../feature-gate/allow-features-empty.stderr | 14 +- src/test/ui/feature-gate/allow-features.rs | 4 +- .../ui/feature-gate/allow-features.stderr | 4 +- .../feature-gate-static-nobundle-2.rs | 2 +- .../feature-gate-static-nobundle-2.stderr | 2 +- .../issue-43106-gating-of-builtin-attrs.rs | 11 +- ...issue-43106-gating-of-builtin-attrs.stderr | 448 +- .../issue-43106-gating-of-derive-2.stderr | 4 +- .../issue-43106-gating-of-derive.rs | 3 - .../issue-43106-gating-of-derive.stderr | 16 +- ...ue-43106-gating-of-rustc_deprecated.stderr | 15 +- .../issue-43106-gating-of-stable.stderr | 15 +- .../issue-43106-gating-of-unstable.stderr | 15 +- src/test/ui/feature-gates/bench.rs | 9 + src/test/ui/feature-gates/bench.stderr | 21 + src/test/ui/feature-gates/feature-gate-abi.rs | 10 +- .../ui/feature-gates/feature-gate-abi.stderr | 187 +- .../feature-gate-alloc-error-handler.rs | 2 +- .../feature-gate-alloc-error-handler.stderr | 2 +- .../feature-gates/feature-gate-allow_fail.rs | 2 +- .../feature-gate-allow_fail.stderr | 2 +- .../feature-gate-async-await-2015-edition.rs | 9 - ...ature-gate-async-await-2015-edition.stderr | 31 - .../feature-gates/feature-gate-async-await.rs | 18 - .../feature-gate-async-await.stderr | 45 - .../feature-gate-const_generics-ptr.rs | 9 + .../feature-gate-const_generics-ptr.stderr | 39 + .../feature-gate-custom_attribute.rs | 26 +- .../feature-gate-custom_attribute.stderr | 26 +- .../feature-gate-custom_attribute2.rs | 34 +- .../feature-gate-custom_attribute2.stderr | 186 +- .../feature-gates/feature-gate-doc_alias.rs | 2 +- .../feature-gate-doc_alias.stderr | 2 +- .../ui/feature-gates/feature-gate-doc_cfg.rs | 2 +- .../feature-gates/feature-gate-doc_cfg.stderr | 2 +- .../feature-gates/feature-gate-doc_keyword.rs | 2 +- .../feature-gate-doc_keyword.stderr | 2 +- .../feature-gate-external_doc.rs | 2 +- .../feature-gate-external_doc.stderr | 2 +- .../feature-gates/feature-gate-generators.rs | 6 + .../feature-gate-generators.stderr | 20 +- .../feature-gates/feature-gate-intrinsics.rs | 1 + .../feature-gate-intrinsics.stderr | 8 +- .../feature-gates/feature-gate-is_sorted.rs | 4 +- .../ui/feature-gates/feature-gate-link_cfg.rs | 2 +- .../feature-gate-link_cfg.stderr | 2 +- .../feature-gate-macros_in_extern.rs | 27 - .../feature-gate-macros_in_extern.stderr | 30 - .../feature-gate-marker_trait_attr.rs | 2 +- .../feature-gate-marker_trait_attr.stderr | 2 +- src/test/ui/feature-gates/feature-gate-nll.rs | 14 +- .../ui/feature-gates/feature-gate-nll.stderr | 20 +- .../ui/feature-gates/feature-gate-no_core.rs | 2 +- .../feature-gates/feature-gate-no_core.stderr | 2 +- .../feature-gate-non_exhaustive.rs | 2 +- .../feature-gate-non_exhaustive.stderr | 2 +- .../ui/feature-gates/feature-gate-plugin.rs | 3 +- .../feature-gates/feature-gate-plugin.stderr | 10 +- .../feature-gate-plugin_registrar.rs | 5 +- .../feature-gate-plugin_registrar.stderr | 21 +- .../feature-gate-repr-simd.stderr | 3 +- .../feature-gates/feature-gate-rustc-attrs.rs | 4 +- .../feature-gate-rustc-attrs.stderr | 4 +- .../feature-gate-rustc-diagnostic-macros.rs | 13 - ...eature-gate-rustc-diagnostic-macros.stderr | 20 - .../feature-gate-staged_api.stderr | 5 +- .../feature-gate-static-nobundle.rs | 2 +- .../feature-gate-static-nobundle.stderr | 2 +- .../feature-gate-track_caller.rs | 5 + .../feature-gate-track_caller.stderr | 12 + .../feature-gate-type_ascription.rs | 2 +- ...-gate-unboxed-closures-manual-impls.stderr | 4 +- .../feature-gate-unwind-attributes.rs | 2 +- .../feature-gate-unwind-attributes.stderr | 2 +- src/test/ui/fmt/send-sync.stderr | 16 +- src/test/ui/fn/fn-trait-formatting.stderr | 12 +- src/test/ui/for/for-c-in-str.rs | 5 +- ...oop-refutable-pattern-error-message.stderr | 4 +- ...for-loop-unconstrained-element-type.stderr | 5 +- src/test/ui/format-hygiene.rs | 8 - src/test/ui/gated-bad-feature.stderr | 3 +- ...erator-yielding-or-returning-itself.stderr | 13 +- .../ui/generator/auto-trait-regions.stderr | 18 +- .../issue-61442-stmt-expr-with-drop.rs | 2 +- .../ui/generator/issue-62506-two_awaits.rs | 1 - .../generator/niche-in-generator.rs | 2 + .../no-arguments-on-generators.stderr | 8 - ...tors.rs => no-parameters-on-generators.rs} | 3 +- .../no-parameters-on-generators.stderr | 21 + src/test/ui/generator/not-send-sync.stderr | 16 +- .../partial-initialization-across-yield.rs | 6 +- ...partial-initialization-across-yield.stderr | 12 +- ...escapes-but-not-over-yield.polonius.stderr | 20 - src/test/ui/generator/static-not-unpin.stderr | 13 +- src/test/ui/generic/generic-extern.stderr | 2 +- ...-type-param-can-reference-self-in-trait.rs | 20 + ...e-param-can-reference-self-in-trait.stderr | 12 + ...efault-type-param-cannot-reference-self.rs | 45 + ...lt-type-param-cannot-reference-self.stderr | 39 + .../hrtb-type-outlives.rs | 2 - .../ui/hrtb/due-to-where-clause.nll.stderr | 8 + src/test/ui/hrtb/due-to-where-clause.rs | 13 + src/test/ui/hrtb/due-to-where-clause.stderr | 14 + .../ui/hrtb/hrtb-cache-issue-54302.stderr | 9 +- src/test/ui/hrtb/hrtb-conflate-regions.rs | 1 - src/test/ui/hrtb/hrtb-conflate-regions.stderr | 17 +- ...b-exists-forall-trait-contravariant.stderr | 19 +- .../hrtb-exists-forall-trait-covariant.stderr | 19 +- .../hrtb-exists-forall-trait-invariant.stderr | 19 +- ...igher-ranker-supertraits-transitive.stderr | 17 +- .../hrtb-higher-ranker-supertraits.stderr | 39 +- src/test/ui/hrtb/hrtb-just-for-static.stderr | 34 +- src/test/ui/hrtb/issue-30786.migrate.stderr | 14 +- src/test/ui/hrtb/issue-30786.nll.stderr | 12 +- src/test/ui/hrtb/issue-30786.rs | 7 +- src/test/ui/hrtb/issue-46989.stderr | 12 +- src/test/ui/hrtb/issue-57639.rs | 2 +- src/test/ui/hrtb/issue-62203-hrtb-ice.stderr | 2 + .../ui/hygiene/auxiliary/codegen-attrs.rs | 10 + src/test/ui/hygiene/auxiliary/not-libstd.rs | 1 + .../ui/hygiene/cross-crate-codegen-attrs.rs | 12 + src/test/ui/hygiene/eager-from-opaque-2.rs | 22 + src/test/ui/hygiene/eager-from-opaque.rs | 20 + src/test/ui/hygiene/format-args.rs | 12 + .../ui/hygiene/no_implicit_prelude-2018.rs | 2 +- .../hygiene/no_implicit_prelude-2018.stderr | 2 +- src/test/ui/hygiene/no_implicit_prelude.rs | 2 +- .../ui/hygiene/no_implicit_prelude.stderr | 20 +- src/test/ui/hygiene/prelude-import-hygiene.rs | 29 + src/test/ui/hygiene/privacy-early.rs | 17 + src/test/ui/hygiene/privacy-early.stderr | 21 + src/test/ui/hygiene/trait_items.stderr | 4 +- src/test/ui/hygiene/unpretty-debug.stdout | 10 + src/test/ui/if-ret.stderr | 10 + src/test/ui/if/if-no-match-bindings.stderr | 40 +- src/test/ui/if/if-without-else-as-fn-expr.rs | 6 - .../ui/if/if-without-else-as-fn-expr.stderr | 83 +- .../dyn-trait.stderr | 1 + src/test/ui/impl-trait/auto-trait-leak.stderr | 8 +- .../ui/impl-trait/auto-trait-leak2.stderr | 16 +- src/test/ui/impl-trait/auto-trait.rs | 23 + src/test/ui/impl-trait/auto-trait.stderr | 12 + src/test/ui/impl-trait/bindings-opaque.stderr | 6 +- .../ui/impl-trait/bound-normalization-fail.rs | 7 +- .../bound-normalization-fail.stderr | 16 +- .../ui/impl-trait/bound-normalization-pass.rs | 5 - .../bound-normalization-pass.stderr | 2 +- .../impl-trait/closure-calling-parent-fn.rs | 2 +- .../dyn-trait-elided-two-inputs-assoc.rs | 16 + .../dyn-trait-elided-two-inputs-param.rs | 11 + .../dyn-trait-elided-two-inputs-ref-assoc.rs | 27 + .../dyn-trait-elided-two-inputs-ref-param.rs | 23 + src/test/ui/impl-trait/equality2.stderr | 2 + .../impl-generic-mismatch-ab.stderr | 2 + src/test/ui/impl-trait/issue-55872-2.rs | 3 +- src/test/ui/impl-trait/issue-55872-2.stderr | 4 +- ...e-21659-show-relevant-trait-impls-3.stderr | 2 +- src/test/ui/impl-trait/issues/issue-53457.rs | 4 +- .../method-suggestion-no-duplication.stderr | 2 +- .../multiple-lifetimes/inverse-bounds.rs | 2 +- ...nds-pick-original-type-alias-impl-trait.rs | 2 +- .../impl-trait/needs_least_region_or_bound.rs | 4 +- src/test/ui/impl-trait/negative-reasoning.rs | 22 + .../ui/impl-trait/negative-reasoning.stderr | 14 + .../no-method-suggested-traits.stderr | 68 +- ...-impl-trait-type--through-non-recursize.rs | 25 + ...l-trait-type--through-non-recursize.stderr | 35 + .../universal-mismatched-type.stderr | 2 + .../universal-two-impl-traits.stderr | 2 + src/test/ui/impl-trait/where-allowed.rs | 6 +- src/test/ui/impl-trait/where-allowed.stderr | 100 +- ...e-extern-crate-restricted-shadowing.stderr | 2 +- src/test/ui/imports/gensymed.rs | 4 +- .../ui/imports/glob-conflict-cross-crate.rs | 2 +- .../imports/glob-conflict-cross-crate.stderr | 2 +- src/test/ui/imports/issue-53512.rs | 3 +- src/test/ui/imports/issue-53512.stderr | 8 +- src/test/ui/imports/issue-56125.stderr | 12 +- src/test/ui/imports/issue-57539.stderr | 4 +- .../local-modularized-tricky-fail-1.stderr | 38 +- .../ui/imports/shadow_builtin_macros.stderr | 28 +- .../ui/imports/unresolved-imports-used.rs | 14 +- .../ui/imports/unresolved-imports-used.stderr | 44 +- .../mismatched_trait_impl-2.stderr | 1 + .../mismatched_trait_impl.nll.stderr | 1 + .../mismatched_trait_impl.stderr | 1 + src/test/ui/in-band-lifetimes/nested-items.rs | 20 + src/test/ui/inaccessible-test-modules.stderr | 21 - src/test/ui/include-macros/data.bin | 2 + src/test/ui/include-macros/normalization.rs | 12 + src/test/ui/include-single-expr-helper-1.rs | 5 + src/test/ui/include-single-expr-helper.rs | 5 + src/test/ui/include-single-expr.rs | 6 + src/test/ui/include-single-expr.stderr | 10 + ...infer-async-enabled-impl-trait-bindings.rs | 17 + ...r-async-enabled-impl-trait-bindings.stderr | 19 + src/test/ui/inference/cannot-infer-async.rs | 15 + .../ui/inference/cannot-infer-async.stderr | 11 + src/test/ui/inference/cannot-infer-closure.rs | 6 + .../ui/inference/cannot-infer-closure.stderr | 13 + .../ui/infinite/infinite-autoderef.stderr | 4 +- src/test/ui/inline-asm-bad-operand.stderr | 4 +- .../ui/inner-static-type-parameter.stderr | 6 +- .../interior-mutability.rs | 2 + .../interior-mutability.stderr | 10 +- src/test/ui/intrinsics-always-extern.rs | 16 + src/test/ui/intrinsics-always-extern.stderr | 24 + src/test/ui/intrinsics/intrinsic-uninit.rs | 13 + src/test/ui/invalid/invalid-plugin-attr.rs | 1 + .../ui/invalid/invalid-plugin-attr.stderr | 8 + .../ui/issues/auxiliary/issue-57271-lib.rs | 11 + src/test/ui/issues/issue-10291.stderr | 1 + src/test/ui/issues/issue-10465.stderr | 4 +- src/test/ui/issues/issue-11692-1.rs | 2 +- src/test/ui/issues/issue-11692-1.stderr | 2 +- src/test/ui/issues/issue-11692-2.rs | 2 +- src/test/ui/issues/issue-11692-2.stderr | 2 +- src/test/ui/issues/issue-12028.rs | 4 +- src/test/ui/issues/issue-12028.stderr | 4 +- src/test/ui/issues/issue-1251.rs | 2 - src/test/ui/issues/issue-13483.stderr | 4 +- src/test/ui/issues/issue-13853.stderr | 4 +- src/test/ui/issues/issue-14309.rs | 2 +- src/test/ui/issues/issue-14309.stderr | 25 +- src/test/ui/issues/issue-15207.stderr | 2 +- src/test/ui/issues/issue-15381.rs | 4 +- src/test/ui/issues/issue-15381.stderr | 8 +- src/test/ui/issues/issue-15783.rs | 8 +- src/test/ui/issues/issue-15783.stderr | 2 +- src/test/ui/issues/issue-16250.rs | 2 +- src/test/ui/issues/issue-16250.stderr | 5 +- src/test/ui/issues/issue-16683.stderr | 1 + src/test/ui/issues/issue-16739.rs | 4 - src/test/ui/issues/issue-17252.stderr | 6 +- src/test/ui/issues/issue-17651.rs | 1 + src/test/ui/issues/issue-17651.stderr | 15 +- src/test/ui/issues/issue-17740.rs | 4 +- src/test/ui/issues/issue-17740.stderr | 4 +- src/test/ui/issues/issue-17758.stderr | 1 + src/test/ui/issues/issue-17904-2.stderr | 2 +- src/test/ui/issues/issue-17905-2.rs | 4 +- src/test/ui/issues/issue-17905-2.stderr | 4 +- src/test/ui/issues/issue-18159.stderr | 5 +- src/test/ui/issues/issue-1871.stderr | 2 +- src/test/ui/issues/issue-18959.stderr | 5 +- src/test/ui/issues/issue-19086.stderr | 3 + src/test/ui/issues/issue-1920-1.stderr | 13 +- src/test/ui/issues/issue-1920-2.stderr | 13 +- src/test/ui/issues/issue-1920-3.stderr | 13 +- src/test/ui/issues/issue-19380.stderr | 5 +- src/test/ui/issues/issue-19521.stderr | 2 +- src/test/ui/issues/issue-19538.stderr | 9 +- src/test/ui/issues/issue-19692.stderr | 2 +- src/test/ui/issues/issue-19734.rs | 2 +- src/test/ui/issues/issue-19734.stderr | 2 +- src/test/ui/issues/issue-20005.stderr | 8 +- src/test/ui/issues/issue-20225.stderr | 6 + src/test/ui/issues/issue-20413.stderr | 18 +- .../ui/issues/issue-20831-debruijn.stderr | 3 +- src/test/ui/issues/issue-21160.rs | 2 + src/test/ui/issues/issue-21160.stderr | 7 +- src/test/ui/issues/issue-2149.stderr | 2 +- src/test/ui/issues/issue-2150.stderr | 5 +- src/test/ui/issues/issue-21596.stderr | 2 +- src/test/ui/issues/issue-21763.stderr | 8 +- src/test/ui/issues/issue-21837.stderr | 8 +- src/test/ui/issues/issue-21974.rs | 2 +- src/test/ui/issues/issue-21974.stderr | 11 +- src/test/ui/issues/issue-23302-1.stderr | 4 +- src/test/ui/issues/issue-23302-2.stderr | 4 +- src/test/ui/issues/issue-23302-3.stderr | 22 +- src/test/ui/issues/issue-23477.rs | 4 +- src/test/ui/issues/issue-23589.stderr | 10 +- src/test/ui/issues/issue-23966.stderr | 4 +- src/test/ui/issues/issue-24204.stderr | 9 +- src/test/ui/issues/issue-24267-flow-exit.rs | 4 +- .../ui/issues/issue-24267-flow-exit.stderr | 8 +- src/test/ui/issues/issue-24424.rs | 2 +- src/test/ui/issues/issue-24424.stderr | 11 +- ...535-allow-mutable-borrow-in-match-guard.rs | 2 - src/test/ui/issues/issue-25076.stderr | 13 +- src/test/ui/issues/issue-25385.stderr | 4 +- src/test/ui/issues/issue-26448-2.rs | 2 +- src/test/ui/issues/issue-26448-3.rs | 2 +- src/test/ui/issues/issue-27042.stderr | 9 +- ...issue-27282-move-match-input-into-guard.rs | 2 - ...e-27282-move-match-input-into-guard.stderr | 2 +- .../issue-27282-move-ref-mut-into-guard.rs | 5 - ...issue-27282-move-ref-mut-into-guard.stderr | 2 +- ...sue-27282-mutate-before-diverging-arm-1.rs | 2 - ...27282-mutate-before-diverging-arm-1.stderr | 2 +- ...sue-27282-mutate-before-diverging-arm-2.rs | 2 - ...27282-mutate-before-diverging-arm-2.stderr | 2 +- ...sue-27282-mutate-before-diverging-arm-3.rs | 2 +- .../issue-27282-reborrow-ref-mut-in-guard.rs | 2 - ...sue-27282-reborrow-ref-mut-in-guard.stderr | 2 +- src/test/ui/issues/issue-27592.rs | 2 +- src/test/ui/issues/issue-27592.stderr | 7 +- src/test/ui/issues/issue-27697.rs | 2 +- src/test/ui/issues/issue-28098.rs | 2 + src/test/ui/issues/issue-28098.stderr | 36 +- src/test/ui/issues/issue-28105.rs | 4 +- src/test/ui/issues/issue-28105.stderr | 8 +- src/test/ui/issues/issue-2823.stderr | 2 +- src/test/ui/issues/issue-29124.stderr | 4 +- src/test/ui/issues/issue-29147.stderr | 11 +- src/test/ui/issues/issue-29181.stderr | 2 +- src/test/ui/issues/issue-2951.stderr | 2 + src/test/ui/issues/issue-29723.rs | 2 - src/test/ui/issues/issue-29723.stderr | 2 +- src/test/ui/issues/issue-31011.stderr | 3 + src/test/ui/issues/issue-31173.stderr | 2 +- src/test/ui/issues/issue-31561.rs | 2 +- src/test/ui/issues/issue-31561.stderr | 6 +- src/test/ui/issues/issue-31776.rs | 6 +- src/test/ui/issues/issue-32004.stderr | 8 +- src/test/ui/issues/issue-32323.stderr | 4 +- src/test/ui/issues/issue-32655.rs | 4 +- src/test/ui/issues/issue-32655.stderr | 4 +- src/test/ui/issues/issue-32963.stderr | 9 +- src/test/ui/issues/issue-32995-2.stderr | 12 +- src/test/ui/issues/issue-32995.stderr | 28 +- src/test/ui/issues/issue-33575.rs | 4 + src/test/ui/issues/issue-33575.stderr | 9 + src/test/ui/issues/issue-34334.rs | 1 + src/test/ui/issues/issue-34334.stderr | 12 +- src/test/ui/issues/issue-35241.stderr | 5 +- src/test/ui/issues/issue-35675.stderr | 2 +- src/test/ui/issues/issue-35677.stderr | 2 +- src/test/ui/issues/issue-36163.stderr | 6 +- src/test/ui/issues/issue-36299.stderr | 4 +- src/test/ui/issues/issue-36617.rs | 1 + src/test/ui/issues/issue-36617.stderr | 10 +- src/test/ui/issues/issue-36638.stderr | 2 +- src/test/ui/issues/issue-36836.rs | 15 + src/test/ui/issues/issue-36836.stderr | 9 + src/test/ui/issues/issue-3707.stderr | 2 +- src/test/ui/issues/issue-37534.stderr | 4 +- src/test/ui/issues/issue-38591.rs | 2 +- src/test/ui/issues/issue-39175.stderr | 4 +- src/test/ui/issues/issue-39687.stderr | 4 +- src/test/ui/issues/issue-39970.stderr | 8 +- .../issues/issue-40510-1.migrate.nll.stderr | 13 - .../ui/issues/issue-40510-1.migrate.stderr | 11 +- src/test/ui/issues/issue-40510-1.rs | 11 +- ...0510-1.nll.stderr => issue-40510-1.stderr} | 2 +- .../ui/issues/issue-40510-3.migrate.stderr | 11 +- src/test/ui/issues/issue-40510-3.nll.stderr | 15 - src/test/ui/issues/issue-40510-3.rs | 11 +- ...igrate.nll.stderr => issue-40510-3.stderr} | 2 +- src/test/ui/issues/issue-40827.stderr | 16 +- src/test/ui/issues/issue-40845.rs | 4 +- src/test/ui/issues/issue-40845.stderr | 4 +- src/test/ui/issues/issue-41880.stderr | 2 +- src/test/ui/issues/issue-43162.stderr | 10 +- src/test/ui/issues/issue-43189.stderr | 4 +- src/test/ui/issues/issue-43623.rs | 19 + src/test/ui/issues/issue-43623.stderr | 28 + src/test/ui/issues/issue-43806.rs | 2 +- src/test/ui/issues/issue-44023.stderr | 2 +- src/test/ui/issues/issue-44405.rs | 22 + src/test/ui/issues/issue-44405.stderr | 11 + src/test/ui/issues/issue-44415.stderr | 28 - src/test/ui/issues/issue-45157.rs | 1 - src/test/ui/issues/issue-45157.stderr | 2 +- ...96-scribble-on-boxed-borrow.migrate.stderr | 60 - .../issue-45696-scribble-on-boxed-borrow.rs | 44 +- ...sue-45696-scribble-on-boxed-borrow.stderr} | 9 +- src/test/ui/issues/issue-46101.rs | 2 + src/test/ui/issues/issue-46101.stderr | 9 +- src/test/ui/issues/issue-47706-trait.stderr | 4 +- src/test/ui/issues/issue-47706.stderr | 24 +- src/test/ui/issues/issue-48132.rs | 2 + src/test/ui/issues/issue-48179.rs | 2 +- src/test/ui/issues/issue-48728.stderr | 2 +- src/test/ui/issues/issue-49040.rs | 1 + src/test/ui/issues/issue-49040.stderr | 6 +- src/test/ui/issues/issue-49074.rs | 4 +- src/test/ui/issues/issue-49074.stderr | 14 +- src/test/ui/issues/issue-49824.nll.stderr | 18 - src/test/ui/issues/issue-49824.rs | 10 +- src/test/ui/issues/issue-49824.stderr | 21 +- src/test/ui/issues/issue-49934-errors.rs | 13 + src/test/ui/issues/issue-49934-errors.stderr | 26 + src/test/ui/issues/issue-49934.rs | 9 +- src/test/ui/issues/issue-49934.stderr | 26 +- .../option-as_deref.rs | 2 - .../option-as_deref.stderr | 2 +- .../option-as_deref_mut.rs | 2 - .../option-as_deref_mut.stderr | 4 +- src/test/ui/issues/issue-50301.rs | 31 + src/test/ui/issues/issue-50415.rs | 6 +- src/test/ui/issues/issue-50571.rs | 6 + src/test/ui/issues/issue-50571.stderr | 13 + src/test/ui/issues/issue-50576.stderr | 8 +- src/test/ui/issues/issue-50577.rs | 1 - src/test/ui/issues/issue-50577.stderr | 15 +- src/test/ui/issues/issue-50581.stderr | 4 +- src/test/ui/issues/issue-5067.rs | 4 +- src/test/ui/issues/issue-50781.stderr | 4 +- src/test/ui/issues/issue-5153.stderr | 2 +- src/test/ui/issues/issue-52060.rs | 1 - src/test/ui/issues/issue-52060.stderr | 10 +- src/test/ui/issues/issue-52213.stderr | 1 + src/test/ui/issues/issue-52262.rs | 25 + src/test/ui/issues/issue-52262.stderr | 9 + src/test/ui/issues/issue-52533.stderr | 1 + src/test/ui/{ => issues}/issue-53912.rs | 0 src/test/ui/issues/issue-54062.stderr | 2 +- src/test/ui/issues/issue-54302-cases.stderr | 54 +- src/test/ui/issues/issue-54302.stderr | 9 +- src/test/ui/issues/issue-54954.rs | 4 +- src/test/ui/issues/issue-54954.stderr | 25 +- src/test/ui/issues/issue-55731.stderr | 13 +- src/test/ui/issues/issue-55796.stderr | 1 + src/test/ui/issues/issue-56806.rs | 5 +- src/test/ui/issues/issue-56806.stderr | 5 +- src/test/ui/issues/issue-56870.rs | 38 + src/test/ui/issues/issue-57271.rs | 24 + src/test/ui/issues/issue-57271.stderr | 25 + src/test/ui/issues/issue-57362-1.stderr | 2 +- .../issue-57399-self-return-impl-trait.rs | 22 + .../issue-57399-self-return-impl-trait.stderr | 8 + src/test/ui/issues/issue-58022.rs | 18 + src/test/ui/issues/issue-58022.stderr | 19 + src/test/ui/issues/issue-58344.rs | 50 + src/test/ui/issues/issue-58344.stderr | 19 + src/test/ui/{ => issues}/issue-59020.rs | 0 src/test/ui/issues/issue-5927.stderr | 3 +- src/test/ui/issues/issue-60057.rs | 2 + src/test/ui/issues/issue-60057.stderr | 9 +- src/test/ui/issues/issue-60218.rs | 19 + src/test/ui/issues/issue-60218.stderr | 15 + src/test/ui/issues/issue-60283.stderr | 38 +- .../issue-61711-once-caused-rustc-inf-loop.rs | 2 +- src/test/ui/issues/issue-63983.rs | 15 + src/test/ui/issues/issue-63983.stderr | 21 + src/test/ui/issues/issue-64430.rs | 14 + src/test/ui/issues/issue-64430.stderr | 12 + src/test/ui/issues/issue-64559.rs | 6 + src/test/ui/issues/issue-64559.stderr | 18 + src/test/ui/issues/issue-6458-4.stderr | 2 +- src/test/ui/issues/issue-64593.rs | 12 + src/test/ui/issues/issue-64620.rs | 5 + src/test/ui/issues/issue-64620.stderr | 9 + src/test/ui/issues/issue-64732.rs | 9 + src/test/ui/issues/issue-64732.stderr | 22 + .../ui/issues/issue-64792-bad-unicode-ctor.rs | 5 + .../issue-64792-bad-unicode-ctor.stderr | 15 + ...issue-65284-suggest-generic-trait-bound.rs | 11 + ...e-65284-suggest-generic-trait-bound.stderr | 15 + src/test/ui/issues/issue-6919.rs | 1 - src/test/ui/issues/issue-7246.stderr | 4 +- src/test/ui/issues/issue-8460-const.rs | 2 + src/test/ui/issues/issue-8460-const.stderr | 82 +- src/test/ui/issues/issue-8460-const2.rs | 59 + src/test/ui/issues/issue-8460-const2.stderr | 188 + src/test/ui/iterators/bound.stderr | 7 +- .../ui/iterators/iter-count-overflow-debug.rs | 16 + .../iterators/iter-count-overflow-ndebug.rs | 11 + .../ui/iterators/iter-map-fold-type-length.rs | 38 + .../iterators/iter-position-overflow-debug.rs | 22 + .../iter-position-overflow-ndebug.rs | 13 + src/test/ui/json-multiple.polonius.stderr | 1 + src/test/ui/json-options.polonius.stderr | 1 + src/test/ui/json-short.stderr | 4 +- .../keyword-extern-as-identifier-pat.rs | 2 +- .../keyword-extern-as-identifier-pat.stderr | 8 +- .../keyword/keyword-self-as-identifier.stderr | 1 + src/test/ui/kindck/kindck-copy.stderr | 133 +- .../kindck/kindck-impl-type-params-2.stderr | 12 +- .../kindck/kindck-inherited-copy-bound.stderr | 12 +- .../ui/kindck/kindck-nonsendable-1.stderr | 8 +- src/test/ui/kindck/kindck-send-object.stderr | 16 +- .../ui/kindck/kindck-send-object1.nll.stderr | 16 +- src/test/ui/kindck/kindck-send-object1.stderr | 16 +- src/test/ui/kindck/kindck-send-object2.stderr | 16 +- src/test/ui/kindck/kindck-send-owned.stderr | 8 +- src/test/ui/kindck/kindck-send-unsafe.stderr | 12 +- src/test/ui/lang-item-missing-generator.rs | 19 + .../ui/lang-item-missing-generator.stderr | 8 + src/test/ui/lifetime-before-type-params.rs | 2 + .../ui/lifetime-before-type-params.stderr | 7 +- .../lifetime-elision-return-type-trait.rs | 2 +- .../lifetime-elision-return-type-trait.stderr | 10 +- .../ex3-both-anon-regions-3.nll.stderr | 6 +- src/test/ui/lint/empty-lint-attributes.rs | 2 +- ...47390-unused-variable-in-struct-pattern.rs | 3 + ...0-unused-variable-in-struct-pattern.stderr | 20 +- .../ui/lint/issue-54538-unused-parens-lint.rs | 92 +- .../issue-54538-unused-parens-lint.stderr | 136 +- .../ui/lint/lint-attr-non-item-node.stderr | 4 +- src/test/ui/lint/lint-ctypes-enum.rs | 21 +- src/test/ui/lint/lint-ctypes-enum.stderr | 77 +- src/test/ui/lint/lint-ctypes.rs | 13 +- src/test/ui/lint/lint-ctypes.stderr | 127 +- .../ui/lint/lint-dead-code-const-and-self.rs | 35 + .../lint-dead-code-empty-unused-enum-pub.rs | 6 + .../lint/lint-dead-code-empty-unused-enum.rs | 5 + .../lint-dead-code-empty-unused-enum.stderr | 15 + .../ui/lint/lint-dead-code-unused-enum.rs | 11 + .../ui/lint/lint-dead-code-unused-enum.stderr | 27 + .../lint/lint-dead-code-unused-variant-pub.rs | 14 + .../ui/lint/lint-dead-code-unused-variant.rs | 13 + .../lint/lint-dead-code-unused-variant.stderr | 15 + src/test/ui/lint/lint-exceeding-bitshifts.rs | 2 + .../ui/lint/lint-exceeding-bitshifts.stderr | 38 +- src/test/ui/lint/lint-exceeding-bitshifts2.rs | 2 + .../ui/lint/lint-exceeding-bitshifts2.stderr | 8 +- src/test/ui/lint/lint-qualification.rs | 1 + src/test/ui/lint/lint-qualification.stderr | 2 +- .../ui/lint/lint-stability-deprecated.stderr | 36 +- src/test/ui/lint/lint-unused-mut-variables.rs | 2 +- src/test/ui/lint/lint-unused-variables.rs | 17 +- src/test/ui/lint/lint-unused-variables.stderr | 28 +- src/test/ui/lint/opaque-ty-ffi-unsafe.rs | 16 + src/test/ui/lint/opaque-ty-ffi-unsafe.stderr | 15 + .../redundant-semi-proc-macro-def.rs | 12 + .../redundant-semi-proc-macro.rs | 19 + .../redundant-semi-proc-macro.stderr | 21 + src/test/ui/lint/uninitialized-zeroed.rs | 91 + src/test/ui/lint/uninitialized-zeroed.stderr | 381 + src/test/ui/lint/unreachable-async-fn.rs | 9 + src/test/ui/lint/use_suggestion_json.stderr | 2 +- .../ui/liveness/liveness-forgot-ret.stderr | 2 +- .../ui/liveness/liveness-missing-ret2.stderr | 2 +- .../liveness-return-last-stmt-semi.stderr | 8 +- src/test/ui/liveness/liveness-unused.stderr | 4 +- src/test/ui/loops/loop-break-value.stderr | 15 +- .../ui/loops/loop-labeled-break-value.stderr | 27 +- src/test/ui/loops/loop-proper-liveness.rs | 2 +- src/test/ui/loops/loop-proper-liveness.stderr | 4 +- .../ui/loops/loop-properly-diverging-2.stderr | 9 +- src/test/ui/lto-duplicate-symbols.stderr | 2 +- src/test/ui/lub-if.stderr | 1 + src/test/ui/lub-match.stderr | 1 + .../macros/auxiliary/proc_macro_sequence.rs | 20 +- .../ui/macros/builtin-prelude-no-accidents.rs | 8 + .../builtin-prelude-no-accidents.stderr | 21 + src/test/ui/macros/builtin-std-paths-fail.rs | 21 + .../ui/macros/builtin-std-paths-fail.stderr | 75 + src/test/ui/macros/builtin-std-paths.rs | 32 + .../derive-in-eager-expansion-hang.stderr | 3 + src/test/ui/macros/issue-54441.rs | 2 - src/test/ui/macros/issue-54441.stderr | 2 +- .../macro-backtrace-invalid-internals.stderr | 4 +- .../ui/macros/macro-comma-support-rpass.rs | 1 + .../ui/macros/macro-expansion-tests.stderr | 4 +- src/test/ui/macros/macro-first-set.rs | 8 +- src/test/ui/macros/macro-in-fn.rs | 8 + src/test/ui/macros/macro-meta-items-modern.rs | 11 + src/test/ui/macros/macro-name-typo.stderr | 2 +- .../ui/macros/macro-path-prelude-fail-3.rs | 2 +- .../macros/macro-path-prelude-fail-3.stderr | 2 +- .../macro-path-prelude-shadowing.stderr | 2 +- src/test/ui/macros/macro-reexport-removed.rs | 2 +- .../ui/macros/macro-reexport-removed.stderr | 2 +- .../ui/macros/macro-use-wrong-name.stderr | 2 +- src/test/ui/macros/macro_undefined.stderr | 2 +- src/test/ui/macros/macros-in-extern-rpass.rs | 30 - src/test/ui/macros/macros-in-extern.rs | 21 +- src/test/ui/macros/macros-in-extern.stderr | 30 - .../ui/macros/restricted-shadowing-modern.rs | 2 - .../macros/restricted-shadowing-modern.stderr | 18 +- src/test/ui/macros/same-sequence-span.stderr | 16 +- src/test/ui/macros/trace-macro.stderr | 2 +- src/test/ui/macros/try-macro.rs | 1 + src/test/ui/main-wrong-location.rs | 1 + src/test/ui/main-wrong-location.stderr | 16 +- src/test/ui/malformed/malformed-plugin-1.rs | 1 + .../ui/malformed/malformed-plugin-1.stderr | 8 + src/test/ui/malformed/malformed-plugin-2.rs | 1 + .../ui/malformed/malformed-plugin-2.stderr | 8 + src/test/ui/malformed/malformed-plugin-3.rs | 1 + .../ui/malformed/malformed-plugin-3.stderr | 8 + .../ui/malformed/malformed-regressions.stderr | 6 +- .../overlap-marker-trait.stderr | 13 +- .../ui/match/match-arm-resolving-to-never.rs | 19 + .../match/match-arm-resolving-to-never.stderr | 22 + .../match-no-arms-unreachable-after.stderr | 4 +- .../match/match-pattern-field-mismatch.stderr | 3 + src/test/ui/match/match-ref-mut-stability.rs | 2 - .../ui/match/match-unresolved-one-arm.stderr | 5 +- src/test/ui/match/match-vec-mismatch.stderr | 2 +- .../ui/match/non-exhaustive-defined-here.rs | 72 + .../match/non-exhaustive-defined-here.stderr | 170 + src/test/ui/maybe-bounds-where.stderr | 2 +- ...method-ambig-one-trait-unknown-int-type.rs | 2 +- .../ui/methods/method-call-err-msg.stderr | 2 +- src/test/ui/methods/method-path-in-pattern.rs | 6 + .../ui/methods/method-path-in-pattern.stderr | 21 +- src/test/ui/methods/method-projection.rs | 9 - .../mir-dataflow/indirect-mutation-offset.rs | 41 + .../indirect-mutation-offset.stderr | 10 + src/test/ui/mismatched_types/E0631.stderr | 44 +- src/test/ui/mismatched_types/abridged.rs | 9 + src/test/ui/mismatched_types/abridged.stderr | 30 +- .../mismatched_types/closure-arg-count.stderr | 46 +- .../closure-arg-type-mismatch.stderr | 28 +- .../mismatched_types/closure-mismatch.stderr | 16 +- .../ui/mismatched_types/fn-variance-1.stderr | 26 +- .../ui/mismatched_types/issue-35030.stderr | 2 + src/test/ui/mismatched_types/issue-36053-2.rs | 1 - .../ui/mismatched_types/issue-36053-2.stderr | 12 +- .../method-help-unsatisfied-bound.stderr | 2 +- .../unboxed-closures-vtable-mismatch.rs | 3 +- .../unboxed-closures-vtable-mismatch.stderr | 13 +- src/test/ui/missing/missing-macro-use.rs | 2 +- src/test/ui/missing/missing-macro-use.stderr | 2 +- src/test/ui/missing/missing-main.stderr | 4 +- src/test/ui/missing/missing-return.stderr | 2 +- .../missing/missing-semicolon-warning.stderr | 4 +- src/test/ui/moves/move-into-dead-array-1.rs | 2 +- .../ui/moves/move-into-dead-array-1.stderr | 4 +- src/test/ui/multiple-plugin-registrars.stderr | 14 + src/test/ui/mut/mutable-enum-indirect.stderr | 8 +- src/test/ui/mutexguard-sync.stderr | 12 +- src/test/ui/namespace/namespace-mix.stderr | 575 +- src/test/ui/never-assign-dead-code.stderr | 11 +- src/test/ui/never-from-impl-is-reserved.rs | 12 + .../ui/never-from-impl-is-reserved.stderr | 14 + src/test/ui/nll/borrowed-match-issue-45045.rs | 2 - .../ui/nll/borrowed-match-issue-45045.stderr | 2 +- .../ui/nll/borrowed-referent-issue-38899.rs | 2 - .../nll/borrowed-referent-issue-38899.stderr | 2 +- src/test/ui/nll/closures-in-loops.stderr | 2 +- .../do-not-ignore-lifetime-bounds-in-copy.rs | 2 - ...-not-ignore-lifetime-bounds-in-copy.stderr | 2 +- src/test/ui/nll/enum-drop-access.rs | 2 - src/test/ui/nll/enum-drop-access.stderr | 4 +- src/test/ui/nll/get_default.polonius.stderr | 5 +- ...ue-21232-partial-init-and-erroneous-use.rs | 8 +- ...1232-partial-init-and-erroneous-use.stderr | 16 +- .../nll/issue-21232-partial-init-and-use.rs | 26 +- .../issue-21232-partial-init-and-use.stderr | 94 +- src/test/ui/nll/issue-27868.rs | 2 - src/test/ui/nll/issue-27868.stderr | 2 +- src/test/ui/nll/issue-31567.rs | 2 - src/test/ui/nll/issue-31567.stderr | 2 +- src/test/ui/nll/issue-48238.rs | 2 - src/test/ui/nll/issue-48238.stderr | 2 +- ...59-report-when-borrow-and-drop-conflict.rs | 2 - ...eport-when-borrow-and-drop-conflict.stderr | 8 +- src/test/ui/nll/issue-52742.stderr | 1 + src/test/ui/nll/issue-53040.rs | 2 - src/test/ui/nll/issue-53040.stderr | 2 +- src/test/ui/nll/issue-53773.rs | 2 - src/test/ui/nll/issue-53773.stderr | 2 +- src/test/ui/nll/issue-55288.rs | 2 +- src/test/ui/nll/issue-55394.stderr | 1 + src/test/ui/nll/issue-55401.stderr | 1 + src/test/ui/nll/issue-57100.rs | 1 - src/test/ui/nll/issue-57100.stderr | 4 +- src/test/ui/nll/issue-57960.rs | 1 - src/test/ui/nll/issue-63154-normalize.rs | 34 + .../loan_ends_mid_block_pair.polonius.stderr | 15 - src/test/ui/nll/match-cfg-fake-edges.rs | 4 +- src/test/ui/nll/match-cfg-fake-edges.stderr | 8 +- src/test/ui/nll/match-guards-always-borrow.rs | 2 - .../ui/nll/match-guards-always-borrow.stderr | 2 +- .../ui/nll/match-guards-partially-borrow.rs | 2 - .../nll/match-guards-partially-borrow.stderr | 18 +- src/test/ui/nll/match-on-borrowed.rs | 2 - src/test/ui/nll/match-on-borrowed.stderr | 12 +- .../ui/nll/normalization-bounds-error.stderr | 1 + src/test/ui/nll/normalization-bounds.rs | 2 +- .../nll/polonius/polonius-smoke-test.stderr | 4 +- .../promotable-mutable-zst-doesnt-conflict.rs | 4 +- src/test/ui/nll/promoted-liveness.rs | 8 + src/test/ui/nll/relate_tys/fn-subtype.rs | 10 + src/test/ui/nll/relate_tys/fn-subtype.stderr | 8 + src/test/ui/nll/relate_tys/trait-hrtb.rs | 16 + src/test/ui/nll/relate_tys/trait-hrtb.stderr | 8 + ...return-ref-mut-issue-46557.polonius.stderr | 15 - src/test/ui/nll/self-assign-ref-mut.rs | 20 + .../ui/nll/type-alias-free-regions.stderr | 1 + .../constant-in-expr-inherent-1.stderr | 1 + .../constant-in-expr-normalize.stderr | 1 + .../constant-in-expr-trait-item-1.stderr | 1 + .../constant-in-expr-trait-item-2.stderr | 1 + .../constant-in-expr-trait-item-3.stderr | 1 + .../ui/nll/user-annotations/issue-55219.rs | 2 +- .../nll/user-annotations/normalize-self-ty.rs | 4 +- src/test/ui/no-link.rs | 2 +- src/test/ui/no-link.stderr | 2 +- src/test/ui/no-patterns-in-args-macro.stderr | 2 +- src/test/ui/no-patterns-in-args.stderr | 3 +- src/test/ui/no-send-res-ports.rs | 2 + src/test/ui/no-send-res-ports.stderr | 12 +- src/test/ui/no_send-enum.stderr | 8 +- src/test/ui/no_send-rc.stderr | 12 +- src/test/ui/no_send-struct.stderr | 12 +- src/test/ui/no_share-enum.stderr | 8 +- src/test/ui/no_share-struct.stderr | 12 +- src/test/ui/non-copyable-void.stderr | 2 +- ...terger-atomic.rs => non-integer-atomic.rs} | 0 ...tomic.stderr => non-integer-atomic.stderr} | 32 +- src/test/ui/noncopyable-class.stderr | 2 +- src/test/ui/not-panic/not-panic-safe-2.stderr | 16 +- src/test/ui/not-panic/not-panic-safe-3.stderr | 16 +- src/test/ui/not-panic/not-panic-safe-4.stderr | 16 +- src/test/ui/not-panic/not-panic-safe-5.stderr | 8 +- src/test/ui/not-panic/not-panic-safe-6.stderr | 16 +- src/test/ui/not-panic/not-panic-safe.stderr | 9 +- src/test/ui/not-sync.stderr | 72 +- src/test/ui/object-does-not-impl-trait.stderr | 12 +- ...lifetime-default-dyn-binding-nonstatic1.rs | 27 + ...time-default-dyn-binding-nonstatic1.stderr | 8 + ...lifetime-default-dyn-binding-nonstatic2.rs | 30 + ...time-default-dyn-binding-nonstatic2.stderr | 8 + ...lifetime-default-dyn-binding-nonstatic3.rs | 23 + ...time-default-dyn-binding-nonstatic3.stderr | 8 + ...ect-lifetime-default-dyn-binding-static.rs | 28 + .../object-lifetime-default-elision.stderr | 1 + src/test/ui/object-pointer-types.stderr | 6 +- .../object-safety-associated-consts.stderr | 5 +- .../object-safety-generics.stderr | 10 +- .../object-safety-mentions-Self.stderr | 10 +- .../object-safety-no-static.stderr | 5 +- src/test/ui/obsolete-in-place/bad.rs | 2 +- src/test/ui/obsolete-in-place/bad.stderr | 8 +- src/test/ui/occurs-check-2.stderr | 2 +- src/test/ui/occurs-check.stderr | 2 +- .../ui/on-unimplemented/multiple-impls.stderr | 58 +- src/test/ui/on-unimplemented/on-impl.stderr | 14 +- src/test/ui/on-unimplemented/on-trait.stderr | 16 +- src/test/ui/or-patterns/already-bound-name.rs | 46 + .../ui/or-patterns/already-bound-name.stderr | 105 + .../ui/or-patterns/consistent-bindings.rs | 46 + .../ui/or-patterns/consistent-bindings.stderr | 20 + .../feature-gate-or_patterns-leading-for.rs | 8 + ...eature-gate-or_patterns-leading-for.stderr | 12 + .../feature-gate-or_patterns-leading-let.rs | 8 + ...eature-gate-or_patterns-leading-let.stderr | 12 + .../or-patterns/feature-gate-or_patterns.rs | 52 + .../feature-gate-or_patterns.stderr | 174 + .../ui/or-patterns/fn-param-wrap-parens.fixed | 14 + .../ui/or-patterns/fn-param-wrap-parens.rs | 14 + .../or-patterns/fn-param-wrap-parens.stderr | 8 + src/test/ui/or-patterns/inconsistent-modes.rs | 28 + .../ui/or-patterns/inconsistent-modes.stderr | 80 + .../issue-64879-trailing-before-guard.rs | 15 + .../issue-64879-trailing-before-guard.stderr | 20 + src/test/ui/or-patterns/missing-bindings.rs | 84 + .../ui/or-patterns/missing-bindings.stderr | 250 + .../ui/or-patterns/multiple-pattern-typo.rs | 45 + .../or-patterns/multiple-pattern-typo.stderr | 64 + .../{ => or-patterns}/or-pattern-mismatch.rs | 0 .../or-pattern-mismatch.stderr | 0 .../or-patterns/or-patterns-syntactic-fail.rs | 53 + .../or-patterns-syntactic-fail.stderr | 132 + .../or-patterns/or-patterns-syntactic-pass.rs | 78 + .../or-patterns-syntactic-pass.stderr | 8 + .../ui/or-patterns/remove-leading-vert.fixed | 46 + .../ui/or-patterns/remove-leading-vert.rs | 46 + .../ui/or-patterns/remove-leading-vert.stderr | 200 + .../while-parsing-this-or-pattern.rs | 9 + .../while-parsing-this-or-pattern.stderr | 10 + src/test/ui/overlap-marker-trait.stderr | 13 +- .../ui/panic-handler/panic-handler-std.stderr | 2 +- src/test/ui/panic-runtime/libtest-unwinds.rs | 10 - .../ui/panic-runtime/libtest-unwinds.stderr | 4 - .../panic-runtime/transitive-link-a-bunch.rs | 3 +- .../ui/panic-runtime/want-unwind-got-abort.rs | 3 +- .../panic-runtime/want-unwind-got-abort2.rs | 3 +- src/test/ui/panic-uninitialized-zeroed.rs | 2 +- src/test/ui/parser-recovery-1.rs | 1 + src/test/ui/parser-recovery-1.stderr | 19 +- src/test/ui/parser/assoc-type-in-type-arg.rs | 11 + .../ui/parser/assoc-type-in-type-arg.stderr | 8 + src/test/ui/parser/bad-match.rs | 2 +- src/test/ui/parser/bad-match.stderr | 4 +- src/test/ui/parser/bad-name.stderr | 4 +- src/test/ui/parser/do-catch-suggests-try.rs | 2 +- .../ui/parser/do-catch-suggests-try.stderr | 2 +- src/test/ui/parser/doc-before-semi.rs | 2 + src/test/ui/parser/doc-before-semi.stderr | 8 + src/test/ui/parser/fn-arg-doc-comment.rs | 4 - src/test/ui/parser/fn-arg-doc-comment.stderr | 33 +- src/test/ui/parser/inverted-parameters.rs | 12 +- src/test/ui/parser/inverted-parameters.stderr | 24 +- src/test/ui/parser/issue-22647.rs | 2 +- src/test/ui/parser/issue-22647.stderr | 4 +- src/test/ui/parser/issue-22712.rs | 2 +- src/test/ui/parser/issue-22712.stderr | 4 +- src/test/ui/parser/issue-2354.rs | 5 +- src/test/ui/parser/issue-2354.stderr | 20 +- src/test/ui/parser/issue-24197.rs | 2 +- src/test/ui/parser/issue-24197.stderr | 4 +- src/test/ui/parser/issue-32501.rs | 3 +- src/test/ui/parser/issue-32501.stderr | 8 +- src/test/ui/parser/issue-33413.rs | 3 +- src/test/ui/parser/issue-33413.stderr | 18 +- src/test/ui/parser/issue-62881.stderr | 2 +- src/test/ui/parser/issue-62895.stderr | 2 +- src/test/ui/parser/issue-63135.rs | 2 +- src/test/ui/parser/issue-63135.stderr | 12 +- .../issue-65122-mac-invoc-in-mut-patterns.rs | 26 + ...sue-65122-mac-invoc-in-mut-patterns.stderr | 45 + src/test/ui/parser/keyword-abstract.rs | 2 +- src/test/ui/parser/keyword-abstract.stderr | 8 +- .../ui/parser/keyword-as-as-identifier.rs | 2 +- .../ui/parser/keyword-as-as-identifier.stderr | 8 +- .../ui/parser/keyword-break-as-identifier.rs | 2 +- .../parser/keyword-break-as-identifier.stderr | 8 +- .../ui/parser/keyword-const-as-identifier.rs | 2 +- .../parser/keyword-const-as-identifier.stderr | 8 +- .../parser/keyword-continue-as-identifier.rs | 2 +- .../keyword-continue-as-identifier.stderr | 8 +- .../ui/parser/keyword-else-as-identifier.rs | 2 +- .../parser/keyword-else-as-identifier.stderr | 8 +- .../ui/parser/keyword-enum-as-identifier.rs | 2 +- .../parser/keyword-enum-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-final.rs | 2 +- src/test/ui/parser/keyword-final.stderr | 8 +- .../ui/parser/keyword-fn-as-identifier.rs | 2 +- .../ui/parser/keyword-fn-as-identifier.stderr | 8 +- .../ui/parser/keyword-for-as-identifier.rs | 2 +- .../parser/keyword-for-as-identifier.stderr | 8 +- .../ui/parser/keyword-if-as-identifier.rs | 2 +- .../ui/parser/keyword-if-as-identifier.stderr | 8 +- .../ui/parser/keyword-impl-as-identifier.rs | 2 +- .../parser/keyword-impl-as-identifier.stderr | 8 +- .../ui/parser/keyword-let-as-identifier.rs | 2 +- .../parser/keyword-let-as-identifier.stderr | 8 +- .../ui/parser/keyword-loop-as-identifier.rs | 2 +- .../parser/keyword-loop-as-identifier.stderr | 8 +- .../ui/parser/keyword-match-as-identifier.rs | 2 +- .../parser/keyword-match-as-identifier.stderr | 8 +- .../ui/parser/keyword-mod-as-identifier.rs | 2 +- .../parser/keyword-mod-as-identifier.stderr | 8 +- .../ui/parser/keyword-move-as-identifier.rs | 2 +- .../parser/keyword-move-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-override.rs | 2 +- src/test/ui/parser/keyword-override.stderr | 8 +- .../ui/parser/keyword-pub-as-identifier.rs | 2 +- .../parser/keyword-pub-as-identifier.stderr | 8 +- .../ui/parser/keyword-return-as-identifier.rs | 2 +- .../keyword-return-as-identifier.stderr | 8 +- .../ui/parser/keyword-static-as-identifier.rs | 2 +- .../keyword-static-as-identifier.stderr | 8 +- .../ui/parser/keyword-struct-as-identifier.rs | 2 +- .../keyword-struct-as-identifier.stderr | 8 +- .../ui/parser/keyword-trait-as-identifier.rs | 2 +- .../parser/keyword-trait-as-identifier.stderr | 8 +- .../keyword-try-as-identifier-edition2018.rs | 2 +- ...yword-try-as-identifier-edition2018.stderr | 8 +- .../ui/parser/keyword-type-as-identifier.rs | 2 +- .../parser/keyword-type-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-typeof.rs | 2 +- src/test/ui/parser/keyword-typeof.stderr | 8 +- .../ui/parser/keyword-unsafe-as-identifier.rs | 2 +- .../keyword-unsafe-as-identifier.stderr | 8 +- .../ui/parser/keyword-use-as-identifier.rs | 2 +- .../parser/keyword-use-as-identifier.stderr | 8 +- .../ui/parser/keyword-where-as-identifier.rs | 2 +- .../parser/keyword-where-as-identifier.stderr | 8 +- .../ui/parser/keyword-while-as-identifier.rs | 2 +- .../parser/keyword-while-as-identifier.stderr | 8 +- src/test/ui/parser/lex-bad-char-literals-2.rs | 2 + .../ui/parser/lex-bad-char-literals-2.stderr | 7 +- src/test/ui/parser/mut-patterns.rs | 42 +- src/test/ui/parser/mut-patterns.stderr | 101 +- .../ui/parser/no-const-fn-in-extern-block.rs | 8 + .../parser/no-const-fn-in-extern-block.stderr | 14 + src/test/ui/parser/omitted-arg-in-item-fn.rs | 2 +- .../ui/parser/omitted-arg-in-item-fn.stderr | 4 +- src/test/ui/parser/pat-lt-bracket-2.rs | 2 +- src/test/ui/parser/pat-lt-bracket-2.stderr | 10 +- src/test/ui/parser/pat-lt-bracket-5.rs | 2 +- src/test/ui/parser/pat-lt-bracket-5.stderr | 4 +- src/test/ui/parser/pat-lt-bracket-6.rs | 5 +- src/test/ui/parser/pat-lt-bracket-6.stderr | 6 +- src/test/ui/parser/pat-lt-bracket-7.rs | 3 +- src/test/ui/parser/pat-lt-bracket-7.stderr | 6 +- src/test/ui/parser/pat-ranges-1.rs | 2 +- src/test/ui/parser/pat-ranges-1.stderr | 4 +- src/test/ui/parser/pat-ranges-2.rs | 2 +- src/test/ui/parser/pat-ranges-2.stderr | 4 +- src/test/ui/parser/pat-ranges-3.rs | 2 +- src/test/ui/parser/pat-ranges-3.stderr | 4 +- src/test/ui/parser/pat-ranges-4.rs | 2 +- src/test/ui/parser/pat-ranges-4.stderr | 4 +- src/test/ui/parser/raw/raw-literal-self.rs | 2 +- .../ui/parser/raw/raw-literal-self.stderr | 2 +- .../ui/parser/raw/raw-literal-underscore.rs | 2 +- .../parser/raw/raw-literal-underscore.stderr | 2 +- .../recover-for-loop-parens-around-head.rs | 2 +- ...recover-for-loop-parens-around-head.stderr | 4 +- .../ui/parser/recover-from-bad-variant.stderr | 3 + src/test/ui/parser/removed-syntax-mode.rs | 2 +- src/test/ui/parser/removed-syntax-mode.stderr | 4 +- .../require-parens-for-chained-comparison.rs | 24 +- ...quire-parens-for-chained-comparison.stderr | 43 +- .../ui/parser/trait-object-lifetime-parens.rs | 1 - .../trait-object-lifetime-parens.stderr | 11 +- .../type-parameters-in-field-exprs.stderr | 4 +- .../parser/unclosed-delimiter-in-dep.stderr | 2 +- src/test/ui/parser/unclosed_delim_mod.rs | 2 + src/test/ui/parser/unclosed_delim_mod.stderr | 9 +- .../ui/pattern/pat-tuple-overfield.stderr | 6 + .../pattern-bindings-after-at.nll.stderr | 22 - .../ui/pattern/pattern-bindings-after-at.rs | 4 +- .../pattern/pattern-bindings-after-at.stderr | 8 +- .../ui/pattern/pattern-error-continue.stderr | 3 + .../pattern/rest-pat-semantic-disallowed.rs | 1 + .../rest-pat-semantic-disallowed.stderr | 37 +- src/test/ui/phantom-oibit.stderr | 24 +- src/test/ui/placement-syntax.rs | 2 +- src/test/ui/placement-syntax.stderr | 10 +- ...-to-type-err-cause-on-impl-trait-return.rs | 31 +- ...type-err-cause-on-impl-trait-return.stderr | 68 +- src/test/ui/privacy/privacy5.stderr | 192 + src/test/ui/privacy/union-field-privacy-2.rs | 2 +- .../ui/privacy/union-field-privacy-2.stderr | 2 +- .../proc-macro/attributes-on-definitions.rs | 12 + .../attributes-on-definitions.stderr | 8 + .../auxiliary/attr-stmt-expr-rpass.rs | 4 +- .../ui/proc-macro/auxiliary/attr-stmt-expr.rs | 4 +- .../auxiliary/attributes-on-definitions.rs | 23 + .../proc-macro/auxiliary/gen-macro-rules.rs | 12 + .../proc-macro/auxiliary/mixed-site-span.rs | 42 + .../proc-macro/auxiliary/test-macros-rpass.rs | 26 - .../ui/proc-macro/derive-helper-configured.rs | 18 + .../ui/proc-macro/derive-helper-shadowing.rs | 3 +- .../proc-macro/derive-helper-shadowing.stderr | 8 +- src/test/ui/proc-macro/derive-still-gated.rs | 2 +- .../ui/proc-macro/derive-still-gated.stderr | 2 +- .../ui/proc-macro/disappearing-resolution.rs | 22 + .../proc-macro/disappearing-resolution.stderr | 15 + .../dollar-crate-issue-57089.stdout | 32 +- .../ui/proc-macro/dollar-crate-issue-62325.rs | 2 - .../dollar-crate-issue-62325.stdout | 44 +- src/test/ui/proc-macro/dollar-crate.stdout | 96 +- src/test/ui/proc-macro/gen-macro-rules.rs | 13 + src/test/ui/proc-macro/generate-mod.stderr | 10 +- .../ui/proc-macro/invalid-punct-ident-1.rs | 6 + .../proc-macro/invalid-punct-ident-1.stderr | 2 +- .../ui/proc-macro/invalid-punct-ident-2.rs | 6 + .../proc-macro/invalid-punct-ident-2.stderr | 2 +- .../ui/proc-macro/invalid-punct-ident-3.rs | 6 + .../proc-macro/invalid-punct-ident-3.stderr | 2 +- .../proc-macro/invalid-punct-ident-4.stderr | 5 +- src/test/ui/proc-macro/lifetimes.rs | 2 - src/test/ui/proc-macro/lifetimes.stderr | 4 +- .../ui/proc-macro/lints_in_proc_macros.stderr | 5 +- .../proc-macro/macro-namespace-reserved-2.rs | 6 +- .../macro-namespace-reserved-2.stderr | 26 +- .../ui/proc-macro/macros-in-extern-derive.rs | 6 + .../proc-macro/macros-in-extern-derive.stderr | 8 + .../ui/proc-macro/macros-in-extern-rpass.rs | 25 - src/test/ui/proc-macro/macros-in-extern.rs | 6 +- .../ui/proc-macro/macros-in-extern.stderr | 30 - src/test/ui/proc-macro/macros-in-type.rs | 11 + src/test/ui/proc-macro/mixed-site-span.rs | 26 + src/test/ui/proc-macro/mixed-site-span.stderr | 49 + src/test/ui/proc-macro/multispan.stderr | 133 +- .../ui/proc-macro/proc-macro-attributes.rs | 2 +- .../proc-macro/proc-macro-attributes.stderr | 2 +- src/test/ui/proc-macro/proc-macro-gates.rs | 1 - .../ui/proc-macro/proc-macro-gates.stderr | 21 +- src/test/ui/proc-macro/proc-macro-gates2.rs | 4 +- .../ui/proc-macro/proc-macro-gates2.stderr | 11 +- src/test/ui/proc-macro/resolve-error.rs | 8 +- src/test/ui/proc-macro/resolve-error.stderr | 76 +- src/test/ui/proc-macro/span-preservation.rs | 2 +- .../ui/proc-macro/span-preservation.stderr | 2 +- src/test/ui/proc-macro/subspan.stderr | 16 +- src/test/ui/proc-macro/three-equals.stderr | 19 +- .../ui/qualified/qualified-path-params.stderr | 3 +- src/test/ui/question-mark-type-infer.rs | 2 +- src/test/ui/question-mark-type-infer.stderr | 2 +- src/test/ui/reachable/expr_add.stderr | 5 +- src/test/ui/reachable/expr_again.stderr | 4 +- src/test/ui/reachable/expr_array.stderr | 9 +- src/test/ui/reachable/expr_assign.stderr | 13 +- src/test/ui/reachable/expr_block.stderr | 8 +- src/test/ui/reachable/expr_box.stderr | 5 +- src/test/ui/reachable/expr_call.stderr | 10 +- src/test/ui/reachable/expr_cast.stderr | 5 +- src/test/ui/reachable/expr_if.stderr | 11 +- src/test/ui/reachable/expr_loop.stderr | 12 +- src/test/ui/reachable/expr_match.stderr | 8 +- src/test/ui/reachable/expr_method.stderr | 12 +- src/test/ui/reachable/expr_repeat.stderr | 5 +- src/test/ui/reachable/expr_return.stderr | 5 +- src/test/ui/reachable/expr_return_in_macro.rs | 15 + .../ui/reachable/expr_return_in_macro.stderr | 17 + src/test/ui/reachable/expr_struct.stderr | 18 +- src/test/ui/reachable/expr_tup.stderr | 9 +- src/test/ui/reachable/expr_type.stderr | 5 +- src/test/ui/reachable/expr_unary.stderr | 5 +- src/test/ui/reachable/expr_while.stderr | 12 +- src/test/ui/recursion/recursive-reexports.rs | 2 +- .../ui/recursion/recursive-reexports.stderr | 2 +- .../recursion/recursive-requirements.stderr | 16 +- .../recursive-types-are-not-uninhabited.rs | 2 +- ...recursive-types-are-not-uninhabited.stderr | 4 +- src/test/ui/refutable-pattern-errors.rs | 4 +- src/test/ui/refutable-pattern-errors.stderr | 8 +- ...unds-on-objects-and-type-parameters.stderr | 2 +- .../regions/region-object-lifetime-2.stderr | 1 + .../regions/region-object-lifetime-4.stderr | 1 + .../region-object-lifetime-in-coercion.stderr | 3 +- .../ui/regions/regions-addr-of-self.stderr | 1 + .../regions/regions-addr-of-upvar-self.stderr | 1 + ...rait-outlives-container.migrate.nll.stderr | 2 +- ...pertrait-outlives-container.migrate.stderr | 10 +- ...n-supertrait-outlives-container.nll.stderr | 2 +- ...c-type-in-supertrait-outlives-container.rs | 4 - ...-type-region-bound-in-trait-not-met.stderr | 1 + ...-type-static-bound-in-trait-not-met.stderr | 1 + .../regions-close-object-into-object-2.stderr | 1 + .../regions-close-object-into-object-4.stderr | 1 + .../regions-close-object-into-object-5.stderr | 12 +- ...-close-over-type-parameter-multiple.stderr | 1 + .../ui/regions/regions-creating-enums4.stderr | 1 + .../regions-early-bound-error-method.stderr | 1 + .../regions/regions-early-bound-error.stderr | 1 + .../ui/regions/regions-escape-method.stderr | 1 + .../regions-escape-via-trait-or-not.stderr | 1 + ...ions-free-region-ordering-incorrect.stderr | 1 + .../ui/regions/regions-infer-call-3.stderr | 1 + .../ui/regions/regions-name-undeclared.stderr | 8 +- src/test/ui/regions/regions-nested-fns.stderr | 2 + ...ions-normalize-in-where-clause-list.stderr | 1 + ...ojection-container-hrtb.migrate.nll.stderr | 4 +- ...s-projection-container-hrtb.migrate.stderr | 20 +- ...lives-projection-container-hrtb.nll.stderr | 4 +- ...ions-outlives-projection-container-hrtb.rs | 7 - ...projection-container-wc.migrate.nll.stderr | 2 +- ...ves-projection-container-wc.migrate.stderr | 10 +- ...utlives-projection-container-wc.nll.stderr | 2 +- ...egions-outlives-projection-container-wc.rs | 4 - ...s-outlives-projection-container.nll.stderr | 8 +- .../regions-outlives-projection-container.rs | 4 - ...gions-outlives-projection-container.stderr | 40 +- .../ui/regions/regions-ret-borrowed-1.stderr | 1 + .../ui/regions/regions-ret-borrowed.stderr | 1 + ...ons-return-ref-to-upvar-issue-17403.stderr | 1 + .../regions-static-bound.migrate.stderr | 3 +- .../regions-trait-object-subtyping.stderr | 2 +- src/test/ui/reify-intrinsic.rs | 15 + src/test/ui/reify-intrinsic.stderr | 22 + .../ui/reject-specialized-drops-8142.stderr | 2 +- .../ui/reserved/reserved-attr-on-macro.rs | 2 +- .../ui/reserved/reserved-attr-on-macro.stderr | 12 +- src/test/ui/reserved/reserved-become.rs | 2 +- src/test/ui/reserved/reserved-become.stderr | 8 +- .../ui/resolve/block-with-trait-parent.rs | 14 + .../ui/resolve/enums-are-namespaced-xc.stderr | 6 +- src/test/ui/resolve/issue-18252.stderr | 3 + src/test/ui/resolve/issue-19452.stderr | 3 + src/test/ui/resolve/issue-3907-2.stderr | 2 +- src/test/ui/resolve/issue-39226.stderr | 3 + ...sue-65025-extern-static-parent-generics.rs | 10 + ...65025-extern-static-parent-generics.stderr | 12 + ...issue-65035-static-with-parent-generics.rs | 29 + ...e-65035-static-with-parent-generics.stderr | 53 + src/test/ui/resolve/issue-6702.stderr | 9 +- src/test/ui/resolve/privacy-enum-ctor.stderr | 60 +- .../ui/resolve/privacy-struct-ctor.stderr | 31 +- .../resolve/resolve-assoc-suggestions.stderr | 2 +- src/test/ui/resolve/resolve-bad-visibility.rs | 4 +- .../ui/resolve/resolve-bad-visibility.stderr | 21 +- .../ui/resolve/resolve-inconsistent-names.rs | 31 +- .../resolve/resolve-inconsistent-names.stderr | 87 +- .../ui/resolve/visibility-indeterminate.rs | 7 + .../resolve/visibility-indeterminate.stderr | 14 + .../bind-by-move-no-guards.rs | 6 +- .../feature-gate.gate_and_2015.stderr | 10 - .../feature-gate.gate_and_2018.stderr | 10 - .../feature-gate.gate_and_feature_nll.stderr | 10 - .../feature-gate.gate_and_znll.stderr | 10 - .../feature-gate.no_gate.stderr | 11 - .../feature-gate.rs | 40 - .../former-E0008-now-pass.rs | 11 + .../rfc-basic-examples.rs | 2 - .../rfc-reject-double-move-across-arms.rs | 2 - .../rfc-reject-double-move-across-arms.stderr | 2 +- .../rfc-reject-double-move-in-first-arm.rs | 2 - ...rfc-reject-double-move-in-first-arm.stderr | 2 +- .../termination-trait-test-wrong-type.rs | 2 + .../termination-trait-test-wrong-type.stderr | 8 +- .../improper_ctypes/auxiliary/types.rs | 31 + .../improper_ctypes/extern_crate_improper.rs | 24 + .../extern_crate_improper.stderr | 47 + .../improper_ctypes/same_crate_proper.rs | 46 + .../ui/rfc-2008-non-exhaustive/struct.stderr | 5 + .../variants_same_crate.rs | 6 +- .../rfc-2091-track-caller/error-odd-syntax.rs | 7 + .../error-odd-syntax.stderr | 16 + .../error-with-invalid-abi.rs | 7 + .../error-with-invalid-abi.stderr | 17 + .../rfc-2091-track-caller/error-with-naked.rs | 8 + .../error-with-naked.stderr | 17 + .../error-with-trait-decl.rs | 13 + .../error-with-trait-decl.stderr | 17 + .../error-with-trait-default-impl.rs | 9 + .../error-with-trait-default-impl.stderr | 17 + .../error-with-trait-fn-impl.rs | 13 + .../error-with-trait-fn-impl.stderr | 17 + .../ui/rfc-2091-track-caller/only-for-fns.rs | 7 + .../rfc-2091-track-caller/only-for-fns.stderr | 18 + src/test/ui/rfc-2091-track-caller/pass.rs | 9 + src/test/ui/rfc-2091-track-caller/pass.stderr | 8 + .../single-segment.rs | 2 +- .../single-segment.stderr | 2 +- .../dbg-macro-expected-behavior.rs | 84 +- .../dbg-macro-expected-behavior.run.stderr | 28 + .../disallowed-positions.stderr | 10 +- .../protect-precedences.rs | 2 - .../protect-precedences.stderr | 10 + .../attr-without-param.rs | 16 + .../attr-without-param.stderr | 20 + .../auxiliary/ident-mac.rs | 11 + .../auxiliary/param-attrs.rs | 12 +- ...-64682-dropping-first-attrs-in-impl-fns.rs | 21 + .../rfc-2565-param-attrs/param-attrs-2018.rs | 4 +- .../param-attrs-2018.stderr | 10 +- .../param-attrs-allowed.rs | 1 - .../param-attrs-builtin-attrs.rs | 49 +- .../param-attrs-builtin-attrs.stderr | 261 +- .../rfc-2565-param-attrs/param-attrs-cfg.rs | 26 +- .../param-attrs-cfg.stderr | 52 +- .../param-attrs-feature-gate.rs | 16 - .../param-attrs-feature-gate.stderr | 27 - .../param-attrs-pretty.rs | 7 +- .../proc-macro-cannot-be-used.rs | 65 + .../proc-macro-cannot-be-used.stderr | 176 + .../feature-gate-raw-dylib-2.rs | 8 + .../feature-gate-raw-dylib-2.stderr | 12 + .../feature-gate-raw-dylib.rs | 5 + .../feature-gate-raw-dylib.stderr | 12 + .../link-ordinal-and-name.rs | 12 + .../link-ordinal-and-name.stderr | 16 + .../link-ordinal-invalid-format.rs | 11 + .../link-ordinal-invalid-format.stderr | 18 + .../link-ordinal-too-large.rs | 11 + .../link-ordinal-too-large.stderr | 18 + .../fn-ptr-is-structurally-matchable.rs | 135 + .../ui/rfc1445/issue-63479-match-fnptr.rs | 36 + .../shadowing.rs | 16 +- .../shadowing.stderr | 21 +- .../rust-2018/trait-import-suggestions.stderr | 12 +- src/test/ui/rust-2018/try-macro.fixed | 1 + src/test/ui/rust-2018/try-macro.rs | 1 + src/test/ui/rust-2018/try-macro.stderr | 2 +- .../ambiguity-macros-nested.stderr | 4 +- .../uniform-paths/ambiguity-macros.stderr | 4 +- .../uniform-paths/ambiguity-nested.stderr | 4 +- .../rust-2018/uniform-paths/ambiguity.stderr | 4 +- .../ui/rust-2018/uniform-paths/deadlock.rs | 2 +- .../rust-2018/uniform-paths/deadlock.stderr | 6 +- .../uniform-paths/issue-56596.stderr | 4 +- src/test/ui/rust-unstable-column-gated.rs | 4 - src/test/ui/rust-unstable-column-gated.stderr | 11 - src/test/ui/save-analysis/issue-63663.rs | 28 + ...rbitrary-self-types-not-object-safe.stderr | 9 +- ...arbitrary_self_types_pin_lifetime-async.rs | 35 + ...s_pin_lifetime_impl_trait-async.nll.stderr | 14 + ...elf_types_pin_lifetime_impl_trait-async.rs | 14 + ...types_pin_lifetime_impl_trait-async.stderr | 20 + ...pes_pin_lifetime_mismatch-async.nll.stderr | 45 + ..._self_types_pin_lifetime_mismatch-async.rs | 20 + ...f_types_pin_lifetime_mismatch-async.stderr | 26 + src/test/ui/self/elision/README.md | 31 + src/test/ui/self/elision/alias-async.rs | 37 + src/test/ui/self/elision/assoc-async.rs | 41 + src/test/ui/self/elision/lt-alias-async.rs | 39 + src/test/ui/self/elision/lt-assoc-async.rs | 51 + .../self/elision/lt-ref-self-async.nll.stderr | 117 + src/test/ui/self/elision/lt-ref-self-async.rs | 40 + .../ui/self/elision/lt-ref-self-async.stderr | 62 + src/test/ui/self/elision/lt-self-async.rs | 50 + src/test/ui/self/elision/lt-struct-async.rs | 37 + .../self/elision/multiple-ref-self-async.rs | 44 + src/test/ui/self/elision/ref-alias-async.rs | 40 + src/test/ui/self/elision/ref-assoc-async.rs | 41 + .../ui/self/elision/ref-mut-alias-async.rs | 37 + .../elision/ref-mut-self-async.nll.stderr | 117 + .../ui/self/elision/ref-mut-self-async.rs | 40 + .../ui/self/elision/ref-mut-self-async.stderr | 62 + .../elision/ref-mut-struct-async.nll.stderr | 98 + .../ui/self/elision/ref-mut-struct-async.rs | 34 + .../self/elision/ref-mut-struct-async.stderr | 52 + .../ui/self/elision/ref-self-async.nll.stderr | 136 + src/test/ui/self/elision/ref-self-async.rs | 53 + .../ui/self/elision/ref-self-async.stderr | 72 + .../self/elision/ref-struct-async.nll.stderr | 98 + src/test/ui/self/elision/ref-struct-async.rs | 34 + .../ui/self/elision/ref-struct-async.stderr | 52 + src/test/ui/self/elision/self-async.rs | 37 + src/test/ui/self/elision/struct-async.rs | 33 + .../point-at-arbitrary-self-type-method.rs | 9 + ...point-at-arbitrary-self-type-method.stderr | 15 + ...int-at-arbitrary-self-type-trait-method.rs | 10 + ...at-arbitrary-self-type-trait-method.stderr | 18 + src/test/ui/self/self_lifetime-async.rs | 14 + src/test/ui/self/self_type_keyword-2.stderr | 3 +- src/test/ui/self/self_type_keyword.rs | 5 +- src/test/ui/self/self_type_keyword.stderr | 39 +- .../ui/shadowed/shadowed-trait-methods.stderr | 4 +- .../ui/shadowed/shadowed-type-parameter.rs | 6 +- .../shadowed/shadowed-type-parameter.stderr | 30 +- .../shadowing-in-the-same-pattern.stderr | 7 +- src/test/ui/span/E0493.stderr | 1 + src/test/ui/span/coerce-suggestions.stderr | 2 +- src/test/ui/span/issue-27522.rs | 2 +- src/test/ui/span/issue-27522.stderr | 5 +- src/test/ui/span/issue-29595.stderr | 9 +- src/test/ui/span/issue-34264.stderr | 18 +- .../issue-42234-unknown-receiver-type.stderr | 4 +- .../ui/span/type-annotations-needed-expr.rs | 3 + .../span/type-annotations-needed-expr.stderr | 11 + src/test/ui/span/visibility-ty-params.stderr | 14 +- .../auxiliary/cross_crates_defaults.rs | 4 +- .../defaultimpl/specialization-no-default.rs | 8 - .../specialization-no-default.stderr | 10 +- ...pecialization-trait-not-implemented.stderr | 2 +- src/test/ui/specialization/issue-36804.rs | 35 + src/test/ui/specialization/issue-52050.stderr | 2 +- .../specialization/issue-63716-parse-async.rs | 14 + .../specialization/non-defaulted-item-fail.rs | 53 + .../non-defaulted-item-fail.stderr | 81 + .../specialization-default-methods.rs | 5 +- .../specialization-default-projection.stderr | 4 + .../specialization-default-types.stderr | 4 + .../specialization-no-default.rs | 8 - .../specialization-no-default.stderr | 10 +- ...attribute-non-staged-force-unstable.stderr | 7 +- .../stability-attribute-non-staged.stderr | 7 +- .../stability-attribute-sanity.rs | 4 + .../stability-attribute-sanity.stderr | 22 +- src/test/ui/static/static-drop-scope.stderr | 3 +- src/test/ui/std-backtrace.rs | 75 + src/test/ui/str/str-idx.stderr | 8 +- src/test/ui/str/str-mut-idx.stderr | 16 +- .../ui/struct-literal-variant-in-if.stderr | 8 +- .../structs/struct-pat-derived-error.stderr | 2 +- .../structs/struct-path-alias-bounds.stderr | 9 +- .../struct-path-self-type-mismatch.stderr | 4 + src/test/ui/structs/struct-path-self.rs | 6 +- src/test/ui/structs/struct-path-self.stderr | 6 +- src/test/ui/substs-ppaux.normal.stderr | 40 +- src/test/ui/substs-ppaux.verbose.stderr | 40 +- ...as-arg-where-it-should-have-been-called.rs | 10 + ...rg-where-it-should-have-been-called.stderr | 15 + src/test/ui/suggestions/attribute-typos.rs | 6 +- .../ui/suggestions/attribute-typos.stderr | 6 +- src/test/ui/suggestions/const-no-type.rs | 46 + src/test/ui/suggestions/const-no-type.stderr | 38 + .../const-pat-non-exaustive-let-new-var.rs | 10 + ...const-pat-non-exaustive-let-new-var.stderr | 15 + .../dont-suggest-ref/duplicate-suggestions.rs | 2 +- .../dont-suggest-ref/move-into-closure.rs | 4 +- .../ui/suggestions/dont-suggest-ref/simple.rs | 8 +- .../dont-suggest-try_into-in-macros.rs | 3 + .../dont-suggest-try_into-in-macros.stderr | 11 + ...as-arg-where-it-should-have-been-called.rs | 18 + ...rg-where-it-should-have-been-called.stderr | 15 + ...fn-or-tuple-struct-with-underscore-args.rs | 19 + ...r-tuple-struct-with-underscore-args.stderr | 38 + .../fn-or-tuple-struct-without-args.rs | 47 + .../fn-or-tuple-struct-without-args.stderr | 237 + .../imm-ref-trait-object-literal.rs | 14 + .../imm-ref-trait-object-literal.stderr | 30 + .../ui/suggestions/imm-ref-trait-object.rs | 8 + .../suggestions/imm-ref-trait-object.stderr | 10 + ...ait-with-missing-trait-bounds-in-arg.fixed | 20 + ...-trait-with-missing-trait-bounds-in-arg.rs | 20 + ...it-with-missing-trait-bounds-in-arg.stderr | 15 + src/test/ui/suggestions/into-str.stderr | 9 +- src/test/ui/suggestions/issue-21673.stderr | 4 +- src/test/ui/suggestions/issue-61226.rs | 5 + src/test/ui/suggestions/issue-61226.stderr | 12 + src/test/ui/suggestions/issue-62843.stderr | 4 +- .../ui/suggestions/issue-64252-self-type.rs | 14 + .../suggestions/issue-64252-self-type.stderr | 30 + .../ui/suggestions/match-needing-semi.fixed | 18 + src/test/ui/suggestions/match-needing-semi.rs | 18 + .../ui/suggestions/match-needing-semi.stderr | 36 + .../mismatched-types-numeric-from.rs | 3 + .../mismatched-types-numeric-from.stderr | 9 + .../suggestions/mut-borrow-needed-by-trait.rs | 23 + .../mut-borrow-needed-by-trait.stderr | 41 + src/test/ui/suggestions/opaque-type-error.rs | 24 + .../ui/suggestions/opaque-type-error.stderr | 20 + src/test/ui/suggestions/remove-as_str.rs | 21 + src/test/ui/suggestions/remove-as_str.stderr | 27 + ...oc-fn-call-with-turbofish-through-deref.rs | 13 + ...n-call-with-turbofish-through-deref.stderr | 19 + .../suggest-assoc-fn-call-with-turbofish.rs | 11 + ...uggest-assoc-fn-call-with-turbofish.stderr | 22 + src/test/ui/suggestions/suggest-box.fixed | 8 + src/test/ui/suggestions/suggest-box.rs | 8 + src/test/ui/suggestions/suggest-box.stderr | 24 + .../suggest-closure-return-type-1.rs | 3 + .../suggest-closure-return-type-1.stderr | 13 + .../suggest-closure-return-type-2.rs | 3 + .../suggest-closure-return-type-2.stderr | 13 + .../suggest-closure-return-type-3.rs | 3 + .../suggest-closure-return-type-3.stderr | 13 + .../ui/suggestions/suggest-methods.stderr | 2 +- .../type-ascription-instead-of-path.rs | 2 +- .../type-ascription-instead-of-path.stderr | 2 +- .../ui/suggestions/vec-macro-in-pattern.fixed | 8 + .../ui/suggestions/vec-macro-in-pattern.rs | 8 + .../suggestions/vec-macro-in-pattern.stderr | 15 + src/test/ui/symbol-names/impl1.legacy.stderr | 16 +- src/test/ui/symbol-names/impl1.rs | 20 +- src/test/ui/symbol-names/impl1.v0.stderr | 16 +- .../ui/symbol-names/issue-60925.legacy.stderr | 4 +- src/test/ui/symbol-names/issue-60925.rs | 4 +- src/test/ui/syntax-extension-minor.rs | 6 +- src/test/ui/syntax-extension-minor.stderr | 9 - src/test/ui/target-feature-wrong.stderr | 50 - .../gate.rs} | 0 .../gate.stderr} | 2 +- .../invalid-attribute.rs} | 25 + .../target-feature/invalid-attribute.stderr | 95 + .../non-whitespace-trimming-2.rs | 6 + .../non-whitespace-trimming-2.stderr | 12 + .../non-whitespace-trimming-unicode.rs | 6 + .../non-whitespace-trimming-unicode.stderr | 12 + .../terminal-width/non-whitespace-trimming.rs | 6 + .../non-whitespace-trimming.stderr | 12 + .../terminal-width/whitespace-trimming-2.rs | 8 + .../whitespace-trimming-2.stderr | 14 + .../ui/terminal-width/whitespace-trimming.rs | 6 + .../terminal-width/whitespace-trimming.stderr | 12 + .../auxiliary/test_macro.rs | 0 src/test/ui/test-attrs/decl-macro-test.rs | 22 + .../inaccessible-test-modules.rs | 4 +- .../inaccessible-test-modules.stderr | 21 + .../{ => test-attrs}/test-allow-fail-attr.rs | 0 .../test-attr-non-associated-functions.rs | 0 .../test-attr-non-associated-functions.stderr | 0 .../test-cant-be-shadowed.rs | 0 ...e-verification-for-explicit-return-type.rs | 0 .../test-main-not-dead-attr.rs | 0 .../ui/{ => test-attrs}/test-main-not-dead.rs | 0 src/test/ui/{ => test-attrs}/test-on-macro.rs | 0 .../ui/{ => test-attrs}/test-on-macro.stderr | 0 .../test-runner-hides-buried-main.rs | 0 .../test-runner-hides-main.rs | 0 .../test-runner-hides-start.rs | 0 .../test-should-fail-good-message.rs | 0 .../test-should-panic-attr.rs | 0 .../test-should-panic-attr.stderr | 0 .../ui/{ => test-attrs}/test-vs-cfg-test.rs | 0 .../{ => test-attrs}/test-warns-dead-code.rs | 0 .../test-warns-dead-code.stderr | 0 src/test/ui/test-panic-abort-disabled.rs | 20 + src/test/ui/test-panic-abort-disabled.stderr | 4 + src/test/ui/test-panic-abort.rs | 37 + src/test/ui/test-panic-abort.run.stdout | 29 + src/test/ui/thread-local-in-ctfe.nll.stderr | 49 - src/test/ui/thread-local-in-ctfe.rs | 8 +- src/test/ui/thread-local-in-ctfe.stderr | 22 +- .../ui/tool-attributes/diagnostic_item.rs | 3 + .../ui/tool-attributes/diagnostic_item.stderr | 12 + .../ui/tool-attributes/diagnostic_item2.rs | 6 + .../ui/tool-attributes/diagnostic_item3.rs | 7 + .../tool-attributes-misplaced-1.rs | 6 +- .../tool-attributes-misplaced-1.stderr | 4 +- .../reservation-impl-coherence-conflict.rs | 16 + ...reservation-impl-coherence-conflict.stderr | 13 + .../reservation-impl-no-use.rs | 14 + .../reservation-impl-no-use.stderr | 15 + .../reservation-impl-non-lattice-ok.rs | 59 + .../reservation-impls/reservation-impl-ok.rs | 28 + .../trait-alias-cross-crate.stderr | 24 +- .../trait-alias/trait-alias-object-wf.rs | 2 +- .../traits/trait-alias/trait-alias-wf.stderr | 7 +- ...-bounds-on-structs-and-enums-in-fns.stderr | 18 +- ...ounds-on-structs-and-enums-in-impls.stderr | 9 +- ...-bounds-on-structs-and-enums-locals.stderr | 18 +- ...-bounds-on-structs-and-enums-static.stderr | 9 +- .../trait-bounds-on-structs-and-enums.stderr | 60 +- src/test/ui/traits/trait-impl-1.stderr | 2 +- ...trait-has-wrong-lifetime-parameters.stderr | 1 + src/test/ui/traits/trait-item-privacy.stderr | 30 +- .../ui/traits/trait-method-private.stderr | 2 +- src/test/ui/traits/trait-object-safety.stderr | 9 +- .../trait-static-method-generic-inference.rs | 2 +- ...ait-static-method-generic-inference.stderr | 11 +- .../ui/traits/trait-suggest-where-clause.rs | 2 + .../traits/trait-suggest-where-clause.stderr | 42 +- src/test/ui/traits/trait-test-2.stderr | 15 +- .../ui/traits/traits-conditional-model-fn.rs | 7 - ...its-inductive-overflow-simultaneous.stderr | 8 +- ...inductive-overflow-supertrait-oibit.stderr | 15 +- ...raits-inductive-overflow-supertrait.stderr | 8 +- ...raits-inductive-overflow-two-traits.stderr | 9 +- .../ui/traits/traits-negative-impls.stderr | 80 +- .../traits-repeated-supertrait-ambig.stderr | 17 +- .../trivial-bounds/trivial-bounds-leak.stderr | 26 +- src/test/ui/try-block/try-block-opt-init.rs | 2 +- .../ui/try-block/try-block-opt-init.stderr | 4 +- .../try-block-unreachable-code-lint.rs | 76 + .../try-block-unreachable-code-lint.stderr | 38 + src/test/ui/try-operator-on-main.rs | 2 +- src/test/ui/try-operator-on-main.stderr | 11 +- .../enum-variant-generic-args-pass.rs | 16 +- .../enum-variant-generic-args.stderr | 12 + ...riant-form-through-Self-issue-58006.stderr | 1 + ...t-variant-form-through-alias-caught.stderr | 2 +- .../auxiliary/foreign-crate.rs | 2 + .../ui/type-alias-impl-trait/coherence.rs | 17 + .../ui/type-alias-impl-trait/coherence.stderr | 9 + .../ui/type-alias-impl-trait/issue-53598.rs | 28 + .../type-alias-impl-trait/issue-53598.stderr | 12 + .../ui/type-alias-impl-trait/issue-57700.rs | 22 + .../type-alias-impl-trait/issue-57700.stderr | 12 + .../ui/type-alias-impl-trait/issue-60564.rs | 2 + .../type-alias-impl-trait/issue-60564.stderr | 7 +- .../issue-63677-type-alias-coherence.rs | 21 + src/test/ui/type/ascription/issue-34255-1.rs | 1 + .../ui/type/ascription/issue-34255-1.stderr | 12 +- .../ui/type/ascription/issue-47666.stderr | 1 + src/test/ui/type/ascription/issue-54516.rs | 2 +- .../ui/type/ascription/issue-54516.stderr | 4 +- src/test/ui/type/type-annotation-needed.rs | 3 +- .../ui/type/type-annotation-needed.stderr | 13 +- src/test/ui/type/type-check-defaults.stderr | 73 +- src/test/ui/type/type-check/issue-40294.rs | 2 +- .../ui/type/type-check/issue-40294.stderr | 11 +- ...ter-defaults-referencing-Self-ppaux.stderr | 5 +- src/test/ui/type/type-parameter-names.stderr | 2 + .../type/type-params-in-different-spaces-1.rs | 2 +- .../type-params-in-different-spaces-1.stderr | 4 +- .../type-params-in-different-spaces-2.stderr | 16 +- .../type-params-in-different-spaces-3.stderr | 4 +- src/test/ui/type/type-path-err-node-types.rs | 2 +- .../ui/type/type-path-err-node-types.stderr | 12 +- ...-52082-type-param-shadows-existing-type.rs | 54 + ...82-type-param-shadows-existing-type.stderr | 75 + .../typeck-auto-trait-no-supertraits-2.stderr | 1 + .../typeck-auto-trait-no-supertraits.stderr | 1 + ...ypeck-default-trait-impl-assoc-type.stderr | 8 +- ...ault-trait-impl-constituent-types-2.stderr | 8 +- ...efault-trait-impl-constituent-types.stderr | 12 +- ...ck-default-trait-impl-negation-send.stderr | 12 +- ...ck-default-trait-impl-negation-sync.stderr | 28 +- .../typeck-default-trait-impl-negation.stderr | 24 +- ...ypeck-default-trait-impl-precedence.stderr | 8 +- ...ypeck-default-trait-impl-send-param.stderr | 12 +- .../typeck/typeck-unsafe-always-share.stderr | 44 +- src/test/ui/typeid-intrinsic.rs | 18 +- src/test/ui/ufcs/ufcs-explicit-self-bad.rs | 14 +- .../ui/ufcs/ufcs-explicit-self-bad.stderr | 23 +- .../unboxed-closure-sugar-default.stderr | 9 +- .../unboxed-closure-sugar-equiv.stderr | 9 +- ...oxed-closure-sugar-used-on-struct-1.stderr | 4 +- ...oxed-closure-sugar-used-on-struct-3.stderr | 10 +- ...nboxed-closure-sugar-used-on-struct.stderr | 4 +- ...ong-number-number-type-parameters-1.stderr | 4 +- ...ong-number-number-type-parameters-3.stderr | 4 +- ...wrong-number-number-type-parameters.stderr | 8 +- .../unboxed-closure-sugar-wrong-trait.stderr | 4 +- ...ures-failed-recursive-fn-1.polonius.stderr | 60 - .../unboxed-closures-fnmut-as-fn.stderr | 12 +- ...-argument-types-two-region-pointers.stderr | 1 + ...ed-closures-static-call-wrong-trait.stderr | 2 +- .../unboxed-closures-unsafe-extern-fn.stderr | 60 +- .../unboxed-closures-wrong-abi.stderr | 60 +- ...d-closures-wrong-arg-type-extern-fn.stderr | 60 +- .../auxiliary/duplicate.rs | 0 .../auxiliary/underscore-imports.rs | 0 .../basic.rs | 0 .../basic.stderr | 0 src/test/ui/underscore-imports/cycle.rs | 18 + .../duplicate.rs | 0 .../intercrate.rs | 0 src/test/ui/underscore-imports/shadow.rs | 23 + src/test/ui/underscore-imports/shadow.stderr | 13 + .../unused-2018.rs | 0 .../unused-2018.stderr | 0 .../dyn-trait-underscore.stderr | 1 + .../unevaluated_fixed_size_array_len.stderr | 8 +- .../uninhabited-irrefutable.stderr | 1 + src/test/ui/union/union-derive-clone.stderr | 2 +- src/test/ui/union/union-generic.stderr | 18 +- src/test/ui/union/union-repr-c.rs | 2 +- src/test/ui/union/union-repr-c.stderr | 5 +- src/test/ui/unique-object-noncopyable.stderr | 2 +- src/test/ui/unique-pinned-nocopy.stderr | 2 +- .../ui/unreachable/unreachable-code.stderr | 5 +- .../ui/unreachable/unreachable-in-call.rs | 2 +- .../ui/unreachable/unreachable-in-call.stderr | 15 +- .../unreachable-try-pattern.stderr | 5 +- .../unwarned-match-on-never.stderr | 13 +- .../ui/unsized/unsized-bare-typaram.stderr | 11 +- src/test/ui/unsized/unsized-enum.stderr | 8 +- .../unsized-inherent-impl-self-type.stderr | 8 +- src/test/ui/unsized/unsized-struct.stderr | 16 +- .../unsized-trait-impl-self-type.stderr | 8 +- src/test/ui/unsized3.stderr | 52 +- src/test/ui/use/use-meta-mismatch.rs | 2 +- src/test/ui/use/use-meta-mismatch.stderr | 2 +- .../variance-regions-unused-direct.stderr | 4 +- .../variance-regions-unused-indirect.stderr | 4 +- .../variance-unused-region-param.stderr | 4 +- .../variance-unused-type-param.stderr | 6 +- src/test/ui/vtable-res-trait-param.stderr | 4 +- src/test/ui/wf/wf-const-type.stderr | 8 +- src/test/ui/wf/wf-enum-bound.stderr | 8 +- .../wf/wf-enum-fields-struct-variant.stderr | 8 +- src/test/ui/wf/wf-enum-fields.stderr | 8 +- src/test/ui/wf/wf-fn-where-clause.stderr | 8 +- .../wf/wf-impl-associated-type-trait.stderr | 8 +- src/test/ui/wf/wf-in-fn-arg.stderr | 8 +- src/test/ui/wf/wf-in-fn-ret.stderr | 8 +- src/test/ui/wf/wf-in-fn-type-arg.stderr | 8 +- src/test/ui/wf/wf-in-fn-type-ret.stderr | 8 +- src/test/ui/wf/wf-in-fn-where-clause.stderr | 8 +- src/test/ui/wf/wf-in-obj-type-trait.stderr | 8 +- ...f-inherent-impl-method-where-clause.stderr | 8 +- .../wf/wf-inherent-impl-where-clause.stderr | 8 +- src/test/ui/wf/wf-object-safe.stderr | 5 +- src/test/ui/wf/wf-static-method.stderr | 3 +- src/test/ui/wf/wf-static-type.stderr | 8 +- src/test/ui/wf/wf-struct-bound.stderr | 8 +- src/test/ui/wf/wf-struct-field.stderr | 8 +- .../wf/wf-trait-associated-type-bound.stderr | 8 +- .../wf/wf-trait-associated-type-trait.stderr | 8 +- src/test/ui/wf/wf-trait-bound.stderr | 8 +- src/test/ui/wf/wf-trait-default-fn-arg.stderr | 8 +- src/test/ui/wf/wf-trait-default-fn-ret.stderr | 8 +- .../wf-trait-default-fn-where-clause.stderr | 8 +- src/test/ui/wf/wf-trait-fn-arg.stderr | 8 +- src/test/ui/wf/wf-trait-fn-ret.stderr | 8 +- .../ui/wf/wf-trait-fn-where-clause.stderr | 8 +- src/test/ui/wf/wf-trait-superbound.stderr | 8 +- ...traints-are-local-for-inherent-impl.stderr | 12 +- ...onstraints-are-local-for-trait-impl.stderr | 12 +- .../where-clauses-method-unsatisfied.stderr | 4 +- .../where-clauses-unsatisfied.stderr | 9 +- .../ui/where-clauses/where-for-self-2.stderr | 12 +- src/test/ui/while-let.rs | 7 +- src/test/ui/while-let.stderr | 12 +- src/test/ui/wrapping-int-combinations.rs | 77 + src/tools/build-manifest/Cargo.toml | 2 +- src/tools/build-manifest/src/main.rs | 49 +- src/tools/cargo | 2 +- src/tools/cargotest/lockfiles/iron-Cargo.lock | 457 -- src/tools/cargotest/main.rs | 8 +- src/tools/clippy | 2 +- src/tools/compiletest/Cargo.toml | 2 +- src/tools/compiletest/src/common.rs | 6 +- src/tools/compiletest/src/header.rs | 28 +- src/tools/compiletest/src/main.rs | 9 +- src/tools/compiletest/src/runtest.rs | 162 +- src/tools/compiletest/src/util.rs | 8 +- src/tools/error_index_generator/Cargo.toml | 4 + src/tools/error_index_generator/build.rs | 57 + src/tools/error_index_generator/main.rs | 63 +- src/tools/linkchecker/main.rs | 2 + src/tools/miri | 2 +- src/tools/publish_toolstate.py | 120 +- src/tools/remote-test-client/src/main.rs | 14 +- src/tools/remote-test-server/src/main.rs | 24 +- src/tools/rls | 2 +- src/tools/rust-installer | 2 +- src/tools/rustbook/Cargo.toml | 7 +- src/tools/rustbook/src/main.rs | 95 +- .../rustc-std-workspace-alloc/Cargo.toml | 2 +- src/tools/rustc-std-workspace-core/Cargo.toml | 2 +- src/tools/rustc-std-workspace-std/Cargo.toml | 15 + src/tools/rustc-std-workspace-std/README.md | 3 + src/tools/rustc-std-workspace-std/lib.rs | 1 + src/tools/rustc-workspace-hack/Cargo.toml | 13 +- src/tools/rustfmt | 2 +- src/tools/tidy/src/deps.rs | 7 + src/tools/tidy/src/error_codes_check.rs | 137 + src/tools/tidy/src/features.rs | 31 +- src/tools/tidy/src/features/tests.rs | 4 +- src/tools/tidy/src/lib.rs | 4 + src/tools/tidy/src/main.rs | 3 + src/tools/tidy/src/style.rs | 26 +- src/tools/unstable-book-gen/src/main.rs | 2 + triagebot.toml | 3 +- 3593 files changed, 88771 insertions(+), 73127 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/report-time.md create mode 100644 src/doc/unstable-book/src/language-features/or-patterns.md delete mode 100644 src/doc/unstable-book/src/language-features/param-attrs.md create mode 100644 src/doc/unstable-book/src/language-features/track-caller.md delete mode 100644 src/grammar/.gitignore delete mode 100644 src/grammar/lexer.l delete mode 100644 src/grammar/parser-lalr-main.c delete mode 100644 src/grammar/parser-lalr.y delete mode 100644 src/grammar/raw-string-literal-ambiguity.md delete mode 100755 src/grammar/testparser.py delete mode 100644 src/grammar/tokens.h create mode 100644 src/libcore/bool.rs create mode 100644 src/libcore/tests/bool.rs delete mode 100644 src/librustc/cfg/construct.rs delete mode 100644 src/librustc/cfg/graphviz.rs delete mode 100644 src/librustc/cfg/mod.rs delete mode 100644 src/librustc/dep_graph/dep_tracking_map.rs create mode 100644 src/librustc/hir/lowering/expr.rs create mode 100644 src/librustc/hir/lowering/item.rs delete mode 100644 src/librustc/middle/borrowck.rs create mode 100644 src/librustc/middle/diagnostic_items.rs delete mode 100644 src/librustc_ast_borrowck/Cargo.toml delete mode 100644 src/librustc_ast_borrowck/borrowck/README.md delete mode 100644 src/librustc_ast_borrowck/borrowck/check_loans.rs delete mode 100644 src/librustc_ast_borrowck/borrowck/gather_loans/gather_moves.rs delete mode 100644 src/librustc_ast_borrowck/borrowck/gather_loans/lifetime.rs delete mode 100644 src/librustc_ast_borrowck/borrowck/gather_loans/mod.rs delete mode 100644 src/librustc_ast_borrowck/borrowck/gather_loans/restrictions.rs delete mode 100644 src/librustc_ast_borrowck/borrowck/mod.rs delete mode 100644 src/librustc_ast_borrowck/borrowck/move_data.rs delete mode 100644 src/librustc_ast_borrowck/dataflow.rs delete mode 100644 src/librustc_ast_borrowck/graphviz.rs delete mode 100644 src/librustc_ast_borrowck/lib.rs delete mode 100644 src/librustc_data_structures/obligation_forest/node_index.rs create mode 100644 src/librustc_data_structures/stable_map.rs create mode 100644 src/librustc_data_structures/stable_set.rs create mode 100644 src/librustc_driver/args.rs create mode 100644 src/librustc_index/Cargo.toml rename src/{librustc_data_structures => librustc_index}/bit_set.rs (99%) rename src/{librustc_data_structures => librustc_index}/bit_set/tests.rs (100%) create mode 100644 src/librustc_index/lib.rs rename src/{librustc_data_structures/indexed_vec.rs => librustc_index/vec.rs} (99%) create mode 100644 src/librustc_interface/build.rs delete mode 100644 src/librustc_interface/profile/mod.rs delete mode 100644 src/librustc_interface/profile/trace.rs create mode 100644 src/librustc_lint/redundant_semicolon.rs create mode 100644 src/librustc_metadata/dependency_format.rs create mode 100644 src/librustc_mir/dataflow/generic.rs create mode 100644 src/librustc_mir/dataflow/generic/graphviz.rs create mode 100644 src/librustc_mir/dataflow/impls/indirect_mutation.rs delete mode 100644 src/librustc_mir/monomorphize/item.rs create mode 100644 src/librustc_mir/transform/check_consts/mod.rs create mode 100644 src/librustc_mir/transform/check_consts/ops.rs create mode 100644 src/librustc_mir/transform/check_consts/qualifs.rs create mode 100644 src/librustc_mir/transform/check_consts/resolver.rs create mode 100644 src/librustc_mir/transform/check_consts/validation.rs rename src/{librustc/middle => librustc_passes}/dead.rs (89%) rename src/{librustc/middle => librustc_passes}/entry.rs (62%) rename src/{librustc/middle => librustc_passes}/intrinsicck.rs (91%) rename src/{librustc/middle => librustc_passes}/liveness.rs (84%) delete mode 100644 src/librustc_passes/rvalue_promotion.rs create mode 100644 src/librustc_plugin/deprecated/Cargo.toml create mode 100644 src/librustc_plugin/deprecated/lib.rs create mode 100644 src/librustc_resolve/late.rs create mode 100644 src/librustc_resolve/late/diagnostics.rs create mode 100644 src/librustc_target/spec/aarch64_unknown_none_softfloat.rs create mode 100644 src/librustc_target/spec/aarch64_uwp_windows_msvc.rs delete mode 100644 src/librustc_target/spec/arm_wrs_vxworks.rs delete mode 100644 src/librustc_target/spec/arm_wrs_vxworks_sf.rs rename src/librustc_target/spec/{armv7_wrs_vxworks.rs => armv7_wrs_vxworks_eabihf.rs} (77%) delete mode 100644 src/librustc_target/spec/i586_wrs_vxworks.rs create mode 100644 src/librustc_target/spec/i686_unknown_uefi.rs create mode 100644 src/librustc_target/spec/i686_uwp_windows_msvc.rs delete mode 100644 src/librustc_target/spec/i686_wrs_vxworks_gnu.rs create mode 100644 src/librustc_target/spec/linux_kernel_base.rs rename src/librustc_target/spec/{powerpc64_wrs_vxworks_gnusf.rs => mips64_unknown_linux_muslabi64.rs} (52%) create mode 100644 src/librustc_target/spec/mips64el_unknown_linux_muslabi64.rs delete mode 100644 src/librustc_target/spec/powerpc_wrs_vxworks_gnusf.rs delete mode 100644 src/librustc_target/spec/powerpc_wrs_vxworks_gnuspesf.rs create mode 100644 src/librustc_target/spec/sparc64_unknown_openbsd.rs create mode 100644 src/librustc_target/spec/windows_uwp_msvc_base.rs create mode 100644 src/librustc_target/spec/x86_64_apple_ios_macabi.rs create mode 100644 src/librustc_target/spec/x86_64_linux_kernel.rs create mode 100644 src/librustc_target/spec/x86_64_uwp_windows_msvc.rs create mode 100644 src/librustc_typeck/check/pat.rs create mode 100644 src/librustdoc/html/render/cache.rs create mode 100644 src/librustdoc/html/sources.rs create mode 100644 src/libstd/backtrace.rs delete mode 100644 src/libstd/sys/vxworks/backtrace/mod.rs delete mode 100644 src/libstd/sys/vxworks/backtrace/printing/dladdr.rs delete mode 100644 src/libstd/sys/vxworks/backtrace/printing/mod.rs delete mode 100644 src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs delete mode 100644 src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs delete mode 100644 src/libstd/sys/vxworks/backtrace/tracing/mod.rs delete mode 100644 src/libstd/sys/vxworks/process/rtp.rs delete mode 100644 src/libsyntax/diagnostics/metadata.rs delete mode 100644 src/libsyntax/diagnostics/plugin.rs create mode 100644 src/libsyntax/ext/mbe.rs rename src/libsyntax/ext/{tt => mbe}/macro_check.rs (99%) rename src/libsyntax/ext/{tt => mbe}/macro_parser.rs (97%) rename src/libsyntax/ext/{tt => mbe}/macro_rules.rs (82%) rename src/libsyntax/ext/{tt => mbe}/quoted.rs (63%) rename src/libsyntax/ext/{tt => mbe}/transcribe.rs (86%) delete mode 100644 src/libsyntax/feature_gate.rs create mode 100644 src/libsyntax/feature_gate/accepted.rs create mode 100644 src/libsyntax/feature_gate/active.rs create mode 100644 src/libsyntax/feature_gate/builtin_attrs.rs create mode 100644 src/libsyntax/feature_gate/check.rs create mode 100644 src/libsyntax/feature_gate/mod.rs create mode 100644 src/libsyntax/feature_gate/removed.rs create mode 100644 src/libsyntax/parse/parser/expr.rs create mode 100644 src/libsyntax/parse/parser/generics.rs create mode 100644 src/libsyntax/parse/parser/item.rs create mode 100644 src/libsyntax/parse/parser/module.rs create mode 100644 src/libsyntax/parse/parser/pat.rs create mode 100644 src/libsyntax/parse/parser/path.rs create mode 100644 src/libsyntax/parse/parser/stmt.rs create mode 100644 src/libsyntax/parse/parser/ty.rs create mode 100644 src/libsyntax_ext/cmdline_attrs.rs create mode 100644 src/test/codegen/README.md create mode 100644 src/test/codegen/integer-cmp.rs create mode 100644 src/test/codegen/iter-fold-closure-no-dupes.rs create mode 100644 src/test/codegen/iter-fold-closure-no-iterator.rs create mode 100644 src/test/codegen/non-terminate/infinite-loop-1.rs create mode 100644 src/test/codegen/non-terminate/infinite-loop-2.rs create mode 100644 src/test/codegen/non-terminate/infinite-recursion.rs create mode 100644 src/test/codegen/var-names.rs rename src/test/{ui/issues => compile-fail}/issue-44415.rs (100%) create mode 100644 src/test/debuginfo/issue-57822.rs create mode 100644 src/test/mir-opt/const_prop/read_immutable_static.rs create mode 100644 src/test/mir-opt/no-spurious-drop-after-call.rs create mode 100644 src/test/run-make-fulldeps/issue-64319/Makefile create mode 100644 src/test/run-make-fulldeps/issue-64319/bar.rs create mode 100644 src/test/run-make-fulldeps/issue-64319/foo.rs rename src/test/run-make-fulldeps/libtest-json/{output.json => output-default.json} (91%) create mode 100644 src/test/run-make-fulldeps/libtest-json/output-stdout-success.json delete mode 100644 src/test/run-make-fulldeps/linker-output-non-utf8/Makefile delete mode 100644 src/test/run-make-fulldeps/linker-output-non-utf8/exec.rs delete mode 100644 src/test/run-make-fulldeps/linker-output-non-utf8/library.rs create mode 100644 src/test/run-make-fulldeps/lto-empty/Makefile create mode 100644 src/test/run-make-fulldeps/lto-empty/lib.rs create mode 100644 src/test/run-make-fulldeps/reproducible-build-2/Makefile create mode 100644 src/test/run-make-fulldeps/reproducible-build-2/linker.rs create mode 100644 src/test/run-make-fulldeps/reproducible-build-2/reproducible-build-aux.rs create mode 100644 src/test/run-make-fulldeps/reproducible-build-2/reproducible-build.rs create mode 100644 src/test/rustdoc-js/exact-match.js create mode 100644 src/test/rustdoc-js/exact-match.rs create mode 100644 src/test/rustdoc-js/module-substring.js create mode 100644 src/test/rustdoc-js/module-substring.rs create mode 100644 src/test/rustdoc-ui/doc-test-doctest-feature.rs create mode 100644 src/test/rustdoc-ui/doc-test-doctest-feature.stdout create mode 100644 src/test/rustdoc-ui/doc-test-rustdoc-feature.rs create mode 100644 src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout create mode 100644 src/test/rustdoc/auxiliary/issue-57180.rs create mode 100644 src/test/rustdoc/auxiliary/through-proc-macro-aux.rs create mode 100644 src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs create mode 100644 src/test/rustdoc/inline_cross/impl_trait.rs create mode 100644 src/test/rustdoc/issue-57180.rs create mode 100644 src/test/rustdoc/through-proc-macro.rs create mode 100644 src/test/ui-fulldeps/issue-15778-pass.stderr create mode 100644 src/test/ui-fulldeps/issue-40001.stderr create mode 100644 src/test/ui-fulldeps/llvm-pass-plugin.stderr create mode 100644 src/test/ui-fulldeps/lto-syntax-extension.stderr create mode 100644 src/test/ui-fulldeps/outlive-expansion-phase.stderr create mode 100644 src/test/ui-fulldeps/plugin-args-1.stderr create mode 100644 src/test/ui-fulldeps/plugin-args-2.stderr create mode 100644 src/test/ui-fulldeps/plugin-args-3.stderr create mode 100644 src/test/ui-fulldeps/roman-numerals-macro.stderr rename src/test/ui/{ => abi}/abi-sysv64-arg-passing.rs (100%) rename src/test/ui/{ => abi}/abi-sysv64-register-usage.rs (100%) rename src/test/ui/{ => abi}/abort-on-c-abi.rs (93%) rename src/test/ui/{ => abi}/anon-extern-mod.rs (100%) rename src/test/ui/{ => abi}/auxiliary/anon-extern-mod-cross-crate-1.rs (100%) rename src/test/ui/{ => abi}/auxiliary/foreign_lib.rs (100%) rename src/test/ui/{ => abi}/c-stack-as-value.rs (100%) rename src/test/ui/{ => abi}/cabi-int-widening.rs (100%) rename src/test/ui/{ => abi}/consts/auxiliary/anon-extern-mod-cross-crate-1.rs (100%) rename src/test/ui/{ => abi}/cross-crate/anon-extern-mod-cross-crate-2.rs (100%) rename src/test/ui/{ => abi}/cross-crate/auxiliary/anon-extern-mod-cross-crate-1.rs (100%) rename src/test/ui/{ => abi}/duplicated-external-mods.rs (100%) rename src/test/ui/{ => abi}/extern/auxiliary/extern-crosscrate-source.rs (100%) rename src/test/ui/{ => abi}/extern/extern-call-deep.rs (100%) rename src/test/ui/{ => abi}/extern/extern-call-deep2.rs (100%) rename src/test/ui/{ => abi}/extern/extern-call-direct.rs (100%) rename src/test/ui/{ => abi}/extern/extern-call-indirect.rs (100%) rename src/test/ui/{ => abi}/extern/extern-call-scrub.rs (100%) rename src/test/ui/{ => abi}/extern/extern-crosscrate.rs (100%) rename src/test/ui/{ => abi}/extern/extern-pass-TwoU16s.rs (100%) rename src/test/ui/{ => abi}/extern/extern-pass-TwoU32s.rs (100%) rename src/test/ui/{ => abi}/extern/extern-pass-TwoU64s.rs (100%) rename src/test/ui/{ => abi}/extern/extern-pass-TwoU8s.rs (100%) rename src/test/ui/{ => abi}/extern/extern-pass-char.rs (100%) rename src/test/ui/{ => abi}/extern/extern-pass-double.rs (100%) rename src/test/ui/{ => abi}/extern/extern-pass-empty.rs (100%) rename src/test/ui/{ => abi}/extern/extern-pass-u32.rs (100%) rename src/test/ui/{ => abi}/extern/extern-pass-u64.rs (100%) rename src/test/ui/{ => abi}/extern/extern-return-TwoU16s.rs (100%) rename src/test/ui/{ => abi}/extern/extern-return-TwoU32s.rs (100%) rename src/test/ui/{ => abi}/extern/extern-return-TwoU64s.rs (100%) rename src/test/ui/{ => abi}/extern/extern-return-TwoU8s.rs (100%) rename src/test/ui/{ => abi}/foreign/auxiliary/foreign_lib.rs (100%) rename src/test/ui/{ => abi}/foreign/foreign-call-no-runtime.rs (100%) rename src/test/ui/{ => abi}/foreign/foreign-dupe.rs (100%) rename src/test/ui/{ => abi}/foreign/foreign-fn-with-byval.rs (100%) rename src/test/ui/{ => abi}/foreign/foreign-no-abi.rs (100%) rename src/test/ui/{ => abi}/invoke-external-foreign.rs (100%) rename src/test/ui/{ => abi}/lib-defaults.rs (100%) rename src/test/ui/{ => abi}/mir/mir_codegen_calls_variadic.rs (100%) rename src/test/ui/{ => abi}/numbers-arithmetic/i128-ffi.rs (100%) rename src/test/ui/{ => abi}/segfault-no-out-of-stack.rs (100%) rename src/test/ui/{ => abi}/stack-probes-lto.rs (100%) rename src/test/ui/{ => abi}/stack-probes.rs (100%) rename src/test/ui/{ => abi}/statics/static-mut-foreign.rs (100%) rename src/test/ui/{structs-enums => abi/struct-enums}/struct-return.rs (100%) rename src/test/ui/{ => abi}/union/union-c-interop.rs (100%) rename src/test/ui/{ => abi}/variadic-ffi.rs (100%) create mode 100644 src/test/ui/allocator/hygiene.rs create mode 100644 src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs create mode 100644 src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr create mode 100644 src/test/ui/associated-types/issue-64855-2.rs create mode 100644 src/test/ui/associated-types/issue-64855.rs create mode 100644 src/test/ui/associated-types/issue-64855.stderr create mode 100644 src/test/ui/ast-json/ast-json-ice.rs create mode 100644 src/test/ui/ast-json/ast-json-output.rs create mode 100644 src/test/ui/ast-json/ast-json-output.stdout create mode 100644 src/test/ui/async-await/async-assoc-fn-anon-lifetimes.rs create mode 100644 src/test/ui/async-await/async-borrowck-escaping-block-error.fixed create mode 100644 src/test/ui/async-await/async-borrowck-escaping-block-error.rs create mode 100644 src/test/ui/async-await/async-borrowck-escaping-block-error.stderr create mode 100644 src/test/ui/async-await/async-borrowck-escaping-closure-error.rs create mode 100644 src/test/ui/async-await/async-borrowck-escaping-closure-error.stderr create mode 100644 src/test/ui/async-await/async-fn-elided-impl-lifetime-parameter.rs create mode 100644 src/test/ui/async-await/async-fn-size-uninit-locals.rs create mode 100644 src/test/ui/async-await/drop-order/drop-order-for-temporary-in-tail-return-expr.rs create mode 100644 src/test/ui/async-await/issue-61949-self-return-type.rs create mode 100644 src/test/ui/async-await/issue-61949-self-return-type.stderr create mode 100644 src/test/ui/async-await/issue-63832-await-short-temporary-lifetime-1.rs create mode 100644 src/test/ui/async-await/issue-63832-await-short-temporary-lifetime.rs create mode 100644 src/test/ui/async-await/issue-64130-non-send-future-diags.rs create mode 100644 src/test/ui/async-await/issue-64130-non-send-future-diags.stderr create mode 100644 src/test/ui/async-await/issue-64391.rs create mode 100644 src/test/ui/async-await/issues/issue-54752-async-block.stderr create mode 100644 src/test/ui/async-await/issues/issue-62517-1.rs create mode 100644 src/test/ui/async-await/issues/issue-62517-2.rs create mode 100644 src/test/ui/async-await/issues/issue-63388-1.nll.stderr create mode 100644 src/test/ui/async-await/issues/issue-63388-1.rs create mode 100644 src/test/ui/async-await/issues/issue-63388-1.stderr create mode 100644 src/test/ui/async-await/issues/issue-63388-2.nll.stderr create mode 100644 src/test/ui/async-await/issues/issue-63388-2.rs create mode 100644 src/test/ui/async-await/issues/issue-63388-2.stderr create mode 100644 src/test/ui/async-await/issues/issue-63388-3.rs create mode 100644 src/test/ui/async-await/issues/issue-63388-4.rs create mode 100644 src/test/ui/async-await/issues/issue-64391-2.rs create mode 100644 src/test/ui/async-await/issues/issue-64433.rs create mode 100644 src/test/ui/async-await/issues/issue-64477.rs create mode 100644 src/test/ui/async-await/issues/issue-64964.rs create mode 100644 src/test/ui/async-await/issues/non-async-enclosing-span.rs create mode 100644 src/test/ui/async-await/issues/non-async-enclosing-span.stderr create mode 100644 src/test/ui/async-await/mutually-recursive-async-impl-trait-type.rs create mode 100644 src/test/ui/async-await/mutually-recursive-async-impl-trait-type.stderr create mode 100644 src/test/ui/async-await/nested-in-impl.rs delete mode 100644 src/test/ui/async-await/no-args-non-move-async-closure.rs create mode 100644 src/test/ui/async-await/no-params-non-move-async-closure.rs rename src/test/ui/async-await/{no-args-non-move-async-closure.stderr => no-params-non-move-async-closure.stderr} (63%) create mode 100644 src/test/ui/async-await/return-ty-raw-ptr-coercion.rs create mode 100644 src/test/ui/async-await/return-ty-unsize-coercion.rs create mode 100644 src/test/ui/async-await/suggest-switching-edition-on-await.rs create mode 100644 src/test/ui/async-await/suggest-switching-edition-on-await.stderr create mode 100644 src/test/ui/async-await/unreachable-lint-1.rs create mode 100644 src/test/ui/async-await/unreachable-lint-1.stderr create mode 100644 src/test/ui/async-await/unreachable-lint.rs create mode 100644 src/test/ui/attributes/multiple-invalid.rs create mode 100644 src/test/ui/attributes/multiple-invalid.stderr create mode 100644 src/test/ui/attributes/unnamed-field-attributes.rs create mode 100644 src/test/ui/attrs-resolution-errors.rs create mode 100644 src/test/ui/attrs-resolution-errors.stderr create mode 100644 src/test/ui/attrs-resolution.rs delete mode 100644 src/test/ui/bind-by-move/bind-by-move-no-guards.rs delete mode 100644 src/test/ui/bind-by-move/bind-by-move-no-guards.stderr create mode 100644 src/test/ui/block-expr-precedence.stderr delete mode 100644 src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr delete mode 100644 src/test/ui/borrowck/borrowck-describe-lvalue.nll.stderr delete mode 100644 src/test/ui/borrowck/borrowck-escaping-closure-error-2.polonius.stderr delete mode 100644 src/test/ui/borrowck/borrowck-migrate-to-nll.edition.stderr delete mode 100644 src/test/ui/borrowck/borrowck-migrate-to-nll.rs delete mode 100644 src/test/ui/borrowck/borrowck-migrate-to-nll.zflag.stderr create mode 100644 src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.rs create mode 100644 src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr create mode 100644 src/test/ui/borrowck/issue-64453.rs create mode 100644 src/test/ui/borrowck/issue-64453.stderr create mode 100644 src/test/ui/borrowck/move-error-snippets-ext.rs create mode 100644 src/test/ui/borrowck/move-error-snippets.rs create mode 100644 src/test/ui/borrowck/move-error-snippets.stderr delete mode 100644 src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.polonius.stderr delete mode 100644 src/test/ui/borrowck/two-phase-surprise-no-conflict.polonius.stderr create mode 100644 src/test/ui/c-variadic/variadic-ffi-no-fixed-args.rs create mode 100644 src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr create mode 100644 src/test/ui/coherence/conflicting-impl-with-err.rs create mode 100644 src/test/ui/coherence/conflicting-impl-with-err.stderr create mode 100644 src/test/ui/coherence/impl-foreign[foreign]-for-foreign.rs create mode 100644 src/test/ui/coherence/impl-foreign[foreign]-for-foreign.stderr create mode 100644 src/test/ui/coherence/impl-foreign[foreign]-for-local.rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[foreign[t]_local]-for-foreign.rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].stderr create mode 100644 src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.stderr create mode 100644 src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.stderr create mode 100644 src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].stderr create mode 100644 src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-local.rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.stderr create mode 100644 src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.stderr create mode 100644 src/test/ui/coherence/impl[t]-foreign[local]-for-foreign.rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].stderr create mode 100644 src/test/ui/coherence/impl[t]-foreign[local]-for-local.rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[local]-for-t.rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[local]-for-t.stderr create mode 100644 src/test/ui/coherence/impl[t]-foreign[local_fundamental[t]]-for-foreign.rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.stderr create mode 100644 src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.stderr create mode 100644 src/test/ui/coherence/impl[t]-foreign[t]-for-local.rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[t]-for-t.rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[t]-for-t.stderr delete mode 100644 src/test/ui/coherence/re-rebalance-coherence-rpass.rs create mode 100644 src/test/ui/commandline-argfile-badutf8.args create mode 100644 src/test/ui/commandline-argfile-badutf8.rs create mode 100644 src/test/ui/commandline-argfile-badutf8.stderr create mode 100644 src/test/ui/commandline-argfile-missing.rs create mode 100644 src/test/ui/commandline-argfile-missing.stderr create mode 100644 src/test/ui/commandline-argfile.args create mode 100644 src/test/ui/commandline-argfile.rs create mode 100644 src/test/ui/conditional-compilation/cfg-arg-invalid-6.rs create mode 100644 src/test/ui/conditional-compilation/cfg-arg-invalid-6.stderr create mode 100644 src/test/ui/const-generics/fn-const-param-call.rs create mode 100644 src/test/ui/const-generics/fn-const-param-call.stderr create mode 100644 src/test/ui/const-generics/fn-const-param-infer.rs create mode 100644 src/test/ui/const-generics/fn-const-param-infer.stderr create mode 100644 src/test/ui/const-generics/foreign-item-const-parameter.rs create mode 100644 src/test/ui/const-generics/foreign-item-const-parameter.stderr rename src/test/ui/const-generics/{ => issues}/issue-60263.rs (100%) rename src/test/ui/const-generics/{ => issues}/issue-60263.stderr (100%) rename src/test/ui/const-generics/{ => issues}/issue-60818-struct-constructors.rs (100%) rename src/test/ui/const-generics/{ => issues}/issue-60818-struct-constructors.stderr (100%) rename src/test/ui/const-generics/{ => issues}/issue-61336-1.rs (100%) rename src/test/ui/const-generics/{ => issues}/issue-61336-1.stderr (100%) rename src/test/ui/const-generics/{ => issues}/issue-61336-2.rs (100%) rename src/test/ui/const-generics/{ => issues}/issue-61336-2.stderr (100%) rename src/test/ui/const-generics/{ => issues}/issue-61336.rs (100%) rename src/test/ui/const-generics/{ => issues}/issue-61336.stderr (100%) rename src/test/ui/const-generics/{ => issues}/issue-61422.rs (79%) rename src/test/ui/const-generics/{ => issues}/issue-61422.stderr (100%) create mode 100644 src/test/ui/const-generics/issues/issue-61432.rs create mode 100644 src/test/ui/const-generics/issues/issue-61432.stderr create mode 100644 src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs create mode 100644 src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr create mode 100644 src/test/ui/const-generics/issues/issue-64519.rs create mode 100644 src/test/ui/const-generics/issues/issue-64519.stderr create mode 100644 src/test/ui/const-generics/raw-ptr-const-param-deref.rs create mode 100644 src/test/ui/const-generics/raw-ptr-const-param-deref.stderr create mode 100644 src/test/ui/const-generics/raw-ptr-const-param.rs create mode 100644 src/test/ui/const-generics/raw-ptr-const-param.stderr create mode 100644 src/test/ui/const-generics/slice-const-param-mismatch.rs create mode 100644 src/test/ui/const-generics/slice-const-param-mismatch.stderr create mode 100644 src/test/ui/const-generics/slice-const-param.rs create mode 100644 src/test/ui/const-generics/slice-const-param.stderr create mode 100644 src/test/ui/const-generics/types-mismatch-const-args.rs create mode 100644 src/test/ui/const-generics/types-mismatch-const-args.stderr create mode 100644 src/test/ui/consts/auxiliary/issue-63226.rs create mode 100644 src/test/ui/consts/const-err3.rs create mode 100644 src/test/ui/consts/const-err3.stderr create mode 100644 src/test/ui/consts/const-eval/const_fn_ptr.rs create mode 100644 src/test/ui/consts/const-eval/const_fn_ptr.stderr create mode 100644 src/test/ui/consts/const-eval/const_fn_ptr_fail.rs create mode 100644 src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr create mode 100644 src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs create mode 100644 src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr create mode 100644 src/test/ui/consts/const-eval/dangling.rs create mode 100644 src/test/ui/consts/const-eval/dangling.stderr create mode 100644 src/test/ui/consts/const-eval/generic-slice.rs create mode 100644 src/test/ui/consts/const-eval/generic-slice.stderr create mode 100644 src/test/ui/consts/const-eval/issue-64908.rs create mode 100644 src/test/ui/consts/const-eval/issue-64970.rs create mode 100644 src/test/ui/consts/const-eval/issue-64970.stderr create mode 100644 src/test/ui/consts/const-eval/promoted_errors2.rs create mode 100644 src/test/ui/consts/const-eval/promoted_errors2.stderr create mode 100644 src/test/ui/consts/const-eval/simd/insert_extract.rs create mode 100644 src/test/ui/consts/const-eval/ub-wide-ptr.rs create mode 100644 src/test/ui/consts/const-eval/ub-wide-ptr.stderr delete mode 100644 src/test/ui/consts/const-eval/union-ub-fat-ptr.rs delete mode 100644 src/test/ui/consts/const-eval/union-ub-fat-ptr.stderr create mode 100644 src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs create mode 100644 src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr create mode 100644 src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs create mode 100644 src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr create mode 100644 src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs create mode 100644 src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.stderr create mode 100644 src/test/ui/consts/const-extern-fn/const-extern-fn.rs create mode 100644 src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs create mode 100644 src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr create mode 100644 src/test/ui/consts/const-if.rs create mode 100644 src/test/ui/consts/const-if.stderr create mode 100644 src/test/ui/consts/const-multi-ref.rs create mode 100644 src/test/ui/consts/const-multi-ref.stderr create mode 100644 src/test/ui/consts/const-prop-read-static-in-const.rs create mode 100644 src/test/ui/consts/const-prop-read-static-in-const.stderr create mode 100644 src/test/ui/consts/issue-63226.rs create mode 100644 src/test/ui/consts/issue-64059-2.rs create mode 100644 src/test/ui/consts/issue-64059.rs create mode 100644 src/test/ui/consts/issue-64662.rs create mode 100644 src/test/ui/consts/issue-64662.stderr delete mode 100644 src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr delete mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs rename src/test/ui/consts/min_const_fn/{min_const_fn_unsafe.stderr => min_const_fn_unsafe_bad.stderr} (79%) rename src/test/ui/consts/min_const_fn/{min_const_fn_unsafe.rs => min_const_fn_unsafe_ok.rs} (61%) create mode 100644 src/test/ui/consts/miri_unleashed/enum_discriminants.rs create mode 100644 src/test/ui/consts/miri_unleashed/enum_discriminants.stderr create mode 100644 src/test/ui/consts/miri_unleashed/mutable_const.rs create mode 100644 src/test/ui/consts/miri_unleashed/mutable_const.stderr create mode 100644 src/test/ui/consts/packed_pattern.stderr create mode 100644 src/test/ui/consts/packed_pattern2.stderr delete mode 100644 src/test/ui/consts/promote_const_let.polonius.stderr create mode 100644 src/test/ui/consts/too_generic_eval_ice.rs create mode 100644 src/test/ui/consts/too_generic_eval_ice.stderr create mode 100644 src/test/ui/consts/zst_no_llvm_alloc.rs create mode 100644 src/test/ui/definition-reachable/auxiliary/field-method-macro.rs create mode 100644 src/test/ui/definition-reachable/auxiliary/nested-fn-macro.rs create mode 100644 src/test/ui/definition-reachable/auxiliary/private-use-macro.rs create mode 100644 src/test/ui/definition-reachable/field-method.rs create mode 100644 src/test/ui/definition-reachable/nested-fn.rs create mode 100644 src/test/ui/definition-reachable/private-non-types.rs create mode 100644 src/test/ui/definition-reachable/private-types.rs create mode 100644 src/test/ui/definition-reachable/private-use.rs create mode 100644 src/test/ui/derives/derive-hygiene.rs delete mode 100644 src/test/ui/did_you_mean/multiple-pattern-typo.rs delete mode 100644 src/test/ui/did_you_mean/multiple-pattern-typo.stderr delete mode 100644 src/test/ui/dropck/dropck_trait_cycle_checked.polonius.stderr delete mode 100644 src/test/ui/error-codes/E0008.rs delete mode 100644 src/test/ui/error-codes/E0008.stderr delete mode 100644 src/test/ui/error-codes/E0301.rs delete mode 100644 src/test/ui/error-codes/E0301.stderr delete mode 100644 src/test/ui/error-codes/E0302.rs delete mode 100644 src/test/ui/error-codes/E0302.stderr create mode 100644 src/test/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs create mode 100644 src/test/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs create mode 100644 src/test/ui/feature-gates/bench.rs create mode 100644 src/test/ui/feature-gates/bench.stderr delete mode 100644 src/test/ui/feature-gates/feature-gate-async-await-2015-edition.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-async-await-2015-edition.stderr delete mode 100644 src/test/ui/feature-gates/feature-gate-async-await.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-async-await.stderr create mode 100644 src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs create mode 100644 src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr delete mode 100644 src/test/ui/feature-gates/feature-gate-macros_in_extern.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr delete mode 100644 src/test/ui/feature-gates/feature-gate-rustc-diagnostic-macros.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-rustc-diagnostic-macros.stderr create mode 100644 src/test/ui/feature-gates/feature-gate-track_caller.rs create mode 100644 src/test/ui/feature-gates/feature-gate-track_caller.stderr delete mode 100644 src/test/ui/format-hygiene.rs rename src/test/{run-pass => ui}/generator/niche-in-generator.rs (95%) delete mode 100644 src/test/ui/generator/no-arguments-on-generators.stderr rename src/test/ui/generator/{no-arguments-on-generators.rs => no-parameters-on-generators.rs} (59%) create mode 100644 src/test/ui/generator/no-parameters-on-generators.stderr delete mode 100644 src/test/ui/generator/ref-escapes-but-not-over-yield.polonius.stderr create mode 100644 src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.rs create mode 100644 src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr create mode 100644 src/test/ui/generics/issue-61631-default-type-param-cannot-reference-self.rs create mode 100644 src/test/ui/generics/issue-61631-default-type-param-cannot-reference-self.stderr create mode 100644 src/test/ui/hrtb/due-to-where-clause.nll.stderr create mode 100644 src/test/ui/hrtb/due-to-where-clause.rs create mode 100644 src/test/ui/hrtb/due-to-where-clause.stderr create mode 100644 src/test/ui/hygiene/auxiliary/codegen-attrs.rs create mode 100644 src/test/ui/hygiene/auxiliary/not-libstd.rs create mode 100644 src/test/ui/hygiene/cross-crate-codegen-attrs.rs create mode 100644 src/test/ui/hygiene/eager-from-opaque-2.rs create mode 100644 src/test/ui/hygiene/eager-from-opaque.rs create mode 100644 src/test/ui/hygiene/format-args.rs create mode 100644 src/test/ui/hygiene/prelude-import-hygiene.rs create mode 100644 src/test/ui/hygiene/privacy-early.rs create mode 100644 src/test/ui/hygiene/privacy-early.stderr create mode 100644 src/test/ui/if-ret.stderr create mode 100644 src/test/ui/impl-trait/auto-trait.rs create mode 100644 src/test/ui/impl-trait/auto-trait.stderr create mode 100644 src/test/ui/impl-trait/dyn-trait-elided-two-inputs-assoc.rs create mode 100644 src/test/ui/impl-trait/dyn-trait-elided-two-inputs-param.rs create mode 100644 src/test/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs create mode 100644 src/test/ui/impl-trait/dyn-trait-elided-two-inputs-ref-param.rs create mode 100644 src/test/ui/impl-trait/negative-reasoning.rs create mode 100644 src/test/ui/impl-trait/negative-reasoning.stderr create mode 100644 src/test/ui/impl-trait/recursive-impl-trait-type--through-non-recursize.rs create mode 100644 src/test/ui/impl-trait/recursive-impl-trait-type--through-non-recursize.stderr create mode 100644 src/test/ui/in-band-lifetimes/nested-items.rs delete mode 100644 src/test/ui/inaccessible-test-modules.stderr create mode 100644 src/test/ui/include-macros/data.bin create mode 100644 src/test/ui/include-macros/normalization.rs create mode 100644 src/test/ui/include-single-expr-helper-1.rs create mode 100644 src/test/ui/include-single-expr-helper.rs create mode 100644 src/test/ui/include-single-expr.rs create mode 100644 src/test/ui/include-single-expr.stderr create mode 100644 src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs create mode 100644 src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr create mode 100644 src/test/ui/inference/cannot-infer-async.rs create mode 100644 src/test/ui/inference/cannot-infer-async.stderr create mode 100644 src/test/ui/inference/cannot-infer-closure.rs create mode 100644 src/test/ui/inference/cannot-infer-closure.stderr create mode 100644 src/test/ui/intrinsics-always-extern.rs create mode 100644 src/test/ui/intrinsics-always-extern.stderr create mode 100644 src/test/ui/intrinsics/intrinsic-uninit.rs create mode 100644 src/test/ui/issues/auxiliary/issue-57271-lib.rs create mode 100644 src/test/ui/issues/issue-33575.rs create mode 100644 src/test/ui/issues/issue-33575.stderr create mode 100644 src/test/ui/issues/issue-36836.rs create mode 100644 src/test/ui/issues/issue-36836.stderr delete mode 100644 src/test/ui/issues/issue-40510-1.migrate.nll.stderr rename src/test/ui/issues/{issue-40510-1.nll.stderr => issue-40510-1.stderr} (93%) delete mode 100644 src/test/ui/issues/issue-40510-3.nll.stderr rename src/test/ui/issues/{issue-40510-3.migrate.nll.stderr => issue-40510-3.stderr} (94%) create mode 100644 src/test/ui/issues/issue-43623.rs create mode 100644 src/test/ui/issues/issue-43623.stderr create mode 100644 src/test/ui/issues/issue-44405.rs create mode 100644 src/test/ui/issues/issue-44405.stderr delete mode 100644 src/test/ui/issues/issue-44415.stderr delete mode 100644 src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.migrate.stderr rename src/test/ui/issues/{issue-45696-scribble-on-boxed-borrow.nll.stderr => issue-45696-scribble-on-boxed-borrow.stderr} (88%) delete mode 100644 src/test/ui/issues/issue-49824.nll.stderr create mode 100644 src/test/ui/issues/issue-49934-errors.rs create mode 100644 src/test/ui/issues/issue-49934-errors.stderr create mode 100644 src/test/ui/issues/issue-50301.rs create mode 100644 src/test/ui/issues/issue-50571.rs create mode 100644 src/test/ui/issues/issue-50571.stderr create mode 100644 src/test/ui/issues/issue-52262.rs create mode 100644 src/test/ui/issues/issue-52262.stderr rename src/test/ui/{ => issues}/issue-53912.rs (100%) create mode 100644 src/test/ui/issues/issue-56870.rs create mode 100644 src/test/ui/issues/issue-57271.rs create mode 100644 src/test/ui/issues/issue-57271.stderr create mode 100644 src/test/ui/issues/issue-57399-self-return-impl-trait.rs create mode 100644 src/test/ui/issues/issue-57399-self-return-impl-trait.stderr create mode 100644 src/test/ui/issues/issue-58022.rs create mode 100644 src/test/ui/issues/issue-58022.stderr create mode 100644 src/test/ui/issues/issue-58344.rs create mode 100644 src/test/ui/issues/issue-58344.stderr rename src/test/ui/{ => issues}/issue-59020.rs (100%) create mode 100644 src/test/ui/issues/issue-60218.rs create mode 100644 src/test/ui/issues/issue-60218.stderr create mode 100644 src/test/ui/issues/issue-63983.rs create mode 100644 src/test/ui/issues/issue-63983.stderr create mode 100644 src/test/ui/issues/issue-64430.rs create mode 100644 src/test/ui/issues/issue-64430.stderr create mode 100644 src/test/ui/issues/issue-64559.rs create mode 100644 src/test/ui/issues/issue-64559.stderr create mode 100644 src/test/ui/issues/issue-64593.rs create mode 100644 src/test/ui/issues/issue-64620.rs create mode 100644 src/test/ui/issues/issue-64620.stderr create mode 100644 src/test/ui/issues/issue-64732.rs create mode 100644 src/test/ui/issues/issue-64732.stderr create mode 100644 src/test/ui/issues/issue-64792-bad-unicode-ctor.rs create mode 100644 src/test/ui/issues/issue-64792-bad-unicode-ctor.stderr create mode 100644 src/test/ui/issues/issue-65284-suggest-generic-trait-bound.rs create mode 100644 src/test/ui/issues/issue-65284-suggest-generic-trait-bound.stderr create mode 100644 src/test/ui/issues/issue-8460-const2.rs create mode 100644 src/test/ui/issues/issue-8460-const2.stderr create mode 100644 src/test/ui/iterators/iter-count-overflow-debug.rs create mode 100644 src/test/ui/iterators/iter-count-overflow-ndebug.rs create mode 100644 src/test/ui/iterators/iter-map-fold-type-length.rs create mode 100644 src/test/ui/iterators/iter-position-overflow-debug.rs create mode 100644 src/test/ui/iterators/iter-position-overflow-ndebug.rs create mode 100644 src/test/ui/json-multiple.polonius.stderr create mode 100644 src/test/ui/json-options.polonius.stderr create mode 100644 src/test/ui/lang-item-missing-generator.rs create mode 100644 src/test/ui/lang-item-missing-generator.stderr create mode 100644 src/test/ui/lint/lint-dead-code-const-and-self.rs create mode 100644 src/test/ui/lint/lint-dead-code-empty-unused-enum-pub.rs create mode 100644 src/test/ui/lint/lint-dead-code-empty-unused-enum.rs create mode 100644 src/test/ui/lint/lint-dead-code-empty-unused-enum.stderr create mode 100644 src/test/ui/lint/lint-dead-code-unused-enum.rs create mode 100644 src/test/ui/lint/lint-dead-code-unused-enum.stderr create mode 100644 src/test/ui/lint/lint-dead-code-unused-variant-pub.rs create mode 100644 src/test/ui/lint/lint-dead-code-unused-variant.rs create mode 100644 src/test/ui/lint/lint-dead-code-unused-variant.stderr create mode 100644 src/test/ui/lint/opaque-ty-ffi-unsafe.rs create mode 100644 src/test/ui/lint/opaque-ty-ffi-unsafe.stderr create mode 100644 src/test/ui/lint/redundant-semicolon/auxiliary/redundant-semi-proc-macro-def.rs create mode 100644 src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.rs create mode 100644 src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr create mode 100644 src/test/ui/lint/uninitialized-zeroed.rs create mode 100644 src/test/ui/lint/uninitialized-zeroed.stderr create mode 100644 src/test/ui/lint/unreachable-async-fn.rs create mode 100644 src/test/ui/macros/builtin-prelude-no-accidents.rs create mode 100644 src/test/ui/macros/builtin-prelude-no-accidents.stderr create mode 100644 src/test/ui/macros/builtin-std-paths-fail.rs create mode 100644 src/test/ui/macros/builtin-std-paths-fail.stderr create mode 100644 src/test/ui/macros/builtin-std-paths.rs create mode 100644 src/test/ui/macros/macro-in-fn.rs create mode 100644 src/test/ui/macros/macro-meta-items-modern.rs delete mode 100644 src/test/ui/macros/macros-in-extern-rpass.rs delete mode 100644 src/test/ui/macros/macros-in-extern.stderr create mode 100644 src/test/ui/match/match-arm-resolving-to-never.rs create mode 100644 src/test/ui/match/match-arm-resolving-to-never.stderr create mode 100644 src/test/ui/match/non-exhaustive-defined-here.rs create mode 100644 src/test/ui/match/non-exhaustive-defined-here.stderr create mode 100644 src/test/ui/mir-dataflow/indirect-mutation-offset.rs create mode 100644 src/test/ui/mir-dataflow/indirect-mutation-offset.stderr create mode 100644 src/test/ui/never-from-impl-is-reserved.rs create mode 100644 src/test/ui/never-from-impl-is-reserved.stderr create mode 100644 src/test/ui/nll/issue-63154-normalize.rs delete mode 100644 src/test/ui/nll/loan_ends_mid_block_pair.polonius.stderr create mode 100644 src/test/ui/nll/promoted-liveness.rs create mode 100644 src/test/ui/nll/relate_tys/fn-subtype.rs create mode 100644 src/test/ui/nll/relate_tys/fn-subtype.stderr create mode 100644 src/test/ui/nll/relate_tys/trait-hrtb.rs create mode 100644 src/test/ui/nll/relate_tys/trait-hrtb.stderr delete mode 100644 src/test/ui/nll/return-ref-mut-issue-46557.polonius.stderr create mode 100644 src/test/ui/nll/self-assign-ref-mut.rs rename src/test/ui/{non-interger-atomic.rs => non-integer-atomic.rs} (100%) rename src/test/ui/{non-interger-atomic.stderr => non-integer-atomic.stderr} (83%) create mode 100644 src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.rs create mode 100644 src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.stderr create mode 100644 src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.rs create mode 100644 src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.stderr create mode 100644 src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs create mode 100644 src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr create mode 100644 src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-static.rs create mode 100644 src/test/ui/or-patterns/already-bound-name.rs create mode 100644 src/test/ui/or-patterns/already-bound-name.stderr create mode 100644 src/test/ui/or-patterns/consistent-bindings.rs create mode 100644 src/test/ui/or-patterns/consistent-bindings.stderr create mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.rs create mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr create mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.rs create mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr create mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns.rs create mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns.stderr create mode 100644 src/test/ui/or-patterns/fn-param-wrap-parens.fixed create mode 100644 src/test/ui/or-patterns/fn-param-wrap-parens.rs create mode 100644 src/test/ui/or-patterns/fn-param-wrap-parens.stderr create mode 100644 src/test/ui/or-patterns/inconsistent-modes.rs create mode 100644 src/test/ui/or-patterns/inconsistent-modes.stderr create mode 100644 src/test/ui/or-patterns/issue-64879-trailing-before-guard.rs create mode 100644 src/test/ui/or-patterns/issue-64879-trailing-before-guard.stderr create mode 100644 src/test/ui/or-patterns/missing-bindings.rs create mode 100644 src/test/ui/or-patterns/missing-bindings.stderr create mode 100644 src/test/ui/or-patterns/multiple-pattern-typo.rs create mode 100644 src/test/ui/or-patterns/multiple-pattern-typo.stderr rename src/test/ui/{ => or-patterns}/or-pattern-mismatch.rs (100%) rename src/test/ui/{ => or-patterns}/or-pattern-mismatch.stderr (100%) create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-fail.rs create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-pass.rs create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr create mode 100644 src/test/ui/or-patterns/remove-leading-vert.fixed create mode 100644 src/test/ui/or-patterns/remove-leading-vert.rs create mode 100644 src/test/ui/or-patterns/remove-leading-vert.stderr create mode 100644 src/test/ui/or-patterns/while-parsing-this-or-pattern.rs create mode 100644 src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr delete mode 100644 src/test/ui/panic-runtime/libtest-unwinds.rs delete mode 100644 src/test/ui/panic-runtime/libtest-unwinds.stderr create mode 100644 src/test/ui/parser/assoc-type-in-type-arg.rs create mode 100644 src/test/ui/parser/assoc-type-in-type-arg.stderr create mode 100644 src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.rs create mode 100644 src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.stderr create mode 100644 src/test/ui/parser/no-const-fn-in-extern-block.rs create mode 100644 src/test/ui/parser/no-const-fn-in-extern-block.stderr delete mode 100644 src/test/ui/pattern/pattern-bindings-after-at.nll.stderr create mode 100644 src/test/ui/proc-macro/attributes-on-definitions.rs create mode 100644 src/test/ui/proc-macro/attributes-on-definitions.stderr create mode 100644 src/test/ui/proc-macro/auxiliary/attributes-on-definitions.rs create mode 100644 src/test/ui/proc-macro/auxiliary/gen-macro-rules.rs create mode 100644 src/test/ui/proc-macro/auxiliary/mixed-site-span.rs delete mode 100644 src/test/ui/proc-macro/auxiliary/test-macros-rpass.rs create mode 100644 src/test/ui/proc-macro/derive-helper-configured.rs create mode 100644 src/test/ui/proc-macro/disappearing-resolution.rs create mode 100644 src/test/ui/proc-macro/disappearing-resolution.stderr create mode 100644 src/test/ui/proc-macro/gen-macro-rules.rs create mode 100644 src/test/ui/proc-macro/macros-in-extern-derive.rs create mode 100644 src/test/ui/proc-macro/macros-in-extern-derive.stderr delete mode 100644 src/test/ui/proc-macro/macros-in-extern-rpass.rs delete mode 100644 src/test/ui/proc-macro/macros-in-extern.stderr create mode 100644 src/test/ui/proc-macro/macros-in-type.rs create mode 100644 src/test/ui/proc-macro/mixed-site-span.rs create mode 100644 src/test/ui/proc-macro/mixed-site-span.stderr create mode 100644 src/test/ui/reachable/expr_return_in_macro.rs create mode 100644 src/test/ui/reachable/expr_return_in_macro.stderr create mode 100644 src/test/ui/reify-intrinsic.rs create mode 100644 src/test/ui/reify-intrinsic.stderr create mode 100644 src/test/ui/resolve/block-with-trait-parent.rs create mode 100644 src/test/ui/resolve/issue-65025-extern-static-parent-generics.rs create mode 100644 src/test/ui/resolve/issue-65025-extern-static-parent-generics.stderr create mode 100644 src/test/ui/resolve/issue-65035-static-with-parent-generics.rs create mode 100644 src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr create mode 100644 src/test/ui/resolve/visibility-indeterminate.rs create mode 100644 src/test/ui/resolve/visibility-indeterminate.stderr delete mode 100644 src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2015.stderr delete mode 100644 src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2018.stderr delete mode 100644 src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_feature_nll.stderr delete mode 100644 src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_znll.stderr delete mode 100644 src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.no_gate.stderr delete mode 100644 src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.rs create mode 100644 src/test/ui/rfc-0107-bind-by-move-pattern-guards/former-E0008-now-pass.rs create mode 100644 src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs create mode 100644 src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs create mode 100644 src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr create mode 100644 src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/same_crate_proper.rs create mode 100644 src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs create mode 100644 src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr create mode 100644 src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs create mode 100644 src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr create mode 100644 src/test/ui/rfc-2091-track-caller/error-with-naked.rs create mode 100644 src/test/ui/rfc-2091-track-caller/error-with-naked.stderr create mode 100644 src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs create mode 100644 src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr create mode 100644 src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs create mode 100644 src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr create mode 100644 src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs create mode 100644 src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr create mode 100644 src/test/ui/rfc-2091-track-caller/only-for-fns.rs create mode 100644 src/test/ui/rfc-2091-track-caller/only-for-fns.stderr create mode 100644 src/test/ui/rfc-2091-track-caller/pass.rs create mode 100644 src/test/ui/rfc-2091-track-caller/pass.stderr create mode 100644 src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.run.stderr create mode 100644 src/test/ui/rfc-2497-if-let-chains/protect-precedences.stderr create mode 100644 src/test/ui/rfc-2565-param-attrs/attr-without-param.rs create mode 100644 src/test/ui/rfc-2565-param-attrs/attr-without-param.stderr create mode 100644 src/test/ui/rfc-2565-param-attrs/auxiliary/ident-mac.rs create mode 100644 src/test/ui/rfc-2565-param-attrs/issue-64682-dropping-first-attrs-in-impl-fns.rs delete mode 100644 src/test/ui/rfc-2565-param-attrs/param-attrs-feature-gate.rs delete mode 100644 src/test/ui/rfc-2565-param-attrs/param-attrs-feature-gate.stderr create mode 100644 src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs create mode 100644 src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr create mode 100644 src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.rs create mode 100644 src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.stderr create mode 100644 src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.rs create mode 100644 src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.stderr create mode 100644 src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs create mode 100644 src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr create mode 100644 src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs create mode 100644 src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr create mode 100644 src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs create mode 100644 src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr create mode 100644 src/test/ui/rfc1445/fn-ptr-is-structurally-matchable.rs create mode 100644 src/test/ui/rfc1445/issue-63479-match-fnptr.rs delete mode 100644 src/test/ui/rust-unstable-column-gated.rs delete mode 100644 src/test/ui/rust-unstable-column-gated.stderr create mode 100644 src/test/ui/save-analysis/issue-63663.rs create mode 100644 src/test/ui/self/arbitrary_self_types_pin_lifetime-async.rs create mode 100644 src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.nll.stderr create mode 100644 src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.rs create mode 100644 src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr create mode 100644 src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr create mode 100644 src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.rs create mode 100644 src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr create mode 100644 src/test/ui/self/elision/alias-async.rs create mode 100644 src/test/ui/self/elision/assoc-async.rs create mode 100644 src/test/ui/self/elision/lt-alias-async.rs create mode 100644 src/test/ui/self/elision/lt-assoc-async.rs create mode 100644 src/test/ui/self/elision/lt-ref-self-async.nll.stderr create mode 100644 src/test/ui/self/elision/lt-ref-self-async.rs create mode 100644 src/test/ui/self/elision/lt-ref-self-async.stderr create mode 100644 src/test/ui/self/elision/lt-self-async.rs create mode 100644 src/test/ui/self/elision/lt-struct-async.rs create mode 100644 src/test/ui/self/elision/multiple-ref-self-async.rs create mode 100644 src/test/ui/self/elision/ref-alias-async.rs create mode 100644 src/test/ui/self/elision/ref-assoc-async.rs create mode 100644 src/test/ui/self/elision/ref-mut-alias-async.rs create mode 100644 src/test/ui/self/elision/ref-mut-self-async.nll.stderr create mode 100644 src/test/ui/self/elision/ref-mut-self-async.rs create mode 100644 src/test/ui/self/elision/ref-mut-self-async.stderr create mode 100644 src/test/ui/self/elision/ref-mut-struct-async.nll.stderr create mode 100644 src/test/ui/self/elision/ref-mut-struct-async.rs create mode 100644 src/test/ui/self/elision/ref-mut-struct-async.stderr create mode 100644 src/test/ui/self/elision/ref-self-async.nll.stderr create mode 100644 src/test/ui/self/elision/ref-self-async.rs create mode 100644 src/test/ui/self/elision/ref-self-async.stderr create mode 100644 src/test/ui/self/elision/ref-struct-async.nll.stderr create mode 100644 src/test/ui/self/elision/ref-struct-async.rs create mode 100644 src/test/ui/self/elision/ref-struct-async.stderr create mode 100644 src/test/ui/self/elision/self-async.rs create mode 100644 src/test/ui/self/elision/struct-async.rs create mode 100644 src/test/ui/self/point-at-arbitrary-self-type-method.rs create mode 100644 src/test/ui/self/point-at-arbitrary-self-type-method.stderr create mode 100644 src/test/ui/self/point-at-arbitrary-self-type-trait-method.rs create mode 100644 src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr create mode 100644 src/test/ui/self/self_lifetime-async.rs create mode 100644 src/test/ui/span/type-annotations-needed-expr.rs create mode 100644 src/test/ui/span/type-annotations-needed-expr.stderr create mode 100644 src/test/ui/specialization/issue-36804.rs create mode 100644 src/test/ui/specialization/issue-63716-parse-async.rs create mode 100644 src/test/ui/specialization/non-defaulted-item-fail.rs create mode 100644 src/test/ui/specialization/non-defaulted-item-fail.stderr create mode 100644 src/test/ui/std-backtrace.rs create mode 100644 src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs create mode 100644 src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr create mode 100644 src/test/ui/suggestions/const-no-type.rs create mode 100644 src/test/ui/suggestions/const-no-type.stderr create mode 100644 src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.rs create mode 100644 src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr create mode 100644 src/test/ui/suggestions/dont-suggest-try_into-in-macros.rs create mode 100644 src/test/ui/suggestions/dont-suggest-try_into-in-macros.stderr create mode 100644 src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs create mode 100644 src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr create mode 100644 src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.rs create mode 100644 src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.stderr create mode 100644 src/test/ui/suggestions/fn-or-tuple-struct-without-args.rs create mode 100644 src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr create mode 100644 src/test/ui/suggestions/imm-ref-trait-object-literal.rs create mode 100644 src/test/ui/suggestions/imm-ref-trait-object-literal.stderr create mode 100644 src/test/ui/suggestions/imm-ref-trait-object.rs create mode 100644 src/test/ui/suggestions/imm-ref-trait-object.stderr create mode 100644 src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.fixed create mode 100644 src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.rs create mode 100644 src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr create mode 100644 src/test/ui/suggestions/issue-61226.rs create mode 100644 src/test/ui/suggestions/issue-61226.stderr create mode 100644 src/test/ui/suggestions/issue-64252-self-type.rs create mode 100644 src/test/ui/suggestions/issue-64252-self-type.stderr create mode 100644 src/test/ui/suggestions/match-needing-semi.fixed create mode 100644 src/test/ui/suggestions/match-needing-semi.rs create mode 100644 src/test/ui/suggestions/match-needing-semi.stderr create mode 100644 src/test/ui/suggestions/mismatched-types-numeric-from.rs create mode 100644 src/test/ui/suggestions/mismatched-types-numeric-from.stderr create mode 100644 src/test/ui/suggestions/mut-borrow-needed-by-trait.rs create mode 100644 src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr create mode 100644 src/test/ui/suggestions/opaque-type-error.rs create mode 100644 src/test/ui/suggestions/opaque-type-error.stderr create mode 100644 src/test/ui/suggestions/remove-as_str.rs create mode 100644 src/test/ui/suggestions/remove-as_str.stderr create mode 100644 src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.rs create mode 100644 src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr create mode 100644 src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.rs create mode 100644 src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr create mode 100644 src/test/ui/suggestions/suggest-box.fixed create mode 100644 src/test/ui/suggestions/suggest-box.rs create mode 100644 src/test/ui/suggestions/suggest-box.stderr create mode 100644 src/test/ui/suggestions/suggest-closure-return-type-1.rs create mode 100644 src/test/ui/suggestions/suggest-closure-return-type-1.stderr create mode 100644 src/test/ui/suggestions/suggest-closure-return-type-2.rs create mode 100644 src/test/ui/suggestions/suggest-closure-return-type-2.stderr create mode 100644 src/test/ui/suggestions/suggest-closure-return-type-3.rs create mode 100644 src/test/ui/suggestions/suggest-closure-return-type-3.stderr create mode 100644 src/test/ui/suggestions/vec-macro-in-pattern.fixed create mode 100644 src/test/ui/suggestions/vec-macro-in-pattern.rs create mode 100644 src/test/ui/suggestions/vec-macro-in-pattern.stderr delete mode 100644 src/test/ui/syntax-extension-minor.stderr delete mode 100644 src/test/ui/target-feature-wrong.stderr rename src/test/ui/{target-feature-gate.rs => target-feature/gate.rs} (100%) rename src/test/ui/{target-feature-gate.stderr => target-feature/gate.stderr} (91%) rename src/test/ui/{target-feature-wrong.rs => target-feature/invalid-attribute.rs} (62%) create mode 100644 src/test/ui/target-feature/invalid-attribute.stderr create mode 100644 src/test/ui/terminal-width/non-whitespace-trimming-2.rs create mode 100644 src/test/ui/terminal-width/non-whitespace-trimming-2.stderr create mode 100644 src/test/ui/terminal-width/non-whitespace-trimming-unicode.rs create mode 100644 src/test/ui/terminal-width/non-whitespace-trimming-unicode.stderr create mode 100644 src/test/ui/terminal-width/non-whitespace-trimming.rs create mode 100644 src/test/ui/terminal-width/non-whitespace-trimming.stderr create mode 100644 src/test/ui/terminal-width/whitespace-trimming-2.rs create mode 100644 src/test/ui/terminal-width/whitespace-trimming-2.stderr create mode 100644 src/test/ui/terminal-width/whitespace-trimming.rs create mode 100644 src/test/ui/terminal-width/whitespace-trimming.stderr rename src/test/ui/{test-shadowing => test-attrs}/auxiliary/test_macro.rs (100%) create mode 100644 src/test/ui/test-attrs/decl-macro-test.rs rename src/test/ui/{ => test-attrs}/inaccessible-test-modules.rs (56%) create mode 100644 src/test/ui/test-attrs/inaccessible-test-modules.stderr rename src/test/ui/{ => test-attrs}/test-allow-fail-attr.rs (100%) rename src/test/ui/{ => test-attrs}/test-attr-non-associated-functions.rs (100%) rename src/test/ui/{ => test-attrs}/test-attr-non-associated-functions.stderr (100%) rename src/test/ui/{test-shadowing => test-attrs}/test-cant-be-shadowed.rs (100%) rename src/test/ui/{ => test-attrs}/test-fn-signature-verification-for-explicit-return-type.rs (100%) rename src/test/ui/{ => test-attrs}/test-main-not-dead-attr.rs (100%) rename src/test/ui/{ => test-attrs}/test-main-not-dead.rs (100%) rename src/test/ui/{ => test-attrs}/test-on-macro.rs (100%) rename src/test/ui/{ => test-attrs}/test-on-macro.stderr (100%) rename src/test/ui/{ => test-attrs}/test-runner-hides-buried-main.rs (100%) rename src/test/ui/{ => test-attrs}/test-runner-hides-main.rs (100%) rename src/test/ui/{ => test-attrs}/test-runner-hides-start.rs (100%) rename src/test/ui/{ => test-attrs}/test-should-fail-good-message.rs (100%) rename src/test/ui/{ => test-attrs}/test-should-panic-attr.rs (100%) rename src/test/ui/{ => test-attrs}/test-should-panic-attr.stderr (100%) rename src/test/ui/{ => test-attrs}/test-vs-cfg-test.rs (100%) rename src/test/ui/{ => test-attrs}/test-warns-dead-code.rs (100%) rename src/test/ui/{ => test-attrs}/test-warns-dead-code.stderr (100%) create mode 100644 src/test/ui/test-panic-abort-disabled.rs create mode 100644 src/test/ui/test-panic-abort-disabled.stderr create mode 100644 src/test/ui/test-panic-abort.rs create mode 100644 src/test/ui/test-panic-abort.run.stdout delete mode 100644 src/test/ui/thread-local-in-ctfe.nll.stderr create mode 100644 src/test/ui/tool-attributes/diagnostic_item.rs create mode 100644 src/test/ui/tool-attributes/diagnostic_item.stderr create mode 100644 src/test/ui/tool-attributes/diagnostic_item2.rs create mode 100644 src/test/ui/tool-attributes/diagnostic_item3.rs create mode 100644 src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.rs create mode 100644 src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.stderr create mode 100644 src/test/ui/traits/reservation-impls/reservation-impl-no-use.rs create mode 100644 src/test/ui/traits/reservation-impls/reservation-impl-no-use.stderr create mode 100644 src/test/ui/traits/reservation-impls/reservation-impl-non-lattice-ok.rs create mode 100644 src/test/ui/traits/reservation-impls/reservation-impl-ok.rs create mode 100644 src/test/ui/try-block/try-block-unreachable-code-lint.rs create mode 100644 src/test/ui/try-block/try-block-unreachable-code-lint.stderr create mode 100644 src/test/ui/type-alias-impl-trait/auxiliary/foreign-crate.rs create mode 100644 src/test/ui/type-alias-impl-trait/coherence.rs create mode 100644 src/test/ui/type-alias-impl-trait/coherence.stderr create mode 100644 src/test/ui/type-alias-impl-trait/issue-53598.rs create mode 100644 src/test/ui/type-alias-impl-trait/issue-53598.stderr create mode 100644 src/test/ui/type-alias-impl-trait/issue-57700.rs create mode 100644 src/test/ui/type-alias-impl-trait/issue-57700.stderr create mode 100644 src/test/ui/type-alias-impl-trait/issue-63677-type-alias-coherence.rs create mode 100644 src/test/ui/typeck/issue-52082-type-param-shadows-existing-type.rs create mode 100644 src/test/ui/typeck/issue-52082-type-param-shadows-existing-type.stderr delete mode 100644 src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.polonius.stderr rename src/test/ui/{rfc-2166-underscore-imports => underscore-imports}/auxiliary/duplicate.rs (100%) rename src/test/ui/{rfc-2166-underscore-imports => underscore-imports}/auxiliary/underscore-imports.rs (100%) rename src/test/ui/{rfc-2166-underscore-imports => underscore-imports}/basic.rs (100%) rename src/test/ui/{rfc-2166-underscore-imports => underscore-imports}/basic.stderr (100%) create mode 100644 src/test/ui/underscore-imports/cycle.rs rename src/test/ui/{rfc-2166-underscore-imports => underscore-imports}/duplicate.rs (100%) rename src/test/ui/{rfc-2166-underscore-imports => underscore-imports}/intercrate.rs (100%) create mode 100644 src/test/ui/underscore-imports/shadow.rs create mode 100644 src/test/ui/underscore-imports/shadow.stderr rename src/test/ui/{rfc-2166-underscore-imports => underscore-imports}/unused-2018.rs (100%) rename src/test/ui/{rfc-2166-underscore-imports => underscore-imports}/unused-2018.stderr (100%) create mode 100644 src/test/ui/wrapping-int-combinations.rs delete mode 100644 src/tools/cargotest/lockfiles/iron-Cargo.lock create mode 100644 src/tools/error_index_generator/build.rs create mode 100644 src/tools/rustc-std-workspace-std/Cargo.toml create mode 100644 src/tools/rustc-std-workspace-std/README.md create mode 100644 src/tools/rustc-std-workspace-std/lib.rs create mode 100644 src/tools/tidy/src/error_codes_check.rs diff --git a/.gitattributes b/.gitattributes index f0b1c67bd0fdd..a7de7ce85593c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,7 +8,7 @@ src/etc/installer/gfx/* binary *.woff binary src/vendor/** -text -Cargo.lock -merge linguist-generated=false +Cargo.lock linguist-generated=false # Older git versions try to fix line endings on images, this prevents it. *.png binary diff --git a/.gitignore b/.gitignore index a0b491f42789a..81a472451d777 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ __pycache__/ /inst/ /llvm/ /mingw-build/ +# Created by default with `src/ci/docker/run.sh`: /obj/ /rustllvm/ /src/libcore/unicode/DerivedCoreProperties.txt @@ -38,6 +39,8 @@ __pycache__/ /src/libcore/unicode/UnicodeData.txt /src/libcore/unicode/downloaded /target/ +# Generated by compiletest for incremental: +/tmp/ tags tags.* TAGS diff --git a/.gitmodules b/.gitmodules index f64e21c5af0e4..3ff5af78097fa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -43,7 +43,7 @@ [submodule "src/llvm-project"] path = src/llvm-project url = https://github.com/rust-lang/llvm-project.git - branch = rustc/9.0-2019-07-12 + branch = rustc/9.0-2019-09-19 [submodule "src/doc/embedded-book"] path = src/doc/embedded-book url = https://github.com/rust-embedded/book.git diff --git a/.mailmap b/.mailmap index c5ecfb54fca52..a2e3c581eabba 100644 --- a/.mailmap +++ b/.mailmap @@ -69,6 +69,7 @@ David Manescu David Ross Derek Chiang Derek Chiang (Enchi Jiang) Diggory Hardy Diggory Hardy +Dustin Bensing Dylan Braithwaite Dzmitry Malyshau E. Dunham edunham @@ -117,6 +118,9 @@ Jason Toffaletti Jason Toffaletti Jauhien Piatlicki Jauhien Piatlicki Jay True Jeremy Letang +Jeremy Stucki +Jeremy Stucki +Jeremy Stucki Jethro Beekman Jihyun Yu Jihyun Yu jihyun @@ -181,12 +185,20 @@ Neil Pankey Nick Platt Nicole Mazzuca Nif Ward -Oliver Schneider oli-obk -Oliver Schneider Oliver 'ker' Schneider -Oliver Schneider Oliver Schneider -Oliver Schneider Oliver Schneider -Oliver Schneider Oliver Schneider -Oliver Schneider Oliver Schneider +Oliver Middleton +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer Ožbolt Menegatti gareins Paul Faria Paul Faria Peer Aramillo Irizar parir diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index ece8dedb0aed7..e3708bc485399 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,40 +1,3 @@ # The Rust Code of Conduct -A version of this document [can be found online](https://www.rust-lang.org/conduct.html). - -## Conduct - -**Contact**: [rust-mods@rust-lang.org](mailto:rust-mods@rust-lang.org) - -* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. -* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. -* Please be kind and courteous. There's no need to be mean or rude. -* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. -* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. -* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the Citizen Code of Conduct; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. -* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Rust moderation team][mod_team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. -* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. - -## Moderation - - -These are the policies for upholding our community's standards of conduct. If you feel that a thread needs moderation, please contact the [Rust moderation team][mod_team]. - -1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) -2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. -3. Moderators will first respond to such remarks with a warning. -4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off. -5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. -6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology. -7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed. -8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others. - -In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. - -And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. - -The enforcement policies listed above apply to all official Rust venues; including official IRC channels (#rust, #rust-internals, #rust-tools, #rust-libs, #rustc, #rust-beginners, #rust-docs, #rust-community, #rust-lang, and #cargo); GitHub repositories under rust-lang, rust-lang-nursery, and rust-lang-deprecated; and all forums under rust-lang.org (users.rust-lang.org, internals.rust-lang.org). For other projects adopting the Rust Code of Conduct, please contact the maintainers of those projects for enforcement. If you wish to use this code of conduct for your own project, consider explicitly mentioning your moderation policy or making a copy with your own moderation policy so as to avoid confusion. - -*Adapted from the [Node.js Policy on Trolling](https://blog.izs.me/2012/08/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).* - -[mod_team]: https://www.rust-lang.org/team.html#Moderation-team +The Code of Conduct for this repository [can be found online](https://www.rust-lang.org/conduct.html). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4daaa986a2dc2..c3a9a68963eb7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,7 +15,7 @@ links to the major sections: * [Helpful Links and Information](#helpful-links-and-information) If you have questions, please make a post on [internals.rust-lang.org][internals] or -hop on the [Rust Discord server][rust-discord], [Rust Zulip server][rust-zulip] or [#rust-internals][pound-rust-internals]. +hop on the [Rust Discord server][rust-discord] or [Rust Zulip server][rust-zulip]. As a reminder, all contributors are expected to follow our [Code of Conduct][coc]. @@ -25,7 +25,6 @@ to contribute to it in more detail than this document. If this is your first time contributing, the [walkthrough] chapter of the guide can give you a good example of how a typical contribution would go. -[pound-rust-internals]: https://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-internals [internals]: https://internals.rust-lang.org [rust-discord]: http://discord.gg/rust-lang [rust-zulip]: https://rust-lang.zulipchat.com @@ -404,7 +403,7 @@ If you're looking for somewhere to start, check out the [E-easy][eeasy] tag. There are a number of other ways to contribute to Rust that don't deal with this repository. -Answer questions in [#rust][pound-rust], or on [users.rust-lang.org][users], +Answer questions in the _Get Help!_ channels from the [Rust Discord server][rust-discord], on [users.rust-lang.org][users], or on [StackOverflow][so]. Participate in the [RFC process](https://github.com/rust-lang/rfcs). @@ -413,7 +412,7 @@ Find a [requested community library][community-library], build it, and publish it to [Crates.io](http://crates.io). Easier said than done, but very, very valuable! -[pound-rust]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust +[rust-discord]: https://discord.gg/rust-lang [users]: https://users.rust-lang.org/ [so]: http://stackoverflow.com/questions/tagged/rust [community-library]: https://github.com/rust-lang/rfcs/labels/A-community-library diff --git a/Cargo.lock b/Cargo.lock index 52cfa2cb1f80e..844320fff3f13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,194 +4,218 @@ name = "adler32" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" [[package]] name = "aho-corasick" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", ] [[package]] name = "alloc" version = "0.0.0" dependencies = [ - "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "core 0.0.0", - "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins", + "core", + "rand 0.7.0", + "rand_xorshift 0.2.0", ] [[package]] name = "ammonia" version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384d704f242a0a9faf793fff775a0be6ab9aa27edabffa097331d73779142520" dependencies = [ - "html5ever 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "html5ever", + "lazy_static 1.3.0", + "maplit", + "matches", + "tendril", + "url 1.7.2", ] [[package]] name = "annotate-snippets" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7021ce4924a3f25f802b2cccd1af585e39ea1a363a1aa2e72afe54b67a3a7a7" dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ansi_term", ] [[package]] name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6", ] [[package]] name = "arc-swap" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1025aeae2b664ca0ea726a89d574fe8f4e77dd712d443236ad1de00379450cf6" [[package]] name = "arena" version = "0.0.0" dependencies = [ - "rustc_data_structures 0.0.0", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_data_structures", + "smallvec", ] [[package]] name = "argon2rs" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392" dependencies = [ - "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2-rfc", + "scoped_threadpool", ] [[package]] name = "arrayref" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" [[package]] name = "arrayvec" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" dependencies = [ - "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop", ] [[package]] name = "atty" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "termion", + "winapi 0.3.6", ] +[[package]] +name = "autocfg" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" + [[package]] name = "backtrace" -version = "0.3.34" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5180c5a20655b14a819b652fd2378fa5f1697b6c9ddad3e695c2f9cedf6df4e2" dependencies = [ - "backtrace-sys 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-std-workspace-core 1.0.0", + "backtrace-sys", + "cfg-if", + "compiler_builtins", + "libc", + "rustc-demangle", + "rustc-std-workspace-core", ] [[package]] name = "backtrace-sys" version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b3a000b9c543553af61bc01cbfc403b04b5caa9e421033866f2e98061eb3e61" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-std-workspace-core 1.0.0", + "cc", + "compiler_builtins", + "libc", + "rustc-std-workspace-core", ] [[package]] name = "base64" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", ] [[package]] name = "bitflags" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" [[package]] name = "blake2-rfc" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec", + "constant_time_eq", ] [[package]] name = "block-buffer" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayref", + "byte-tools", ] [[package]] name = "bootstrap" version = "0.0.0" dependencies = [ - "build_helper 0.1.0", - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", - "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "build_helper", + "cc", + "cmake", + "filetime", + "getopts", + "lazy_static 1.3.0", + "libc", + "num_cpus", + "petgraph", + "pretty_assertions", + "serde", + "serde_json", + "time", + "toml", ] [[package]] name = "bstr" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "853b090ce0f45d0265902666bf88039ea3da825e33796716c511a1ec9c170036" dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", ] [[package]] name = "build-manifest" version = "0.1.0" dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", + "toml", ] [[package]] name = "build_const" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" [[package]] name = "build_helper" @@ -201,118 +225,152 @@ version = "0.1.0" name = "byte-tools" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" [[package]] name = "bytecount" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0017894339f586ccb943b01b9555de56770c11cda818e7e3d8bd93f4ed7f46e" dependencies = [ - "packed_simd 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "packed_simd", ] [[package]] name = "byteorder" -version = "1.2.7" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" [[package]] name = "bytes" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "either", + "iovec", ] [[package]] name = "bytesize" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "716960a18f978640f25101b5cbf1c6f6b0d3192fab36a2d98ca96f0ecbe41010" [[package]] name = "c2-chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0", + "ppv-lite86", ] [[package]] name = "cargo" -version = "0.39.0" -dependencies = [ - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo-test-macro 0.1.0", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crates-io 0.27.0", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "curl 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)", - "curl-sys 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fwdansi 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "git2-curl 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ignore 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "im-rc 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jobserver 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "opener 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-workspace-hack 1.0.0", - "rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "same-file 1.0.4 (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.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "strip-ansi-escapes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +version = "0.41.0" +dependencies = [ + "atty", + "bytesize", + "cargo-platform", + "cargo-test-macro", + "cargo-test-support", + "clap", + "core-foundation", + "crates-io", + "crossbeam-utils 0.6.5", + "crypto-hash", + "curl", + "curl-sys", + "env_logger 0.7.0", + "failure", + "filetime", + "flate2", + "fs2", + "fwdansi", + "git2", + "git2-curl", + "glob", + "hex 0.4.0", + "home", + "humantime", + "ignore", + "im-rc", + "jobserver", + "lazy_static 1.3.0", + "lazycell", + "libc", + "libgit2-sys", + "log", + "memchr", + "miow 0.3.3", + "num_cpus", + "opener", + "openssl", + "percent-encoding 2.0.0", + "pretty_env_logger", + "remove_dir_all", + "rustc-workspace-hack", + "rustfix", + "same-file", + "semver", + "serde", + "serde_ignored", + "serde_json", + "shell-escape", + "strip-ansi-escapes", + "tar", + "tempfile", + "termcolor", + "toml", + "unicode-width", + "url 2.1.0", + "walkdir", + "winapi 0.3.6", +] + +[[package]] +name = "cargo-platform" +version = "0.1.0" +dependencies = [ + "serde", ] [[package]] name = "cargo-test-macro" version = "0.1.0" +[[package]] +name = "cargo-test-support" +version = "0.1.0" +dependencies = [ + "cargo", + "cargo-test-macro", + "filetime", + "flate2", + "git2", + "glob", + "lazy_static 1.3.0", + "remove_dir_all", + "serde_json", + "tar", + "url 2.1.0", +] + [[package]] name = "cargo_metadata" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "929766d993a2fde7a0ae962ee82429069cd7b68839cd9375b98efd719df65d3a" dependencies = [ - "failure 0.1.5 (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.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "failure", + "semver", + "serde", + "serde_derive", + "serde_json", ] [[package]] @@ -323,73 +381,79 @@ version = "0.1.0" name = "cc" version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83" [[package]] name = "cfg-if" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89431bba4e6b7092fb5fcd00a6f6ca596c55cc26b2f1e6dcdd08a1f4933f66b2" dependencies = [ - "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-std-workspace-core 1.0.0", + "compiler_builtins", + "rustc-std-workspace-core", ] [[package]] name = "chalk-engine" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ec698a6f053a23bfbe646d9f2fde4b02abc19125595270a99e6f44ae0bdd1a" dependencies = [ - "chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "chalk-macros", + "rustc-hash", ] [[package]] name = "chalk-macros" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e" dependencies = [ - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11", ] [[package]] name = "chrono" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" dependencies = [ - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer", + "num-traits", + "time", ] [[package]] name = "clap" -version = "2.32.0" +version = "2.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", + "yaml-rust", ] [[package]] name = "clippy" version = "0.0.212" dependencies = [ - "cargo_metadata 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy-mini-macro-test 0.2.0", - "clippy_lints 0.0.212", - "compiletest_rs 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-workspace-hack 1.0.0", + "cargo_metadata", + "clippy-mini-macro-test", + "clippy_lints", + "compiletest_rs", + "derive-new", + "lazy_static 1.3.0", + "regex", + "rustc-workspace-hack", "rustc_tools_util 0.2.0", - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "semver", + "serde", ] [[package]] @@ -400,703 +464,787 @@ version = "0.2.0" name = "clippy_lints" version = "0.0.212" dependencies = [ - "cargo_metadata 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "if_chain 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "pulldown-cmark 0.5.3 (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.6.6 (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.92 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata", + "if_chain", + "itertools 0.8.0", + "lazy_static 1.3.0", + "matches", + "pulldown-cmark 0.6.0", + "quine-mc_cluskey", + "regex-syntax", + "semver", + "serde", + "smallvec", + "toml", + "unicode-normalization", + "url 2.1.0", ] [[package]] name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", ] [[package]] name = "cmake" version = "0.1.38" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96210eec534fc3fbfc0452a63769424eaa80205fda6cea98e5b61cb3d97bcec8" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", ] [[package]] name = "colored" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc" dependencies = [ - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11", ] [[package]] name = "commoncrypto" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" dependencies = [ - "commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "commoncrypto-sys", ] [[package]] name = "commoncrypto-sys" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "compiler_builtins" version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1c086a06d6f52f9c0d50cacdc021bfb6034ddeec9fb7e62f099f13f65472f4" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-std-workspace-core 1.0.0", + "cc", + "rustc-std-workspace-core", ] [[package]] name = "compiletest" version = "0.0.0" dependencies = [ - "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "diff", + "env_logger 0.7.0", + "getopts", + "lazy_static 1.3.0", + "libc", + "log", + "miow 0.3.3", + "regex", + "rustfix", + "serde", + "serde_json", + "walkdir", + "winapi 0.3.6", ] [[package]] name = "compiletest_rs" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb783fe7afb90ec3d3e49ccaf9196d29ab63c6ed61d4b0695839daa580ae3a3d" dependencies = [ - "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tester 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "diff", + "filetime", + "getopts", + "libc", + "log", + "miow 0.3.3", + "regex", + "rustfix", + "serde", + "serde_derive", + "serde_json", + "tempfile", + "winapi 0.3.6", ] [[package]] name = "constant_time_eq" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" [[package]] name = "core" version = "0.0.0" dependencies = [ - "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.0", ] [[package]] name = "core-foundation" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e2640d6d0bf22e82bed1b73c6aef8d5dd31e5abe6666c57e6d45e2649f4f887" dependencies = [ - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys", + "libc", ] [[package]] name = "core-foundation-sys" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" [[package]] name = "crates-io" -version = "0.27.0" +version = "0.29.0" dependencies = [ - "curl 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "url 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "curl", + "failure", + "percent-encoding 2.0.0", + "serde", + "serde_derive", + "serde_json", + "url 2.1.0", ] [[package]] name = "crc" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" dependencies = [ - "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "build_const", ] [[package]] name = "crc32fast" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91d5240c6975ef33aeb5f148f35275c25eda8e8a5f95abe421978b05b8bf192" dependencies = [ - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] name = "crossbeam-channel" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5", + "smallvec", ] [[package]] name = "crossbeam-deque" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" dependencies = [ - "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.3.1", + "crossbeam-utils 0.2.2", ] [[package]] name = "crossbeam-deque" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" +dependencies = [ + "crossbeam-epoch 0.7.2", + "crossbeam-utils 0.6.5", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" dependencies = [ - "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.7.2", + "crossbeam-utils 0.6.5", ] [[package]] name = "crossbeam-epoch" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec", + "cfg-if", + "crossbeam-utils 0.2.2", + "lazy_static 1.3.0", + "memoffset 0.2.1", + "nodrop", + "scopeguard 0.3.3", ] [[package]] name = "crossbeam-epoch" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec", + "cfg-if", + "crossbeam-utils 0.6.5", + "lazy_static 1.3.0", + "memoffset 0.5.1", + "scopeguard 1.0.0", ] [[package]] name = "crossbeam-queue" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5", ] [[package]] name = "crossbeam-utils" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" dependencies = [ - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] name = "crossbeam-utils" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" dependencies = [ - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "lazy_static 1.3.0", ] [[package]] name = "crypto-hash" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09de9ee0fc255ace04c7fa0763c9395a945c37c8292bb554f8d48361d1dcf1b4" dependencies = [ - "commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "commoncrypto", + "hex 0.3.2", + "openssl", + "winapi 0.3.6", ] [[package]] name = "curl" -version = "0.4.21" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08ad3cb89d076a36b0ce5749eec2c9964f70c0c58480ab6b75a91ec4fc206d8" dependencies = [ - "curl-sys 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys", + "libc", + "openssl-probe", + "openssl-sys", + "schannel", + "socket2", + "winapi 0.3.6", ] [[package]] name = "curl-sys" -version = "0.4.18" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9a9a4e417722876332136a00cacf92c2ceb331fab4b52b6a1ad16c6cd79255" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "libnghttp2-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "libnghttp2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", + "winapi 0.3.6", ] [[package]] name = "darling" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9158d690bc62a3a57c3e45b85e4d50de2008b39345592c64efd79345c7e24be0" dependencies = [ - "darling_core 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", - "darling_macro 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", + "darling_core", + "darling_macro", ] [[package]] name = "darling_core" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2a368589465391e127e10c9e3a08efc8df66fd49b87dc8524c764bbe7f2ef82" dependencies = [ - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv", + "ident_case", + "proc-macro2 0.4.30", + "quote 0.6.12", + "syn 0.15.35", ] [[package]] name = "darling_macro" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "244e8987bd4e174385240cde20a3657f607fb0797563c28255c353b5819a07b1" dependencies = [ - "darling_core 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "darling_core", + "quote 0.6.12", + "syn 0.15.35", ] [[package]] name = "datafrog" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69" [[package]] name = "derive-new" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ca414e896ae072546f4d789f452daaecf60ddee4c9df5dc6d5936d769e3d87c" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30", + "quote 0.6.12", + "syn 0.15.35", ] [[package]] name = "derive_more" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f57d78cf3bd45270dad4e70c21ec77a960b36c7a841ff9db76aaa775a8fb871" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30", + "quote 0.6.12", + "rustc_version", + "syn 0.15.35", ] [[package]] name = "diff" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" [[package]] name = "difference" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" [[package]] name = "digest" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" dependencies = [ - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array", ] [[package]] name = "directories" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ccc83e029c3cebb4c8155c644d34e3a070ccdb4ff90d369c74cd73f7cb3c984" dependencies = [ - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "dirs-sys", ] [[package]] name = "dirs" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c4ef5a8b902d393339e2a2c7fe573af92ce7e0ee5a3ff827b4c9ad7e07e4fa1" dependencies = [ - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "dirs-sys", ] [[package]] name = "dirs-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "937756392ec77d1f2dd9dc3ac9d69867d109a2121479d72c364e42f4cab21e2d" dependencies = [ - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "redox_users", + "winapi 0.3.6", ] [[package]] name = "dlmalloc" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f283302e035e61c23f2b86b3093e8c6273a4c3125742d6087e96ade001ca5e63" dependencies = [ - "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-std-workspace-core 1.0.0", + "compiler_builtins", + "libc", + "rustc-std-workspace-core", ] [[package]] name = "dtoa" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" [[package]] name = "either" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" [[package]] name = "elasticlunr-rs" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a99a310cd1f9770e7bf8e48810c7bcbb0e078c8fb23a8c7bcf0da4c2bf61a455" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "strum 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "strum_macros 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0", + "regex", + "serde", + "serde_derive", + "serde_json", + "strum", + "strum_macros", ] [[package]] name = "ena" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8944dc8fa28ce4a38f778bd46bf7d923fe73eed5a439398507246c8e017e6f36" dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log", ] [[package]] name = "encoding_rs" version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4155785c79f2f6701f185eb2e6b4caf0555ec03477cb4c70db67b465311620ed" dependencies = [ - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] name = "env_logger" -version = "0.5.13" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" dependencies = [ - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "humantime", + "log", + "regex", + "termcolor", ] [[package]] name = "env_logger" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ecdb7dd54465526f0a56d666e3b2dd5f3a218665a030b6e4ad9e70fa95d8fa" dependencies = [ - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "humantime", + "log", + "regex", + "termcolor", ] [[package]] name = "error-chain" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" dependencies = [ - "backtrace 0.3.34 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace", ] [[package]] name = "error_index_generator" version = "0.0.0" dependencies = [ - "rustdoc 0.0.0", + "rustdoc", + "walkdir", ] [[package]] name = "failure" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" dependencies = [ - "backtrace 0.3.34 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace", + "failure_derive", ] [[package]] name = "failure_derive" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30", + "quote 0.6.12", + "syn 0.15.35", + "synstructure 0.10.2", ] [[package]] name = "fake-simd" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" [[package]] name = "filetime" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646" dependencies = [ - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "redox_syscall", ] [[package]] name = "fixedbitset" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" [[package]] name = "flate2" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2291c165c8e703ee54ef3055ad6188e3d51108e2ded18e9f2476e774fc5ad3d4" dependencies = [ - "crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide_c_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crc32fast", + "libc", + "libz-sys", + "miniz-sys", + "miniz_oxide_c_api", ] [[package]] name = "fmt_macros" version = "0.0.0" dependencies = [ - "syntax_pos 0.0.0", + "rustc_lexer", + "syntax_pos", ] [[package]] name = "fnv" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" [[package]] name = "foreign-types" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types-shared", ] [[package]] name = "foreign-types-shared" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "fortanix-sgx-abi" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f8cbee5e872cf7db61a999a041f9bc4706ca7bf7df4cb914f53fabb1c1bc550" dependencies = [ - "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-std-workspace-core 1.0.0", + "compiler_builtins", + "rustc-std-workspace-core", ] [[package]] name = "fs2" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "winapi 0.3.6", ] [[package]] name = "fs_extra" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" [[package]] name = "fst" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d94485a00b1827b861dd9d1a2cc9764f9044d4c535514c0760a5a2012ef3399f" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", ] [[package]] name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "fuchsia-zircon-sys", ] [[package]] name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futf" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" dependencies = [ - "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "new_debug_unreachable 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mac", + "new_debug_unreachable", ] [[package]] name = "futures" version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869" [[package]] name = "futures-cpupool" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" dependencies = [ - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "num_cpus", ] [[package]] name = "fwdansi" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34dd4c507af68d37ffef962063dfa1944ce0dd4d5b82043dbab1dabe088610c3" dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", + "termcolor", ] [[package]] name = "generic-array" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" dependencies = [ - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum", ] [[package]] name = "getopts" -version = "0.2.19" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" dependencies = [ - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-std-workspace-core", + "rustc-std-workspace-std", + "unicode-width", ] [[package]] name = "getrandom" -version = "0.1.8" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" dependencies = [ - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "wasi", ] [[package]] name = "git2" -version = "0.9.2" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327d698f86a7ebdfeb86a4238ccdb004828939d3a3555b6ead679541d14e36c0" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)", - "url 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url 2.1.0", ] [[package]] name = "git2-curl" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6527e480187ce19aaf4fa6acfb7657b25628ce31cb8ffabdfca3bf731524c5" dependencies = [ - "curl 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "url 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "curl", + "git2", + "log", + "url 2.1.0", ] [[package]] name = "glob" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "globset" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef4feaabe24a0a658fd9cf4a9acf6ed284f045c77df0f49020ba3245cfb7b454" dependencies = [ - "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", ] [[package]] @@ -1107,402 +1255,532 @@ version = "0.0.0" name = "h2" version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a539b63339fbbb00e081e84b6e11bd1d9634a82d91da2984a18ac74a8823f392" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "bytes", + "fnv", + "futures", + "http", + "indexmap", + "log", + "slab", + "string", + "tokio-io", ] [[package]] name = "handlebars" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df044dd42cdb7e32f28557b661406fc0f2494be75199779998810dbc35030e0d" dependencies = [ - "hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "pest 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "hashbrown 0.5.0", + "lazy_static 1.3.0", + "log", + "pest", + "pest_derive", + "quick-error", + "regex", + "serde", + "serde_json", ] [[package]] name = "hashbrown" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1de41fb8dba9714efd92241565cdff73f78508c95697dd56787d3cba27e2353" dependencies = [ - "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-std-workspace-alloc 1.0.0", - "rustc-std-workspace-core 1.0.0", + "serde", ] [[package]] name = "hashbrown" -version = "0.5.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6587d09be37fb98a11cb08b9000a3f592451c1b1b613ca69d949160e313a430a" dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "compiler_builtins", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", ] [[package]] name = "heck" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04fa3ead4e05e51a7c806fc07271fdbde4e246a6c6d1efd52e72230b771b82" dependencies = [ - "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation", ] [[package]] name = "hex" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" + +[[package]] +name = "hex" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e" [[package]] name = "home" -version = "0.3.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3753954f7bd71f0e671afb8b5a992d1724cf43b7f95a563cd4a0bde94659ca8" dependencies = [ - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.0.0", + "winapi 0.3.6", ] [[package]] name = "html5ever" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce65ac8028cf5a287a7dbf6c4e0a6cf2dcf022ed5b167a81bae66ebf599a8b7" dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "markup5ever 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "log", + "mac", + "markup5ever", + "proc-macro2 0.4.30", + "quote 0.6.12", + "syn 0.15.35", ] [[package]] name = "http" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe67e3678f2827030e89cc4b9e7ecd16d52f132c0b940ab5005f88e821500f6a" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "fnv", + "itoa", ] [[package]] name = "http-body" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "http", + "tokio-buf", ] [[package]] name = "httparse" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" [[package]] name = "humantime" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" dependencies = [ - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error", ] [[package]] name = "hyper" version = "0.12.31" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "h2 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +checksum = "6481fff8269772d4463253ca83c788104a7305cb3fb9136bc651a6211e46e03f" +dependencies = [ + "bytes", + "futures", + "futures-cpupool", + "h2", + "http", + "http-body", + "httparse", + "iovec", + "itoa", + "log", + "net2", + "rustc_version", + "time", + "tokio", + "tokio-buf", + "tokio-executor", + "tokio-io", + "tokio-reactor", + "tokio-tcp", + "tokio-threadpool", + "tokio-timer", + "want", ] [[package]] name = "hyper-tls" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.31 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "hyper", + "native-tls", + "tokio-io", ] [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", + "unicode-bidi", + "unicode-normalization", ] [[package]] name = "idna" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", + "unicode-bidi", + "unicode-normalization", ] [[package]] name = "if_chain" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3360c7b59e5ffa2653671fb74b4741a5d343c03f331c0a4aeda42b5c2b0ec7d" [[package]] name = "ignore" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc57fa12805f367736a38541ac1a9fc6a52812a0ca959b1d4d4b640a89eb002" dependencies = [ - "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "globset 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel", + "globset", + "lazy_static 1.3.0", + "log", + "memchr", + "regex", + "same-file", + "thread_local", + "walkdir", + "winapi-util", ] [[package]] name = "im-rc" version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a0197597d095c0d11107975d3175173f810ee572c2501ff4de64f4f3f119806" dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "sized-chunks 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version", + "sized-chunks", + "typenum", ] [[package]] name = "indexmap" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" [[package]] name = "installer" version = "0.0.0" dependencies = [ - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "xz2 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "clap", + "failure", + "flate2", + "lazy_static 1.3.0", + "num_cpus", + "rayon", + "remove_dir_all", + "tar", + "walkdir", + "winapi 0.3.6", + "xz2", ] [[package]] name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "winapi 0.2.8", ] [[package]] name = "is-match" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053" [[package]] name = "itertools" version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450" dependencies = [ - "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "either", ] [[package]] name = "itertools" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" dependencies = [ - "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "either", ] [[package]] name = "itoa" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" [[package]] name = "jemalloc-sys" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bef0d4ce37578dfd80b466e3d8324bd9de788e249f1accebb0c472ea4b52bdc" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "fs_extra", + "libc", ] [[package]] name = "jobserver" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f74e73053eaf95399bf926e48fc7a2a3ce50bd0eaaa2357d391e95b2dcdd4f10" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "log", + "rand 0.7.0", ] [[package]] name = "json" version = "0.11.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be" + +[[package]] +name = "jsonrpc-client-transports" +version = "13.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39577db48b004cffb4c5b8e5c9b993c177c52599ecbee88711e815acf65144db" +dependencies = [ + "failure", + "futures", + "jsonrpc-core", + "jsonrpc-pubsub", + "jsonrpc-server-utils", + "log", + "parity-tokio-ipc", + "serde", + "serde_json", + "tokio", + "url 1.7.2", +] [[package]] name = "jsonrpc-core" -version = "12.0.0" +version = "13.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd42951eb35079520ee29b7efbac654d85821b397ef88c8151600ef7e2d00217" +dependencies = [ + "futures", + "log", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "jsonrpc-core-client" +version = "13.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f047c10738edee7c3c6acf5241a0ce33df32ef9230c1a7fb03e4a77ee72c992f" +dependencies = [ + "jsonrpc-client-transports", +] + +[[package]] +name = "jsonrpc-derive" +version = "13.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29f9149f785deaae92a4c834a9a1a83a4313b8cfedccf15362cd4cf039a64501" +dependencies = [ + "proc-macro-crate", + "proc-macro2 0.4.30", + "quote 0.6.12", + "syn 0.15.35", +] + +[[package]] +name = "jsonrpc-ipc-server" +version = "13.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "256c5e4292c17b4c2ecdf542299dc8e9d6b3939c075c54825570ad9317fe5751" dependencies = [ - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core", + "jsonrpc-server-utils", + "log", + "parity-tokio-ipc", + "parking_lot 0.9.0", + "tokio-service", +] + +[[package]] +name = "jsonrpc-pubsub" +version = "13.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2c08b444cc0ed70263798834343d0ac875e664257df8079160f23ac1ea79446" +dependencies = [ + "jsonrpc-core", + "log", + "parking_lot 0.9.0", + "serde", +] + +[[package]] +name = "jsonrpc-server-utils" +version = "13.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44561bfdd31401bad790527f1e951dde144f2341ddc3e1b859d32945e1a34eff" +dependencies = [ + "bytes", + "globset", + "jsonrpc-core", + "lazy_static 1.3.0", + "log", + "num_cpus", + "tokio", + "tokio-codec", + "unicase 2.5.1", ] [[package]] name = "kernel32-sys" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8", + "winapi-build", ] [[package]] name = "lazy_static" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" [[package]] name = "lazy_static" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" [[package]] name = "lazycell" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" [[package]] name = "libc" -version = "0.2.60" +version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" dependencies = [ - "rustc-std-workspace-core 1.0.0", + "rustc-std-workspace-core", ] [[package]] name = "libflate" version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90c6f86f4b0caa347206f916f8b687b51d77c6ef8ff18d52dd007491fd580529" dependencies = [ - "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "adler32", + "byteorder", + "crc32fast", + "rle-decode-fast", + "take_mut", ] [[package]] name = "libgit2-sys" -version = "0.8.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2078aec6f4b16d1b89f6a72e4f6eb1e75ffa85312023291e89c6d3087bc8fb" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "libssh2-sys 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", ] [[package]] name = "libnghttp2-sys" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75d7966bda4730b722d1eab8e668df445368a24394bae9fc1e8dc0ab3dbe4f4" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", ] [[package]] name = "libssh2-sys" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126a1f4078368b163bfdee65fbab072af08a1b374a5551b21e87ade27b1fbf9d" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", ] [[package]] name = "libz-sys" version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "pkg-config", + "vcpkg", ] [[package]] @@ -1513,916 +1791,1109 @@ version = "0.1.0" name = "lock_api" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54" dependencies = [ - "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref", + "scopeguard 0.3.3", +] + +[[package]] +name = "lock_api" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" +dependencies = [ + "scopeguard 1.0.0", ] [[package]] name = "log" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" dependencies = [ - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] name = "log_settings" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19af41f0565d7c19b2058153ad0b42d4d5ce89ec4dbf06ed6741114a8b63e7cd" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0", ] [[package]] name = "lsp-codec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "169d737ad89cf8ddd82d1804d9122f54568c49377665157277cc90d747b1d31a" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "serde_json", + "tokio-codec", ] [[package]] name = "lsp-types" -version = "0.57.2" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe3edefcd66dde1f7f1df706f46520a3c93adc5ca4bc5747da6621195e894efd" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "serde", + "serde_json", + "serde_repr", + "url 2.1.0", ] [[package]] name = "lzma-sys" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b5c59c57cc4d39e7999f50431aa312ea78af7c93b23fbb0c3567bd672e7f35" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "pkg-config", ] [[package]] name = "mac" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" [[package]] name = "macro-utils" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2c4deaccc2ead6a28c16c0ba82f07d52b6475397415ce40876e559b0b0ea510" [[package]] name = "maplit" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43" [[package]] name = "markup5ever" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1af46a727284117e09780d05038b1ce6fc9c76cc6df183c3dae5a8955a25e21" dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "string_cache_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log", + "phf", + "phf_codegen", + "serde", + "serde_derive", + "serde_json", + "string_cache", + "string_cache_codegen", + "tendril", ] [[package]] name = "matches" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "mdbook" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ammonia 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "elasticlunr-rs 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "handlebars 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pulldown-cmark 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "toml-query 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +checksum = "949bb2acb2cff9fa5c375cf9c43e70b3dba0a974d9fe01c31285d7a84d2a0fa2" +dependencies = [ + "ammonia", + "chrono", + "clap", + "elasticlunr-rs", + "env_logger 0.6.2", + "error-chain", + "handlebars", + "itertools 0.8.0", + "lazy_static 1.3.0", + "log", + "memchr", + "open", + "pulldown-cmark 0.5.3", + "regex", + "serde", + "serde_derive", + "serde_json", + "shlex", + "tempfile", + "toml", + "toml-query", ] [[package]] name = "mdbook-linkcheck" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77d1f0ba4d1e6b86fa18e8853d026d7d76a97eb7eb5eb052ed80901e43b7fc10" dependencies = [ - "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mdbook 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pulldown-cmark 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "reqwest 0.9.11 (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.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2", + "failure", + "log", + "mdbook", + "memchr", + "pulldown-cmark 0.5.3", + "rayon", + "regex", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "structopt 0.2.18", + "url 1.7.2", ] [[package]] name = "measureme" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d09de7dafa3aa334bc806447c7e4de69419723312f4b88b80b561dea66601ce8" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "memmap", + "rustc-hash", ] [[package]] name = "memchr" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" [[package]] name = "memmap" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "winapi 0.3.6", ] [[package]] name = "memoffset" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" [[package]] name = "memoffset" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version", ] [[package]] name = "mime" version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e27ca21f40a310bd06d9031785f4801710d566c184a6e15bad4f1d9b65f9425" dependencies = [ - "unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 2.5.1", ] [[package]] name = "mime_guess" version = "2.0.0-alpha.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30de2e4613efcba1ec63d8133f344076952090c122992a903359be5a4f99c3ed" dependencies = [ - "mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "mime", + "phf", + "phf_codegen", + "unicase 1.4.2", ] [[package]] name = "minifier" version = "0.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70bf0db2475f5e627787da77ca52fe33c294063f49f4134b8bc662eedb5e7332" dependencies = [ - "macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "macro-utils", ] [[package]] name = "miniz-sys" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0300eafb20369952951699b68243ab4334f4b10a88f411c221d444b36c40e649" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", ] [[package]] name = "miniz_oxide" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ad30a47319c16cde58d0314f5d98202a80c9083b5f61178457403dfb14e509c" dependencies = [ - "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "adler32", ] [[package]] name = "miniz_oxide_c_api" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28edaef377517fd9fe3e085c37d892ce7acd1fbeab9239c5a36eec352d8a8b7e" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "crc", + "libc", + "miniz_oxide", ] [[package]] name = "mio" version = "0.6.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "lazycell", + "libc", + "log", + "miow 0.2.1", + "net2", + "slab", + "winapi 0.2.8", ] [[package]] name = "mio-named-pipes" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e374eff525ce1c5b7687c4cef63943e7686524a387933ad27ca7ec43779cb3" dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log", + "mio", + "miow 0.3.3", + "winapi 0.3.6", ] [[package]] name = "mio-uds" version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" dependencies = [ - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec", + "libc", + "mio", ] [[package]] name = "miow" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", ] [[package]] name = "miow" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" dependencies = [ - "socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2", + "winapi 0.3.6", ] [[package]] name = "miri" version = "0.1.0" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "directories 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-workspace-hack 1.0.0", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "cargo_metadata", + "colored", + "compiletest_rs", + "directories", + "env_logger 0.6.2", + "getrandom", + "hex 0.3.2", + "log", + "num-traits", + "rand 0.7.0", + "rustc-workspace-hack", + "rustc_version", + "shell-escape", + "vergen", ] [[package]] name = "native-tls" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", ] [[package]] name = "net2" version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" dependencies = [ - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "winapi 0.3.6", ] [[package]] name = "new_debug_unreachable" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40f005c60db6e03bae699e414c58bf9aa7ea02a2d0b9bfbcf19286cc4c82b30" [[package]] name = "nodrop" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "num-derive" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" [[package]] name = "num-integer" version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits", ] [[package]] name = "num-traits" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" [[package]] name = "num_cpus" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] +[[package]] +name = "once_cell" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6a04cb71e910d0034815600180f62a95bf6e67942d7ab52a166a68c7d7e9cd0" + [[package]] name = "open" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c281318d992e4432cfa799969467003d05921582a7489a8325e37f8a450d5113" [[package]] name = "opener" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998c59e83d9474c01127a96e023b7a04bb061dd286bf8bb939d31dc8d31a7448" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6", ] [[package]] name = "openssl" version = "0.10.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7bd7ca4cce6dbdc77e7c1230682740d307d1218a87fb0349a571272be749f9" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "cfg-if", + "foreign-types", + "lazy_static 1.3.0", + "libc", + "openssl-sys", ] [[package]] name = "openssl-probe" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-src" -version = "111.3.0+1.1.1c" +version = "111.6.0+1.1.1d" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9c2da1de8a7a3f860919c01540b03a6db16de042405a8a07a5e9d0b4b825d9c" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", ] [[package]] name = "openssl-sys" version = "0.9.43" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c86834957dd5b915623e94f2f4ab2c70dd8f6b70679824155d5ae21dbd495d" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-src 111.3.0+1.1.1c (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "openssl-src", + "pkg-config", + "rustc_version", + "vcpkg", ] [[package]] name = "ordermap" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" [[package]] name = "ordslice" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd20eec3dbe4376829cb7d80ae6ac45e0a766831dca50202ff2d40db46a8a024" [[package]] name = "owning_ref" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" dependencies = [ - "stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "stable_deref_trait", ] [[package]] name = "packed_simd" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25d36de864f7218ec5633572a800109bbe5a1cc8d9d95a967f3daf93ea7e6ddc" dependencies = [ - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] name = "panic_abort" version = "0.0.0" dependencies = [ - "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "core 0.0.0", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins", + "core", + "libc", ] [[package]] name = "panic_unwind" version = "0.0.0" dependencies = [ - "alloc 0.0.0", - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "core 0.0.0", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "unwind 0.0.0", + "alloc", + "cfg-if", + "compiler_builtins", + "core", + "libc", + "unwind", +] + +[[package]] +name = "parity-tokio-ipc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8281bf4f1d6429573f89589bf68d89451c46750977a8264f8ea3edbabeba7947" +dependencies = [ + "bytes", + "futures", + "log", + "mio-named-pipes", + "miow 0.3.3", + "rand 0.7.0", + "tokio", + "tokio-named-pipes", + "tokio-uds", + "winapi 0.3.6", ] [[package]] name = "parking_lot" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" dependencies = [ - "lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api 0.1.3", + "parking_lot_core 0.4.0", +] + +[[package]] +name = "parking_lot" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" +dependencies = [ + "lock_api 0.3.1", + "parking_lot_core 0.6.2", + "rustc_version", ] [[package]] name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "rand 0.6.1", + "rustc_version", + "smallvec", + "winapi 0.3.6", +] + +[[package]] +name = "parking_lot_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" +dependencies = [ + "cfg-if", + "cloudabi", + "libc", + "redox_syscall", + "rustc_version", + "smallvec", + "winapi 0.3.6", ] [[package]] name = "percent-encoding" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" [[package]] name = "percent-encoding" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4f28a6faf4ffea762ba8f4baef48c61a6db348647c73095034041fc79dd954" [[package]] name = "pest" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54f0c72a98d8ab3c99560bfd16df8059cc10e1f9a8e83e6e3b97718dd766e9c3" dependencies = [ - "ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ucd-trie", ] [[package]] name = "pest_derive" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" dependencies = [ - "pest 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pest_generator 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pest", + "pest_generator", ] [[package]] name = "pest_generator" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63120576c4efd69615b5537d3d052257328a4ca82876771d6944424ccfd9f646" dependencies = [ - "pest 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pest_meta 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "pest", + "pest_meta", + "proc-macro2 0.4.30", + "quote 0.6.12", + "syn 0.15.35", ] [[package]] name = "pest_meta" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5a3492a4ed208ffc247adcdcc7ba2a95be3104f58877d0d02f0df39bf3efb5e" dependencies = [ - "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pest 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "maplit", + "pest", + "sha-1", ] [[package]] name = "petgraph" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f" dependencies = [ - "fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "fixedbitset", + "ordermap", ] [[package]] name = "phf" version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18" dependencies = [ - "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared", ] [[package]] name = "phf_codegen" version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e" dependencies = [ - "phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_generator", + "phf_shared", ] [[package]] name = "phf_generator" version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" dependencies = [ - "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared", + "rand 0.6.1", ] [[package]] name = "phf_shared" version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" dependencies = [ - "siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "siphasher", + "unicase 1.4.2", ] [[package]] name = "pkg-config" version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" [[package]] name = "polonius-engine" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50fa9dbfd0d3d60594da338cfe6f94028433eecae4b11b7e83fd99759227bbfe" dependencies = [ - "datafrog 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "datafrog", + "log", + "rustc-hash", ] [[package]] name = "ppv-lite86" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" [[package]] name = "precomputed-hash" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "pretty_assertions" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6" dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ansi_term", + "difference", ] [[package]] name = "pretty_env_logger" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8b3f4e0475def7d9c2e5de8e5a1306949849761e107b360d03e98eafaffd61" +dependencies = [ + "chrono", + "env_logger 0.6.2", + "log", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" dependencies = [ - "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "toml", +] + +[[package]] +name = "proc-macro-error" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097" +dependencies = [ + "proc-macro2 1.0.3", + "quote 1.0.2", + "syn 1.0.5", ] [[package]] name = "proc-macro2" version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0", +] + +[[package]] +name = "proc-macro2" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8" +dependencies = [ + "unicode-xid 0.2.0", ] [[package]] name = "proc_macro" version = "0.0.0" +dependencies = [ + "std", +] [[package]] name = "profiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "core 0.0.0", + "cc", + "compiler_builtins", + "core", ] [[package]] name = "pulldown-cmark" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77043da1282374688ee212dc44b3f37ff929431de9c9adc3053bd3cee5630357" +dependencies = [ + "bitflags", + "getopts", + "memchr", + "unicase 2.5.1", +] + +[[package]] +name = "pulldown-cmark" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b0ad0d4c1702965ee6bb5b4ff5e71f83850b497d497e9444302987bf9e26a4" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "getopts", + "memchr", + "unicase 2.5.1", ] [[package]] name = "punycode" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ddd112cca70a4d30883b2d21568a1d376ff8be4758649f64f973c6845128ad3" [[package]] name = "quick-error" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" [[package]] name = "quine-mc_cluskey" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" [[package]] name = "quote" version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +dependencies = [ + "proc-macro2 1.0.3", ] [[package]] name = "racer" -version = "2.1.25" +version = "2.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acc70369054bad4ad0c16a3f45cd73e0695361a3af35c7b465e619ac2674f064" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-span 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "clap", + "derive_more", + "env_logger 0.6.2", + "humantime", + "lazy_static 1.3.0", + "log", + "rls-span", + "rustc-ap-syntax", ] [[package]] name = "rand" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae9d223d52ae411a33cf7e54ec6034ec165df296ccd23533d671a28252b6f66a" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi", + "fuchsia-zircon", + "libc", + "rand_chacha 0.1.0", + "rand_core 0.3.0", + "rand_hc 0.1.0", + "rand_isaac", + "rand_pcg", + "rand_xorshift 0.1.0", + "rustc_version", + "winapi 0.3.6", ] [[package]] name = "rand" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" dependencies = [ - "getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", + "libc", + "rand_chacha 0.2.1", + "rand_core 0.5.0", + "rand_hc 0.2.0", ] [[package]] name = "rand_chacha" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771b009e3a508cb67e8823dda454aaa5368c7bc1c16829fb77d3e980440dd34a" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0", + "rustc_version", ] [[package]] name = "rand_chacha" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" dependencies = [ - "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "c2-chacha", + "rand_core 0.5.0", ] [[package]] name = "rand_core" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" [[package]] name = "rand_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" [[package]] name = "rand_core" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" dependencies = [ - "getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", ] [[package]] name = "rand_hc" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0", ] [[package]] name = "rand_isaac" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0", ] [[package]] name = "rand_os" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.0", + "rdrand", + "winapi 0.3.6", ] [[package]] name = "rand_pcg" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0", + "rustc_version", ] [[package]] name = "rand_xorshift" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effa3fcaa47e18db002bdde6060944b6d2f9cfd8db471c30e873448ad9187be3" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0", ] [[package]] name = "rand_xorshift" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" dependencies = [ - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0", ] [[package]] name = "rayon" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123" dependencies = [ - "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.1", + "either", + "rayon-core", ] [[package]] name = "rayon-core" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b" dependencies = [ - "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.1", + "crossbeam-queue", + "crossbeam-utils 0.6.5", + "lazy_static 1.3.0", + "num_cpus", ] [[package]] name = "rdrand" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0", ] [[package]] name = "redox_syscall" version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "679da7508e9a6390aeaf7fbd02a800fdc64b73fe2204dd2c8ae66d22d9d5ad5d" [[package]] name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" dependencies = [ - "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall", ] [[package]] name = "redox_users" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fe5204c3a17e97dde73f285d49be585df59ed84b50a872baf416e73b62c3828" dependencies = [ - "argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "argon2rs", + "failure", + "rand_os", + "redox_syscall", ] [[package]] name = "regex" version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58" dependencies = [ - "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", + "utf8-ranges", ] [[package]] name = "regex-syntax" version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" dependencies = [ - "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ucd-util", ] [[package]] @@ -2437,526 +2908,603 @@ version = "0.1.0" name = "remove_dir_all" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6", ] [[package]] name = "reqwest" version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.31 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libflate 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", - "mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", +checksum = "e542d9f077c126af32536b6aacc75bb7325400eab8cd0743543be5d91660780d" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures", + "http", + "hyper", + "hyper-tls", + "libflate", + "log", + "mime", + "mime_guess", + "native-tls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-executor", + "tokio-io", + "tokio-threadpool", + "tokio-timer", + "url 1.7.2", + "uuid", ] [[package]] name = "rle-decode-fast" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" [[package]] name = "rls" -version = "1.38.0" -dependencies = [ - "cargo 0.39.0", - "cargo_metadata 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy_lints 0.0.212", - "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lsp-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lsp-types 0.57.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ordslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "racer 2.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-analysis 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-rustc 0.6.0", - "rls-span 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-vfs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-workspace-hack 1.0.0", +version = "1.39.0" +dependencies = [ + "cargo", + "cargo_metadata", + "clippy_lints", + "crossbeam-channel", + "difference", + "env_logger 0.6.2", + "failure", + "futures", + "heck", + "home", + "itertools 0.8.0", + "jsonrpc-core", + "lazy_static 1.3.0", + "log", + "lsp-codec", + "lsp-types", + "num_cpus", + "ordslice", + "racer", + "rand 0.6.1", + "rayon", + "regex", + "rls-analysis", + "rls-data", + "rls-ipc", + "rls-rustc", + "rls-span", + "rls-vfs", + "rustc-serialize", + "rustc-workspace-hack", "rustc_tools_util 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfmt-nightly 1.4.4", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-process 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfmt-nightly", + "serde", + "serde_derive", + "serde_ignored", + "serde_json", + "tempfile", + "tokio", + "tokio-process", + "tokio-timer", + "toml", + "url 2.1.0", + "walkdir", ] [[package]] name = "rls-analysis" version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c0d208ad66717501222c74b42d9e823a7612592e85ed78b04074c8f58c0be0a" dependencies = [ - "derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "fst 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", - "json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-span 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "derive-new", + "fst", + "itertools 0.7.8", + "json", + "log", + "rls-data", + "rls-span", + "serde", + "serde_json", ] [[package]] name = "rls-data" version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76c72ea97e045be5f6290bb157ebdc5ee9f2b093831ff72adfaf59025cf5c491" +dependencies = [ + "rls-span", + "serde", +] + +[[package]] +name = "rls-ipc" +version = "0.1.0" dependencies = [ - "rls-span 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core", + "jsonrpc-core-client", + "jsonrpc-derive", + "jsonrpc-ipc-server", + "rls-data", + "serde", ] [[package]] name = "rls-rustc" version = "0.6.0" +dependencies = [ + "clippy_lints", + "env_logger 0.6.2", + "failure", + "futures", + "log", + "rand 0.6.1", + "rls-data", + "rls-ipc", + "serde", + "tokio", +] [[package]] name = "rls-span" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1cb4694410d8d2ce43ccff3682f1c782158a018d5a9a92185675677f7533eb3" dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] [[package]] name = "rls-vfs" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce4b57b25b4330ed5ec14028fc02141e083ddafda327e7eb598dc0569c8c83c9" dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-span 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log", + "rls-span", ] [[package]] name = "rustbook" version = "0.1.0" dependencies = [ - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "mdbook 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mdbook-linkcheck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap", + "failure", + "mdbook", + "mdbook-linkcheck", ] [[package]] name = "rustc" version = "0.0.0" dependencies = [ - "arena 0.0.0", - "backtrace 0.3.34 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "chalk-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fmt_macros 0.0.0", - "graphviz 0.0.0", - "jobserver 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "measureme 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "polonius-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-rayon-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_apfloat 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_fs_util 0.0.0", - "rustc_macros 0.1.0", - "rustc_target 0.0.0", - "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serialize 0.0.0", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syntax 0.0.0", - "syntax_pos 0.0.0", + "arena", + "backtrace", + "bitflags", + "byteorder", + "chalk-engine", + "fmt_macros", + "graphviz", + "jobserver", + "log", + "measureme", + "num_cpus", + "parking_lot 0.9.0", + "polonius-engine", + "rustc-rayon 0.3.0", + "rustc-rayon-core 0.3.0", + "rustc_apfloat", + "rustc_data_structures", + "rustc_errors", + "rustc_fs_util", + "rustc_index", + "rustc_macros", + "rustc_target", + "scoped-tls", + "serialize", + "smallvec", + "syntax", + "syntax_pos", ] [[package]] name = "rustc-ap-arena" -version = "546.0.0" +version = "606.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a623fd4805842e9bd0bb6e6dace63efede0ee22de4522a0b03b7c3d15a22f009" dependencies = [ - "rustc-ap-rustc_data_structures 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures", + "smallvec", ] [[package]] name = "rustc-ap-graphviz" -version = "546.0.0" +version = "606.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee549ade784b444ef10c0240c3487ed785aa65d711071f7984246b15329a17b6" [[package]] name = "rustc-ap-rustc_data_structures" -version = "546.0.0" +version = "606.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca545744a5a9b42e3d0410d6290d40de96dd567253fe77f310c1de4afd213dd4" dependencies = [ - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jobserver 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-graphviz 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-rayon-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "crossbeam-utils 0.6.5", + "ena", + "indexmap", + "jobserver", + "lazy_static 1.3.0", + "log", + "parking_lot 0.9.0", + "rustc-ap-graphviz", + "rustc-ap-rustc_index", + "rustc-ap-serialize", + "rustc-hash", + "rustc-rayon 0.2.0", + "rustc-rayon-core 0.2.0", + "smallvec", + "stable_deref_trait", ] [[package]] name = "rustc-ap-rustc_errors" -version = "546.0.0" +version = "606.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6967a41ed38ef4bce0f559fe9a4801d8ba12ac032f40a12a55e72f79d52c9bb" dependencies = [ - "annotate-snippets 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "annotate-snippets", + "atty", + "log", + "rustc-ap-rustc_data_structures", + "rustc-ap-serialize", + "rustc-ap-syntax_pos", + "term_size", + "termcolor", + "unicode-width", +] + +[[package]] +name = "rustc-ap-rustc_index" +version = "606.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "457a5c204ae2fdaa5bdb5b196e58ca59896870d80445fe423063c9453496e3ea" +dependencies = [ + "rustc-ap-serialize", + "smallvec", ] [[package]] name = "rustc-ap-rustc_lexer" -version = "546.0.0" +version = "606.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed0c064676f8a08e42a36b0d4e4a102465fb0f4b75e11436cb7f66d2c3fa7139" +dependencies = [ + "unicode-xid 0.2.0", +] [[package]] name = "rustc-ap-rustc_macros" -version = "546.0.0" +version = "606.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2d77e46159c5288c585decbcdc9d742889c65e307c31e104c7a36d63fe1f5d0" dependencies = [ - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.0", + "proc-macro2 0.4.30", + "quote 0.6.12", + "syn 0.15.35", + "synstructure 0.10.2", ] [[package]] name = "rustc-ap-rustc_target" -version = "546.0.0" +version = "606.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ca895350b0de14d064b499168c93fa183958d5462eb042c927d93623e41ec1" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "log", + "rustc-ap-rustc_data_structures", + "rustc-ap-rustc_index", + "rustc-ap-serialize", + "rustc-ap-syntax_pos", ] [[package]] name = "rustc-ap-serialize" -version = "546.0.0" +version = "606.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92679240e86f4583cc05f8dcf6439bdab87bac9e6555718469176de9bd52ba20" dependencies = [ - "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap", + "smallvec", ] [[package]] name = "rustc-ap-syntax" -version = "546.0.0" +version = "606.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a0c30f8e38c847dbfd9e2f1e472ab06d0bd0a23ab53ae4c5a44912842ce834e" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_errors 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_lexer 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_macros 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_target 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "lazy_static 1.3.0", + "log", + "rustc-ap-rustc_data_structures", + "rustc-ap-rustc_errors", + "rustc-ap-rustc_index", + "rustc-ap-rustc_lexer", + "rustc-ap-rustc_target", + "rustc-ap-serialize", + "rustc-ap-syntax_pos", + "scoped-tls", + "smallvec", ] [[package]] name = "rustc-ap-syntax_pos" -version = "546.0.0" +version = "606.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdaa0fb40143b4b878256ac4e2b498885daafc269502504d91929eab4744bf4" dependencies = [ - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-arena 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_macros 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "rustc-ap-arena", + "rustc-ap-rustc_data_structures", + "rustc-ap-rustc_index", + "rustc-ap-rustc_macros", + "rustc-ap-serialize", + "scoped-tls", + "unicode-width", ] [[package]] name = "rustc-demangle" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" dependencies = [ - "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-std-workspace-core 1.0.0", + "compiler_builtins", + "rustc-std-workspace-core", ] [[package]] name = "rustc-hash" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", ] [[package]] name = "rustc-main" version = "0.0.0" dependencies = [ - "jemalloc-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_codegen_ssa 0.0.0", - "rustc_driver 0.0.0", - "rustc_target 0.0.0", + "jemalloc-sys", + "rustc_codegen_ssa", + "rustc_driver", + "rustc_target", ] [[package]] name = "rustc-rayon" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d2e07e19601f21c59aad953c2632172ba70cb27e685771514ea66e4062b3363" dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-rayon-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.2.0", + "either", + "rustc-rayon-core 0.2.0", +] + +[[package]] +name = "rustc-rayon" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f32767f90d938f1b7199a174ef249ae1924f6e5bbdb9d112fea141e016f25b3a" +dependencies = [ + "crossbeam-deque 0.7.1", + "either", + "rustc-rayon-core 0.3.0", ] [[package]] name = "rustc-rayon-core" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79d38ca7cbc22fa59f09d8534ea4b27f67b0facf0cbe274433aceea227a02543" dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.2.0", + "lazy_static 1.3.0", + "libc", + "num_cpus", +] + +[[package]] +name = "rustc-rayon-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2427831f0053ea3ea73559c8eabd893133a51b251d142bacee53c62a288cb3" +dependencies = [ + "crossbeam-deque 0.7.1", + "crossbeam-queue", + "crossbeam-utils 0.6.5", + "lazy_static 1.3.0", + "num_cpus", ] [[package]] name = "rustc-serialize" version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" [[package]] name = "rustc-std-workspace-alloc" -version = "1.0.0" +version = "1.99.0" dependencies = [ - "alloc 0.0.0", + "alloc", ] [[package]] name = "rustc-std-workspace-core" -version = "1.0.0" +version = "1.99.0" dependencies = [ - "core 0.0.0", + "core", ] [[package]] -name = "rustc-workspace-hack" -version = "1.0.0" +name = "rustc-std-workspace-std" +version = "1.99.0" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "std", ] [[package]] -name = "rustc_apfloat" -version = "0.0.0" +name = "rustc-workspace-hack" +version = "1.0.0" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5", + "serde", + "serde_json", + "smallvec", + "url 2.1.0", + "winapi 0.3.6", ] [[package]] -name = "rustc_asan" +name = "rustc_apfloat" version = "0.0.0" dependencies = [ - "alloc 0.0.0", - "build_helper 0.1.0", - "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "core 0.0.0", + "bitflags", + "smallvec", ] [[package]] -name = "rustc_ast_borrowck" +name = "rustc_asan" version = "0.0.0" dependencies = [ - "graphviz 0.0.0", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", + "alloc", + "build_helper", + "cmake", + "compiler_builtins", + "core", ] [[package]] name = "rustc_codegen_llvm" version = "0.0.0" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_llvm 0.0.0", - "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_llvm", ] [[package]] name = "rustc_codegen_ssa" version = "0.0.0" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "jobserver 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_apfloat 0.0.0", - "rustc_codegen_utils 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_fs_util 0.0.0", - "rustc_incremental 0.0.0", - "rustc_target 0.0.0", - "serialize 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", - "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "cc", + "jobserver", + "libc", + "log", + "memmap", + "num_cpus", + "rustc", + "rustc_apfloat", + "rustc_codegen_utils", + "rustc_data_structures", + "rustc_errors", + "rustc_fs_util", + "rustc_incremental", + "rustc_index", + "rustc_target", + "serialize", + "syntax", + "syntax_pos", + "tempfile", ] [[package]] name = "rustc_codegen_utils" version = "0.0.0" dependencies = [ - "flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "punycode 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_data_structures 0.0.0", - "rustc_metadata 0.0.0", - "rustc_target 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", + "log", + "punycode", + "rustc", + "rustc-demangle", + "rustc_data_structures", + "rustc_metadata", + "rustc_target", + "syntax", + "syntax_pos", ] [[package]] name = "rustc_data_structures" version = "0.0.0" dependencies = [ - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "graphviz 0.0.0", - "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jobserver 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-rayon-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serialize 0.0.0", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "crossbeam-utils 0.6.5", + "ena", + "graphviz", + "indexmap", + "jobserver", + "lazy_static 1.3.0", + "log", + "parking_lot 0.9.0", + "rustc-hash", + "rustc-rayon 0.3.0", + "rustc-rayon-core 0.3.0", + "rustc_index", + "serialize", + "smallvec", + "stable_deref_trait", ] [[package]] name = "rustc_driver" version = "0.0.0" dependencies = [ - "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", - "graphviz 0.0.0", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_ast_borrowck 0.0.0", - "rustc_codegen_utils 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_interface 0.0.0", - "rustc_metadata 0.0.0", - "rustc_mir 0.0.0", - "rustc_save_analysis 0.0.0", - "rustc_target 0.0.0", - "serialize 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", + "env_logger 0.7.0", + "graphviz", + "lazy_static 1.3.0", + "log", + "rustc", + "rustc_codegen_utils", + "rustc_data_structures", + "rustc_errors", + "rustc_interface", + "rustc_metadata", + "rustc_mir", + "rustc_plugin", + "rustc_plugin_impl", + "rustc_save_analysis", + "rustc_target", + "serialize", + "syntax", + "syntax_pos", ] [[package]] name = "rustc_errors" version = "0.0.0" dependencies = [ - "annotate-snippets 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_data_structures 0.0.0", - "serialize 0.0.0", - "syntax_pos 0.0.0", - "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "annotate-snippets", + "atty", + "log", + "rustc_data_structures", + "serialize", + "syntax_pos", + "term_size", + "termcolor", + "unicode-width", ] [[package]] @@ -2967,225 +3515,243 @@ version = "0.0.0" name = "rustc_incremental" version = "0.0.0" dependencies = [ - "graphviz 0.0.0", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_fs_util 0.0.0", - "serialize 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", + "graphviz", + "log", + "rand 0.7.0", + "rustc", + "rustc_data_structures", + "rustc_fs_util", + "serialize", + "syntax", + "syntax_pos", +] + +[[package]] +name = "rustc_index" +version = "0.0.0" +dependencies = [ + "serialize", + "smallvec", ] [[package]] name = "rustc_interface" version = "0.0.0" dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_ast_borrowck 0.0.0", - "rustc_codegen_ssa 0.0.0", - "rustc_codegen_utils 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_incremental 0.0.0", - "rustc_lint 0.0.0", - "rustc_metadata 0.0.0", - "rustc_mir 0.0.0", - "rustc_passes 0.0.0", - "rustc_plugin 0.0.0", - "rustc_privacy 0.0.0", - "rustc_resolve 0.0.0", - "rustc_traits 0.0.0", - "rustc_typeck 0.0.0", - "serialize 0.0.0", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syntax 0.0.0", - "syntax_ext 0.0.0", - "syntax_pos 0.0.0", - "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log", + "once_cell", + "rustc", + "rustc-rayon 0.3.0", + "rustc_codegen_ssa", + "rustc_codegen_utils", + "rustc_data_structures", + "rustc_errors", + "rustc_incremental", + "rustc_lint", + "rustc_metadata", + "rustc_mir", + "rustc_passes", + "rustc_plugin_impl", + "rustc_privacy", + "rustc_resolve", + "rustc_traits", + "rustc_typeck", + "serialize", + "smallvec", + "syntax", + "syntax_ext", + "syntax_pos", + "tempfile", ] [[package]] name = "rustc_lexer" version = "0.1.0" dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0", ] [[package]] name = "rustc_lint" version = "0.0.0" dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_target 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", + "log", + "rustc", + "rustc_data_structures", + "rustc_index", + "rustc_target", + "syntax", + "syntax_pos", ] [[package]] name = "rustc_llvm" version = "0.0.0" dependencies = [ - "build_helper 0.1.0", - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "build_helper", + "cc", ] [[package]] name = "rustc_lsan" version = "0.0.0" dependencies = [ - "alloc 0.0.0", - "build_helper 0.1.0", - "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "core 0.0.0", + "alloc", + "build_helper", + "cmake", + "compiler_builtins", + "core", ] [[package]] name = "rustc_macros" version = "0.1.0" dependencies = [ - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.0", + "proc-macro2 1.0.3", + "quote 1.0.2", + "syn 1.0.5", + "synstructure 0.12.1", ] [[package]] name = "rustc_metadata" version = "0.0.0" dependencies = [ - "flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_target 0.0.0", - "serialize 0.0.0", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntax 0.0.0", - "syntax_pos 0.0.0", + "flate2", + "log", + "memmap", + "rustc", + "rustc_data_structures", + "rustc_errors", + "rustc_index", + "rustc_target", + "serialize", + "smallvec", + "stable_deref_trait", + "syntax", + "syntax_pos", ] [[package]] name = "rustc_mir" version = "0.0.0" dependencies = [ - "arena 0.0.0", - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "graphviz 0.0.0", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "log_settings 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "polonius-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_apfloat 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_target 0.0.0", - "serialize 0.0.0", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syntax 0.0.0", - "syntax_pos 0.0.0", + "arena", + "either", + "graphviz", + "log", + "log_settings", + "polonius-engine", + "rustc", + "rustc_apfloat", + "rustc_data_structures", + "rustc_errors", + "rustc_index", + "rustc_lexer", + "rustc_target", + "serialize", + "smallvec", + "syntax", + "syntax_pos", ] [[package]] name = "rustc_msan" version = "0.0.0" dependencies = [ - "alloc 0.0.0", - "build_helper 0.1.0", - "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "core 0.0.0", + "alloc", + "build_helper", + "cmake", + "compiler_builtins", + "core", ] [[package]] name = "rustc_passes" version = "0.0.0" dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", + "log", + "rustc", + "rustc_data_structures", + "rustc_errors", + "rustc_index", + "rustc_target", + "syntax", + "syntax_pos", ] [[package]] name = "rustc_plugin" version = "0.0.0" dependencies = [ - "rustc 0.0.0", - "rustc_errors 0.0.0", - "rustc_metadata 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", + "rustc_plugin_impl", +] + +[[package]] +name = "rustc_plugin_impl" +version = "0.0.0" +dependencies = [ + "rustc", + "rustc_metadata", + "syntax", + "syntax_pos", ] [[package]] name = "rustc_privacy" version = "0.0.0" dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_typeck 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", + "log", + "rustc", + "rustc_data_structures", + "rustc_typeck", + "syntax", + "syntax_pos", ] [[package]] name = "rustc_resolve" version = "0.0.0" dependencies = [ - "arena 0.0.0", - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_metadata 0.0.0", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syntax 0.0.0", - "syntax_pos 0.0.0", + "arena", + "bitflags", + "log", + "rustc", + "rustc_data_structures", + "rustc_errors", + "rustc_metadata", + "smallvec", + "syntax", + "syntax_pos", ] [[package]] name = "rustc_save_analysis" version = "0.0.0" dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-span 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_codegen_utils 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_target 0.0.0", - "rustc_typeck 0.0.0", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "syntax 0.0.0", - "syntax_pos 0.0.0", + "log", + "rls-data", + "rls-span", + "rustc", + "rustc_codegen_utils", + "rustc_data_structures", + "rustc_target", + "serde_json", + "syntax", + "syntax_pos", ] [[package]] name = "rustc_target" version = "0.0.0" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_data_structures 0.0.0", - "serialize 0.0.0", - "syntax_pos 0.0.0", + "bitflags", + "log", + "rustc_data_structures", + "rustc_index", + "serialize", + "syntax_pos", ] [[package]] @@ -3196,66 +3762,66 @@ version = "0.2.0" name = "rustc_tools_util" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b725dadae9fabc488df69a287f5a99c5eaf5d10853842a8a3dfac52476f544ee" [[package]] name = "rustc_traits" version = "0.0.0" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "chalk-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "graphviz 0.0.0", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_target 0.0.0", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syntax 0.0.0", - "syntax_pos 0.0.0", + "chalk-engine", + "log", + "rustc", + "rustc_data_structures", + "rustc_target", + "smallvec", + "syntax", + "syntax_pos", ] [[package]] name = "rustc_tsan" version = "0.0.0" dependencies = [ - "alloc 0.0.0", - "build_helper 0.1.0", - "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "core 0.0.0", + "alloc", + "build_helper", + "cmake", + "compiler_builtins", + "core", ] [[package]] name = "rustc_typeck" version = "0.0.0" dependencies = [ - "arena 0.0.0", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_target 0.0.0", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syntax 0.0.0", - "syntax_pos 0.0.0", + "arena", + "log", + "rustc", + "rustc_data_structures", + "rustc_errors", + "rustc_index", + "rustc_target", + "smallvec", + "syntax", + "syntax_pos", ] [[package]] name = "rustc_version" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver", ] [[package]] name = "rustdoc" version = "0.0.0" dependencies = [ - "minifier 0.0.33 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pulldown-cmark 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "minifier", + "pulldown-cmark 0.5.3", + "rustc-rayon 0.3.0", + "tempfile", ] [[package]] @@ -3266,1452 +3832,1270 @@ version = "0.1.0" name = "rustdoc-tool" version = "0.0.0" dependencies = [ - "rustdoc 0.0.0", + "rustdoc", ] [[package]] name = "rustfix" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7150ac777a2931a53489f5a41eb0937b84e3092a20cd0e73ad436b65b507f607" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "failure", + "log", + "serde", + "serde_json", ] [[package]] name = "rustfmt-config_proc_macro" -version = "0.1.2" +version = "0.2.0" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3", + "quote 1.0.2", + "serde", + "syn 1.0.5", ] [[package]] name = "rustfmt-nightly" -version = "1.4.4" -dependencies = [ - "annotate-snippets 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "bytecount 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", - "ignore 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_target 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-workspace-hack 1.0.0", - "rustfmt-config_proc_macro 0.1.2", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +version = "1.4.9" +dependencies = [ + "annotate-snippets", + "bytecount", + "cargo_metadata", + "derive-new", + "diff", + "dirs", + "env_logger 0.6.2", + "failure", + "getopts", + "ignore", + "itertools 0.8.0", + "lazy_static 1.3.0", + "log", + "regex", + "rustc-ap-rustc_target", + "rustc-ap-syntax", + "rustc-ap-syntax_pos", + "rustc-workspace-hack", + "rustfmt-config_proc_macro", + "serde", + "serde_json", + "structopt 0.3.1", + "term 0.6.0", + "toml", + "unicode-segmentation", + "unicode-width", + "unicode_categories", ] [[package]] name = "ryu" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" [[package]] name = "same-file" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" dependencies = [ - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util", ] [[package]] name = "schannel" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1a231dc10abf6749cfa5d7767f25888d484201accbd919b66ab5413c502d56" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0", + "winapi 0.3.6", ] [[package]] name = "scoped-tls" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" [[package]] name = "scoped_threadpool" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" [[package]] name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" [[package]] name = "scopeguard" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" [[package]] name = "security-framework" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2" dependencies = [ - "core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", ] [[package]] name = "security-framework-sys" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56" dependencies = [ - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys", ] [[package]] name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "semver-parser", + "serde", ] [[package]] name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.92" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" dependencies = [ - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "477b13b646f5b5b56fc95bedfc3b550d12141ce84f466f6c44b9a17589923885" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30", + "quote 0.6.12", + "syn 0.15.35", ] [[package]] name = "serde_ignored" -version = "0.0.4" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c24bbb8f4b81834f618cd3e28698235c2fba06ddf7f4fbe30519dd081364e59" dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] [[package]] name = "serde_json" version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" dependencies = [ - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573" +dependencies = [ + "proc-macro2 1.0.3", + "quote 1.0.2", + "syn 1.0.5", ] [[package]] name = "serde_urlencoded" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" dependencies = [ - "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "dtoa", + "itoa", + "serde", + "url 1.7.2", ] [[package]] name = "serialize" version = "0.0.0" dependencies = [ - "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap", + "smallvec", ] [[package]] name = "sha-1" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded" dependencies = [ - "block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer", + "byte-tools", + "digest", + "fake-simd", ] [[package]] name = "shell-escape" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" [[package]] name = "shlex" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" [[package]] name = "signal-hook" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f272d1b7586bec132ed427f532dd418d8beca1ca7f2caf7df35569b1415a4b4" dependencies = [ - "arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "arc-swap", + "libc", ] [[package]] name = "siphasher" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" [[package]] name = "sized-chunks" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a2eb3fe454976eefb479f78f9b394d34d661b647c6326a3a6e66f68bb12c26" dependencies = [ - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum", ] [[package]] name = "slab" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "smallvec" version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" [[package]] name = "socket2" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4d11a52082057d87cb5caa31ad812f4504b97ab44732cd8359df2e9ff9f48e7" dependencies = [ - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "redox_syscall", + "winapi 0.3.6", ] [[package]] name = "stable_deref_trait" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbc596e092fe5f598b12ef46cc03754085ac2f4d8c739ad61c4ae266cc3b3fa" [[package]] name = "std" version = "0.0.0" dependencies = [ - "alloc 0.0.0", - "backtrace 0.3.34 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "core 0.0.0", - "dlmalloc 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fortanix-sgx-abi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hashbrown 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "panic_abort 0.0.0", - "panic_unwind 0.0.0", - "profiler_builtins 0.0.0", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_asan 0.0.0", - "rustc_lsan 0.0.0", - "rustc_msan 0.0.0", - "rustc_tsan 0.0.0", - "unwind 0.0.0", + "alloc", + "backtrace", + "cfg-if", + "compiler_builtins", + "core", + "dlmalloc", + "fortanix-sgx-abi", + "hashbrown 0.6.1", + "libc", + "panic_abort", + "panic_unwind", + "profiler_builtins", + "rand 0.7.0", + "rustc_asan", + "rustc_lsan", + "rustc_msan", + "rustc_tsan", + "unwind", + "wasi", ] [[package]] name = "string" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", ] [[package]] name = "string_cache" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "new_debug_unreachable 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", - "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "string_cache_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0", + "new_debug_unreachable", + "phf_shared", + "precomputed-hash", + "serde", + "string_cache_codegen", + "string_cache_shared", ] [[package]] name = "string_cache_codegen" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1eea1eee654ef80933142157fdad9dd8bc43cf7c74e999e369263496f04ff4da" dependencies = [ - "phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_generator", + "phf_shared", + "proc-macro2 0.4.30", + "quote 0.6.12", + "string_cache_shared", ] [[package]] name = "string_cache_shared" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" [[package]] name = "strip-ansi-escapes" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d63676e2abafa709460982ddc02a3bb586b6d15a49b75c212e06edd3933acee" dependencies = [ - "vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "vte", ] [[package]] name = "strsim" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "structopt" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" +dependencies = [ + "clap", + "structopt-derive 0.2.18", +] + +[[package]] +name = "structopt" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ac9d6e93dd792b217bf89cda5c14566e3043960c6f9da890c2ba5d09d07804c" dependencies = [ - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "clap", + "structopt-derive 0.3.1", ] [[package]] name = "structopt-derive" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" +dependencies = [ + "heck", + "proc-macro2 0.4.30", + "quote 0.6.12", + "syn 0.15.35", +] + +[[package]] +name = "structopt-derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae9e5165d463a0dea76967d021f8d0f9316057bf5163aa2a4843790e842ff37" dependencies = [ - "heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "heck", + "proc-macro-error", + "proc-macro2 1.0.3", + "quote 1.0.2", + "syn 1.0.5", ] [[package]] name = "strum" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6c3a2071519ab6a48f465808c4c1ffdd00dfc8e93111d02b4fc5abab177676e" [[package]] name = "strum_macros" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8baacebd7b7c9b864d83a6ba7a246232983e277b86fa5cdec77f565715a4b136" dependencies = [ - "heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "heck", + "proc-macro2 0.4.30", + "quote 0.6.12", + "syn 0.15.35", ] [[package]] name = "syn" version = "0.15.35" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "641e117d55514d6d918490e47102f7e08d096fdde360247e4a10f7a91a8478d3" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.12", + "unicode-xid 0.1.0", +] + +[[package]] +name = "syn" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3", + "quote 1.0.2", + "unicode-xid 0.2.0", ] [[package]] name = "synstructure" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30", + "quote 0.6.12", + "syn 0.15.35", + "unicode-xid 0.1.0", +] + +[[package]] +name = "synstructure" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" +dependencies = [ + "proc-macro2 1.0.3", + "quote 1.0.2", + "syn 1.0.5", + "unicode-xid 0.2.0", ] [[package]] name = "syntax" version = "0.0.0" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_lexer 0.1.0", - "rustc_macros 0.1.0", - "rustc_target 0.0.0", - "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serialize 0.0.0", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syntax_pos 0.0.0", + "bitflags", + "lazy_static 1.3.0", + "log", + "rustc_data_structures", + "rustc_errors", + "rustc_index", + "rustc_lexer", + "rustc_target", + "scoped-tls", + "serialize", + "smallvec", + "syntax_pos", ] [[package]] name = "syntax_ext" version = "0.0.0" dependencies = [ - "fmt_macros 0.0.0", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_target 0.0.0", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syntax 0.0.0", - "syntax_pos 0.0.0", + "fmt_macros", + "log", + "rustc_data_structures", + "rustc_errors", + "rustc_target", + "smallvec", + "syntax", + "syntax_pos", ] [[package]] name = "syntax_pos" version = "0.0.0" dependencies = [ - "arena 0.0.0", - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_data_structures 0.0.0", - "rustc_macros 0.1.0", - "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serialize 0.0.0", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "arena", + "cfg-if", + "rustc_data_structures", + "rustc_index", + "rustc_macros", + "scoped-tls", + "serialize", + "unicode-width", ] [[package]] name = "take_mut" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" [[package]] name = "tar" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a303ba60a099fcd2aaa646b14d2724591a96a75283e4b7ed3d1a1658909d9ae2" dependencies = [ - "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime", + "libc", + "redox_syscall", + "xattr", ] [[package]] name = "tempfile" -version = "3.0.5" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "rand 0.7.0", + "redox_syscall", + "remove_dir_all", + "winapi 0.3.6", ] [[package]] name = "tendril" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508" dependencies = [ - "futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "utf-8 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futf", + "mac", + "utf-8", ] [[package]] name = "term" version = "0.0.0" +dependencies = [ + "core", + "std", +] [[package]] name = "term" -version = "0.4.6" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd90505d5006a4422d3520b30c781d480b3f36768c2fa2187c3e950bc110464" 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)", + "byteorder", + "dirs", + "winapi 0.3.6", ] [[package]] -name = "term" -version = "0.6.0" +name = "term_size" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys", + "libc", + "winapi 0.2.8", ] [[package]] name = "termcolor" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" dependencies = [ - "wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wincolor", ] [[package]] name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "redox_syscall", + "redox_termios", ] [[package]] name = "test" version = "0.0.0" dependencies = [ - "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", - "proc_macro 0.0.0", + "core", + "getopts", + "libc", + "panic_abort", + "panic_unwind", + "proc_macro", + "std", "term 0.0.0", ] -[[package]] -name = "tester" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "textwrap" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width", ] [[package]] name = "thread_local" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0", ] [[package]] name = "tidy" version = "0.1.0" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0", + "regex", + "serde", + "serde_json", + "walkdir", ] [[package]] name = "time" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "redox_syscall", + "winapi 0.3.6", ] [[package]] name = "tokio" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4790d0be6f4ba6ae4f48190efa2ed7780c9e3567796abdb285003cf39840d9c5" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "mio", + "num_cpus", + "tokio-codec", + "tokio-current-thread", + "tokio-executor", + "tokio-fs", + "tokio-io", + "tokio-reactor", + "tokio-tcp", + "tokio-threadpool", + "tokio-timer", + "tokio-udp", + "tokio-uds", ] [[package]] name = "tokio-buf" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "either", + "futures", ] [[package]] name = "tokio-codec" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "tokio-io", ] [[package]] name = "tokio-current-thread" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "331c8acc267855ec06eb0c94618dcbbfea45bed2d20b77252940095273fb58f6" dependencies = [ - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "tokio-executor", ] [[package]] name = "tokio-executor" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0" dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5", + "futures", ] [[package]] name = "tokio-fs" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e9cbbc8a3698b7ab652340f46633364f9eaa928ddaaee79d8b8f356dd79a09d" dependencies = [ - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "tokio-io", + "tokio-threadpool", ] [[package]] name = "tokio-io" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b53aeb9d3f5ccf2ebb29e19788f96987fa1355f8fe45ea193928eaaaf3ae820f" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "log", +] + +[[package]] +name = "tokio-named-pipes" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d282d483052288b2308ba5ee795f5673b159c9bdf63c385a05609da782a5eae" +dependencies = [ + "bytes", + "futures", + "mio", + "mio-named-pipes", + "tokio", ] [[package]] name = "tokio-process" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88e1281e412013f1ff5787def044a9577a0bed059f451e835f1643201f8b777d" dependencies = [ - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-signal 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "libc", + "mio", + "mio-named-pipes", + "tokio-io", + "tokio-reactor", + "tokio-signal", + "winapi 0.3.6", ] [[package]] name = "tokio-reactor" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afbcdb0f0d2a1e4c440af82d7bbf0bf91a8a8c0575bcd20c05d15be7e9d3a02f" dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5", + "futures", + "lazy_static 1.3.0", + "log", + "mio", + "num_cpus", + "parking_lot 0.7.1", + "slab", + "tokio-executor", + "tokio-io", +] + +[[package]] +name = "tokio-service" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" +dependencies = [ + "futures", ] [[package]] name = "tokio-signal" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd6dc5276ea05ce379a16de90083ec80836440d5ef8a6a39545a3207373b8296" dependencies = [ - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "libc", + "mio", + "mio-uds", + "signal-hook", + "tokio-executor", + "tokio-io", + "tokio-reactor", + "winapi 0.3.6", ] [[package]] name = "tokio-tcp" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "iovec", + "mio", + "tokio-io", + "tokio-reactor", ] [[package]] name = "tokio-threadpool" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17465013014410310f9f61fa10bf4724803c149ea1d51efece131c38efca93aa" dependencies = [ - "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (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.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel", + "crossbeam-deque 0.6.3", + "crossbeam-utils 0.6.5", + "futures", + "log", + "num_cpus", + "rand 0.6.1", + "tokio-executor", ] [[package]] name = "tokio-timer" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f37f0111d76cc5da132fe9bc0590b9b9cfd079bc7e75ac3846278430a299ff8" dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5", + "futures", + "slab", + "tokio-executor", ] [[package]] name = "tokio-udp" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "log", + "mio", + "tokio-codec", + "tokio-io", + "tokio-reactor", ] [[package]] name = "tokio-uds" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "iovec", + "libc", + "log", + "mio", + "mio-uds", + "tokio-codec", + "tokio-io", + "tokio-reactor", ] [[package]] name = "toml" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "toml" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7aabe75941d914b72bf3e5d3932ed92ce0664d49d8432305a8b547c37227724" dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] [[package]] name = "toml-query" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a24369a1894ac8224efcfd567c3d141aea360292f49888e7ec7dcc316527aebb" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "toml-query_derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure", + "failure_derive", + "is-match", + "lazy_static 1.3.0", + "regex", + "toml", + "toml-query_derive", ] [[package]] name = "toml-query_derive" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c99ca245ec273c7e75c8ee58f47b882d0146f3c2c8495158082c6671e8b5335" dependencies = [ - "darling 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "darling", + "quote 0.6.12", + "syn 0.15.35", ] [[package]] name = "try-lock" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" [[package]] name = "typenum" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" [[package]] name = "ucd-trie" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77" [[package]] name = "ucd-util" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" [[package]] name = "unicase" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" dependencies = [ - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check", ] [[package]] name = "unicase" -version = "2.4.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e2e6bd1e59e56598518beb94fd6db628ded570326f0a98c679a304bd9f00150" dependencies = [ - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check", ] [[package]] name = "unicode-bidi" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", ] [[package]] name = "unicode-normalization" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" [[package]] name = "unicode-segmentation" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" [[package]] name = "unicode-width" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-core", + "rustc-std-workspace-std", +] [[package]] name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" [[package]] name = "unicode_categories" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] name = "unstable-book-gen" version = "0.1.0" dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tidy 0.1.0", + "num-traits", + "tidy", ] [[package]] name = "unwind" version = "0.0.0" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "core 0.0.0", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "cfg-if", + "compiler_builtins", + "core", + "libc", ] [[package]] name = "url" version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" dependencies = [ - "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.5", + "matches", + "percent-encoding 1.0.1", ] [[package]] name = "url" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "url_serde" -version = "0.2.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61" dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.2.0", + "matches", + "percent-encoding 2.0.0", + "serde", ] [[package]] name = "utf-8" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1262dfab4c30d5cb7c07026be00ee343a6cf5027fdc0104a9160f354e5db75c" [[package]] name = "utf8-ranges" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" [[package]] name = "utf8parse" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" [[package]] name = "uuid" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" dependencies = [ - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1", ] [[package]] name = "vcpkg" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d" [[package]] name = "vec_map" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" [[package]] name = "vergen" version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "chrono", + "failure", ] [[package]] name = "version_check" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" [[package]] name = "vte" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf" dependencies = [ - "utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8parse", ] [[package]] name = "walkdir" version = "2.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" dependencies = [ - "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file", + "winapi 0.3.6", + "winapi-util", ] [[package]] name = "want" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" dependencies = [ - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", ] [[package]] name = "winapi" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" [[package]] name = "winapi" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "wincolor" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6", + "winapi-util", ] [[package]] name = "ws2_32-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8", + "winapi-build", ] [[package]] name = "xattr" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "xz2" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8bf41d3030c3577c9458fd6640a05afbf43b150d0b531b16bd77d3f794f27a" dependencies = [ - "lzma-sys 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "lzma-sys", ] [[package]] name = "yaml-rust" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" -"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" -"checksum ammonia 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "384d704f242a0a9faf793fff775a0be6ab9aa27edabffa097331d73779142520" -"checksum annotate-snippets 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7021ce4924a3f25f802b2cccd1af585e39ea1a363a1aa2e72afe54b67a3a7a7" -"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1025aeae2b664ca0ea726a89d574fe8f4e77dd712d443236ad1de00379450cf6" -"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392" -"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" -"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" -"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum backtrace 0.3.34 (registry+https://github.com/rust-lang/crates.io-index)" = "b5164d292487f037ece34ec0de2fcede2faa162f085dd96d2385ab81b12765ba" -"checksum backtrace-sys 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "5b3a000b9c543553af61bc01cbfc403b04b5caa9e421033866f2e98061eb3e61" -"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" -"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" -"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" -"checksum bstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "853b090ce0f45d0265902666bf88039ea3da825e33796716c511a1ec9c170036" -"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" -"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" -"checksum bytecount 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be0fdd54b507df8f22012890aadd099979befdba27713c767993f8380112ca7c" -"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" -"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" -"checksum bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "716960a18f978640f25101b5cbf1c6f6b0d3192fab36a2d98ca96f0ecbe41010" -"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" -"checksum cargo_metadata 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "929766d993a2fde7a0ae962ee82429069cd7b68839cd9375b98efd719df65d3a" -"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83" -"checksum cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "89431bba4e6b7092fb5fcd00a6f6ca596c55cc26b2f1e6dcdd08a1f4933f66b2" -"checksum chalk-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17ec698a6f053a23bfbe646d9f2fde4b02abc19125595270a99e6f44ae0bdd1a" -"checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e" -"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" -"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "96210eec534fc3fbfc0452a63769424eaa80205fda6cea98e5b61cb3d97bcec8" -"checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc" -"checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" -"checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" -"checksum compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "ef1c086a06d6f52f9c0d50cacdc021bfb6034ddeec9fb7e62f099f13f65472f4" -"checksum compiletest_rs 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "f40ecc9332b68270998995c00f8051ee856121764a0d3230e64c9efd059d27b6" -"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" -"checksum core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4e2640d6d0bf22e82bed1b73c6aef8d5dd31e5abe6666c57e6d45e2649f4f887" -"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" -"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" -"checksum crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e91d5240c6975ef33aeb5f148f35275c25eda8e8a5f95abe421978b05b8bf192" -"checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" -"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" -"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" -"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" -"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" -"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" -"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" -"checksum crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09de9ee0fc255ace04c7fa0763c9395a945c37c8292bb554f8d48361d1dcf1b4" -"checksum curl 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)" = "a85f2f95f2bd277d316d1aa8a477687ab4a6942258c7db7c89c187534669979c" -"checksum curl-sys 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)" = "9d91a0052d5b982887d8e829bee0faffc7218ea3c6ebd3d6c2c8f678a93c9a42" -"checksum darling 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9158d690bc62a3a57c3e45b85e4d50de2008b39345592c64efd79345c7e24be0" -"checksum darling_core 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d2a368589465391e127e10c9e3a08efc8df66fd49b87dc8524c764bbe7f2ef82" -"checksum darling_macro 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "244e8987bd4e174385240cde20a3657f607fb0797563c28255c353b5819a07b1" -"checksum datafrog 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69" -"checksum derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6ca414e896ae072546f4d789f452daaecf60ddee4c9df5dc6d5936d769e3d87c" -"checksum derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f57d78cf3bd45270dad4e70c21ec77a960b36c7a841ff9db76aaa775a8fb871" -"checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" -"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" -"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" -"checksum directories 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ccc83e029c3cebb4c8155c644d34e3a070ccdb4ff90d369c74cd73f7cb3c984" -"checksum dirs 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1c4ef5a8b902d393339e2a2c7fe573af92ce7e0ee5a3ff827b4c9ad7e07e4fa1" -"checksum dirs-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "937756392ec77d1f2dd9dc3ac9d69867d109a2121479d72c364e42f4cab21e2d" -"checksum dlmalloc 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f283302e035e61c23f2b86b3093e8c6273a4c3125742d6087e96ade001ca5e63" -"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" -"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" -"checksum elasticlunr-rs 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a99a310cd1f9770e7bf8e48810c7bcbb0e078c8fb23a8c7bcf0da4c2bf61a455" -"checksum ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dc01d68e08ca384955a3aeba9217102ca1aa85b6e168639bf27739f1d749d87" -"checksum encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4155785c79f2f6701f185eb2e6b4caf0555ec03477cb4c70db67b465311620ed" -"checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" -"checksum env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afb070faf94c85d17d50ca44f6ad076bce18ae92f0037d350947240a36e9d42e" -"checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" -"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" -"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" -"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -"checksum filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646" -"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" -"checksum flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2291c165c8e703ee54ef3055ad6188e3d51108e2ded18e9f2476e774fc5ad3d4" -"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" -"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -"checksum fortanix-sgx-abi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3f8cbee5e872cf7db61a999a041f9bc4706ca7bf7df4cb914f53fabb1c1bc550" -"checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -"checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" -"checksum fst 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d94485a00b1827b861dd9d1a2cc9764f9044d4c535514c0760a5a2012ef3399f" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" -"checksum futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869" -"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum fwdansi 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34dd4c507af68d37ffef962063dfa1944ce0dd4d5b82043dbab1dabe088610c3" -"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" -"checksum getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "72327b15c228bfe31f1390f93dd5e9279587f0463836393c9df719ce62a3e450" -"checksum getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "34f33de6f0ae7c9cb5e574502a562e2b512799e32abb801cd1e79ad952b62b49" -"checksum git2 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cb400360e8a4d61b10e648285bbfa919bbf9519d0d5d5720354456f44349226" -"checksum git2-curl 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2293de73491c3dc4174c5949ef53d2cc037b27613f88d72032e3f5237247a7dd" -"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" -"checksum globset 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4feaabe24a0a658fd9cf4a9acf6ed284f045c77df0f49020ba3245cfb7b454" -"checksum h2 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "a539b63339fbbb00e081e84b6e11bd1d9634a82d91da2984a18ac74a8823f392" -"checksum handlebars 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "df044dd42cdb7e32f28557b661406fc0f2494be75199779998810dbc35030e0d" -"checksum hashbrown 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9529213c67695ca2d146e6f263b7b72df8fa973368beadf767e8ed80c03f2f36" -"checksum hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1de41fb8dba9714efd92241565cdff73f78508c95697dd56787d3cba27e2353" -"checksum heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea04fa3ead4e05e51a7c806fc07271fdbde4e246a6c6d1efd52e72230b771b82" -"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" -"checksum home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "80dff82fb58cfbbc617fb9a9184b010be0529201553cda50ad04372bc2333aff" -"checksum html5ever 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ce65ac8028cf5a287a7dbf6c4e0a6cf2dcf022ed5b167a81bae66ebf599a8b7" -"checksum http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fe67e3678f2827030e89cc4b9e7ecd16d52f132c0b940ab5005f88e821500f6a" -"checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" -"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" -"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" -"checksum hyper 0.12.31 (registry+https://github.com/rust-lang/crates.io-index)" = "6481fff8269772d4463253ca83c788104a7305cb3fb9136bc651a6211e46e03f" -"checksum hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f" -"checksum ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" -"checksum if_chain 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c3360c7b59e5ffa2653671fb74b4741a5d343c03f331c0a4aeda42b5c2b0ec7d" -"checksum ignore 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8dc57fa12805f367736a38541ac1a9fc6a52812a0ca959b1d4d4b640a89eb002" -"checksum im-rc 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0197597d095c0d11107975d3175173f810ee572c2501ff4de64f4f3f119806" -"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" -"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" -"checksum is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053" -"checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450" -"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" -"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" -"checksum jemalloc-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bef0d4ce37578dfd80b466e3d8324bd9de788e249f1accebb0c472ea4b52bdc" -"checksum jobserver 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "f74e73053eaf95399bf926e48fc7a2a3ce50bd0eaaa2357d391e95b2dcdd4f10" -"checksum json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be" -"checksum jsonrpc-core 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "288dca7f9713710a29e485076b9340156cb701edb46a881f5d0c31aa4f5b9143" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" -"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb" -"checksum libflate 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "90c6f86f4b0caa347206f916f8b687b51d77c6ef8ff18d52dd007491fd580529" -"checksum libgit2-sys 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4c179ed6d19cd3a051e68c177fbbc214e79ac4724fac3a850ec9f3d3eb8a5578" -"checksum libnghttp2-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d75d7966bda4730b722d1eab8e668df445368a24394bae9fc1e8dc0ab3dbe4f4" -"checksum libssh2-sys 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "126a1f4078368b163bfdee65fbab072af08a1b374a5551b21e87ade27b1fbf9d" -"checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" -"checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54" -"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" -"checksum log_settings 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19af41f0565d7c19b2058153ad0b42d4d5ce89ec4dbf06ed6741114a8b63e7cd" -"checksum lsp-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "169d737ad89cf8ddd82d1804d9122f54568c49377665157277cc90d747b1d31a" -"checksum lsp-types 0.57.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b62b77309737b1e262b3bbf37ff8faa740562c633b14702afe9be85dbcb6f88a" -"checksum lzma-sys 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "16b5c59c57cc4d39e7999f50431aa312ea78af7c93b23fbb0c3567bd672e7f35" -"checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" -"checksum macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2c4deaccc2ead6a28c16c0ba82f07d52b6475397415ce40876e559b0b0ea510" -"checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43" -"checksum markup5ever 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f1af46a727284117e09780d05038b1ce6fc9c76cc6df183c3dae5a8955a25e21" -"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum mdbook 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "949bb2acb2cff9fa5c375cf9c43e70b3dba0a974d9fe01c31285d7a84d2a0fa2" -"checksum mdbook-linkcheck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d1f0ba4d1e6b86fa18e8853d026d7d76a97eb7eb5eb052ed80901e43b7fc10" -"checksum measureme 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d09de7dafa3aa334bc806447c7e4de69419723312f4b88b80b561dea66601ce8" -"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" -"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" -"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" -"checksum mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "3e27ca21f40a310bd06d9031785f4801710d566c184a6e15bad4f1d9b65f9425" -"checksum mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30de2e4613efcba1ec63d8133f344076952090c122992a903359be5a4f99c3ed" -"checksum minifier 0.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "70bf0db2475f5e627787da77ca52fe33c294063f49f4134b8bc662eedb5e7332" -"checksum miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0300eafb20369952951699b68243ab4334f4b10a88f411c221d444b36c40e649" -"checksum miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ad30a47319c16cde58d0314f5d98202a80c9083b5f61178457403dfb14e509c" -"checksum miniz_oxide_c_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28edaef377517fd9fe3e085c37d892ce7acd1fbeab9239c5a36eec352d8a8b7e" -"checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" -"checksum mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f5e374eff525ce1c5b7687c4cef63943e7686524a387933ad27ca7ec43779cb3" -"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" -"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" -"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e" -"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" -"checksum new_debug_unreachable 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f40f005c60db6e03bae699e414c58bf9aa7ea02a2d0b9bfbcf19286cc4c82b30" -"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" -"checksum num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8af1847c907c2f04d7bfd572fb25bbb4385c637fe5be163cf2f8c5d778fe1e7d" -"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" -"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" -"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c281318d992e4432cfa799969467003d05921582a7489a8325e37f8a450d5113" -"checksum opener 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "998c59e83d9474c01127a96e023b7a04bb061dd286bf8bb939d31dc8d31a7448" -"checksum openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ec7bd7ca4cce6dbdc77e7c1230682740d307d1218a87fb0349a571272be749f9" -"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" -"checksum openssl-src 111.3.0+1.1.1c (registry+https://github.com/rust-lang/crates.io-index)" = "53ed5f31d294bdf5f7a4ba0a206c2754b0f60e9a63b7e3076babc5317873c797" -"checksum openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)" = "33c86834957dd5b915623e94f2f4ab2c70dd8f6b70679824155d5ae21dbd495d" -"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" -"checksum ordslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd20eec3dbe4376829cb7d80ae6ac45e0a766831dca50202ff2d40db46a8a024" -"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" -"checksum packed_simd 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "25d36de864f7218ec5633572a800109bbe5a1cc8d9d95a967f3daf93ea7e6ddc" -"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" -"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" -"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum percent-encoding 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba4f28a6faf4ffea762ba8f4baef48c61a6db348647c73095034041fc79dd954" -"checksum pest 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "54f0c72a98d8ab3c99560bfd16df8059cc10e1f9a8e83e6e3b97718dd766e9c3" -"checksum pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" -"checksum pest_generator 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63120576c4efd69615b5537d3d052257328a4ca82876771d6944424ccfd9f646" -"checksum pest_meta 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5a3492a4ed208ffc247adcdcc7ba2a95be3104f58877d0d02f0df39bf3efb5e" -"checksum petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f" -"checksum phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18" -"checksum phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e" -"checksum phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" -"checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" -"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" -"checksum polonius-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f6b8a5defa2aef9ba4999aaa745fbc01c622ecea35964a306adc3e44be4f3b5b" -"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" -"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 pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8b3f4e0475def7d9c2e5de8e5a1306949849761e107b360d03e98eafaffd61" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum pulldown-cmark 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "77043da1282374688ee212dc44b3f37ff929431de9c9adc3053bd3cee5630357" -"checksum punycode 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6ddd112cca70a4d30883b2d21568a1d376ff8be4758649f64f973c6845128ad3" -"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" -"checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" -"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" -"checksum racer 2.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "0727b9d7baaf9e42851145545d7b980b5c1752bd16a4c77c925c5e573d0069d9" -"checksum rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9d223d52ae411a33cf7e54ec6034ec165df296ccd23533d671a28252b6f66a" -"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" -"checksum rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "771b009e3a508cb67e8823dda454aaa5368c7bc1c16829fb77d3e980440dd34a" -"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" -"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" -"checksum rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effa3fcaa47e18db002bdde6060944b6d2f9cfd8db471c30e873448ad9187be3" -"checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" -"checksum rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4b0186e22767d5b9738a05eab7c6ac90b15db17e5b5f9bd87976dd7d89a10a4" -"checksum rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe0df8435ac0c397d467b6cad6d25543d06e8a019ef3f6af3c384597515bd2" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "679da7508e9a6390aeaf7fbd02a800fdc64b73fe2204dd2c8ae66d22d9d5ad5d" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe5204c3a17e97dde73f285d49be585df59ed84b50a872baf416e73b62c3828" -"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58" -"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" -"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum reqwest 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e542d9f077c126af32536b6aacc75bb7325400eab8cd0743543be5d91660780d" -"checksum rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" -"checksum rls-analysis 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4c0d208ad66717501222c74b42d9e823a7612592e85ed78b04074c8f58c0be0a" -"checksum rls-data 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76c72ea97e045be5f6290bb157ebdc5ee9f2b093831ff72adfaf59025cf5c491" -"checksum rls-span 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f1cb4694410d8d2ce43ccff3682f1c782158a018d5a9a92185675677f7533eb3" -"checksum rls-vfs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce4b57b25b4330ed5ec14028fc02141e083ddafda327e7eb598dc0569c8c83c9" -"checksum rustc-ap-arena 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4dc2e1e68b64268c543bfa6e63e3c0d9ea58074c71396f42f76931f35a9287f9" -"checksum rustc-ap-graphviz 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c108d647ce0dd46477b048eafff5a6273b5652e02d47424b0cd684147379c811" -"checksum rustc-ap-rustc_data_structures 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "656771744e0783cb8e4481e3b8b1f975687610aaf18833b898018111a0e0e582" -"checksum rustc-ap-rustc_errors 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e37064f6624bc799bfaa2968b61ee6880926dea2a8bba69f18aef6c8e69c9604" -"checksum rustc-ap-rustc_lexer 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef5bc0a971823637ea23a857f0ef1467f44b1e05d71968821f83a0abe53e0fe3" -"checksum rustc-ap-rustc_macros 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b90037e3336fe8835f468db44d0848ae10d9cc8533ae89b55828883f905b7e80" -"checksum rustc-ap-rustc_target 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cadf9ca07315eab3a7a21f63872f9cc81e250fd6ede0419c24f8926ade73a45d" -"checksum rustc-ap-serialize 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "61673783f2089e01033ffa82d1988f55175402071b31253a358292e1624d4602" -"checksum rustc-ap-syntax 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28f3dd1346d5b0269c07a4a78855e309a298ab569c9c1302d4d4f57f8eee4e84" -"checksum rustc-ap-syntax_pos 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45e67b526dbda3a0c7dab91c8947d43685e7697f52686a4949da3c179cd7c979" -"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" -"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" -"checksum rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d2e07e19601f21c59aad953c2632172ba70cb27e685771514ea66e4062b3363" -"checksum rustc-rayon-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "79d38ca7cbc22fa59f09d8534ea4b27f67b0facf0cbe274433aceea227a02543" -"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum rustc_tools_util 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b725dadae9fabc488df69a287f5a99c5eaf5d10853842a8a3dfac52476f544ee" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7150ac777a2931a53489f5a41eb0937b84e3092a20cd0e73ad436b65b507f607" -"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" -"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" -"checksum schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0e1a231dc10abf6749cfa5d7767f25888d484201accbd919b66ab5413c502d56" -"checksum scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" -"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" -"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" -"checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2" -"checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56" -"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.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be" -"checksum serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)" = "477b13b646f5b5b56fc95bedfc3b550d12141ce84f466f6c44b9a17589923885" -"checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142" -"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" -"checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" -"checksum sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded" -"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 signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1f272d1b7586bec132ed427f532dd418d8beca1ca7f2caf7df35569b1415a4b4" -"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" -"checksum sized-chunks 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2a2eb3fe454976eefb479f78f9b394d34d661b647c6326a3a6e66f68bb12c26" -"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" -"checksum socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d11a52082057d87cb5caa31ad812f4504b97ab44732cd8359df2e9ff9f48e7" -"checksum stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbc596e092fe5f598b12ef46cc03754085ac2f4d8c739ad61c4ae266cc3b3fa" -"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" -"checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423" -"checksum string_cache_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eea1eee654ef80933142157fdad9dd8bc43cf7c74e999e369263496f04ff4da" -"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" -"checksum strip-ansi-escapes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d63676e2abafa709460982ddc02a3bb586b6d15a49b75c212e06edd3933acee" -"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" -"checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" -"checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" -"checksum strum 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c3a2071519ab6a48f465808c4c1ffdd00dfc8e93111d02b4fc5abab177676e" -"checksum strum_macros 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8baacebd7b7c9b864d83a6ba7a246232983e277b86fa5cdec77f565715a4b136" -"checksum syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)" = "641e117d55514d6d918490e47102f7e08d096fdde360247e4a10f7a91a8478d3" -"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" -"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" -"checksum tar 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "a303ba60a099fcd2aaa646b14d2724591a96a75283e4b7ed3d1a1658909d9ae2" -"checksum tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7e91405c14320e5c79b3d148e1c86f40749a36e490642202a31689cb1a3452b2" -"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.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd90505d5006a4422d3520b30c781d480b3f36768c2fa2187c3e950bc110464" -"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" -"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum tester 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e812cb26c597f86a49b26dbb58b878bd2a2b4b93fc069dc39499228fe556ff6" -"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" -"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" -"checksum tokio 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4790d0be6f4ba6ae4f48190efa2ed7780c9e3567796abdb285003cf39840d9c5" -"checksum tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" -"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" -"checksum tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "331c8acc267855ec06eb0c94618dcbbfea45bed2d20b77252940095273fb58f6" -"checksum tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0" -"checksum tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e9cbbc8a3698b7ab652340f46633364f9eaa928ddaaee79d8b8f356dd79a09d" -"checksum tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b53aeb9d3f5ccf2ebb29e19788f96987fa1355f8fe45ea193928eaaaf3ae820f" -"checksum tokio-process 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88e1281e412013f1ff5787def044a9577a0bed059f451e835f1643201f8b777d" -"checksum tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "afbcdb0f0d2a1e4c440af82d7bbf0bf91a8a8c0575bcd20c05d15be7e9d3a02f" -"checksum tokio-signal 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "dd6dc5276ea05ce379a16de90083ec80836440d5ef8a6a39545a3207373b8296" -"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" -"checksum tokio-threadpool 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "17465013014410310f9f61fa10bf4724803c149ea1d51efece131c38efca93aa" -"checksum tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4f37f0111d76cc5da132fe9bc0590b9b9cfd079bc7e75ac3846278430a299ff8" -"checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" -"checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" -"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" -"checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039" -"checksum toml-query 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a24369a1894ac8224efcfd567c3d141aea360292f49888e7ec7dcc316527aebb" -"checksum toml-query_derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c99ca245ec273c7e75c8ee58f47b882d0146f3c2c8495158082c6671e8b5335" -"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" -"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" -"checksum ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77" -"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" -"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" -"checksum unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a84e5511b2a947f3ae965dcb29b13b7b1691b6e7332cf5dbc1744138d5acb7f6" -"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" -"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" -"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" -"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -"checksum url 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77ddaf52e65c6b81c56b7e957c0b1970f7937f21c5c6774c4e56fcb4e20b48c6" -"checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea" -"checksum utf-8 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1262dfab4c30d5cb7c07026be00ee343a6cf5027fdc0104a9160f354e5db75c" -"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" -"checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" -"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" -"checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d" -"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" -"checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" -"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" -"checksum vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf" -"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" -"checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -"checksum xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" -"checksum xz2 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "df8bf41d3030c3577c9458fd6640a05afbf43b150d0b531b16bd77d3f794f27a" -"checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" +checksum = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" diff --git a/Cargo.toml b/Cargo.toml index ccd7e8b7654a6..a242f090fbc07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,7 @@ rustc-workspace-hack = { path = 'src/tools/rustc-workspace-hack' } # here rustc-std-workspace-core = { path = 'src/tools/rustc-std-workspace-core' } rustc-std-workspace-alloc = { path = 'src/tools/rustc-std-workspace-alloc' } +rustc-std-workspace-std = { path = 'src/tools/rustc-std-workspace-std' } [patch."https://github.com/rust-lang/rust-clippy"] clippy_lints = { path = "src/tools/clippy/clippy_lints" } diff --git a/README.md b/README.md index 40df6a4737871..c5468a2924888 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,14 @@ or reading the [rustc guide][rustcguidebuild]. ### Building on *nix 1. Make sure you have installed the dependencies: - * `g++` 4.7 or later or `clang++` 3.x or later + * `g++` 5.1 or later or `clang++` 3.5 or later * `python` 2.7 (but not 3.x) * GNU `make` 3.81 or later * `cmake` 3.4.3 or later * `curl` * `git` + * `ssl` which comes in `libssl-dev` or `openssl-devel` + * `pkg-config` if you are compiling on Linux and targeting Linux 2. Clone the [source] with `git`: @@ -56,6 +58,8 @@ or reading the [rustc guide][rustcguidebuild]. an installation (using `./x.py install`) that you set the `prefix` value in the `[install]` section to a directory that you have write permissions. + Create install directory if you are not installing in default directory + 4. Build and install: ```sh @@ -144,10 +148,21 @@ then you may need to force rustbuild to use an older version. This can be done by manually calling the appropriate vcvars file before running the bootstrap. ```batch -> CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvars64.bat" +> CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" > python x.py build ``` +### Building rustc with older host toolchains +It is still possible to build Rust with the older toolchain versions listed below, but only if the +LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN option is set to true in the config.toml file. + +* Clang 3.1 +* Apple Clang 3.1 +* GCC 4.8 +* Visual Studio 2015 (Update 3) + +Toolchain versions older than what is listed above cannot be used to build rustc. + #### Specifying an ABI Each specific ABI can also be used from either environment (for example, using @@ -229,19 +244,17 @@ The Rust community congregates in a few places: To contribute to Rust, please see [CONTRIBUTING](CONTRIBUTING.md). -Rust has an [IRC] culture and most real-time collaboration happens in a -variety of channels on Mozilla's IRC network, irc.mozilla.org. The -most popular channel is [#rust], a venue for general discussion about -Rust. And a good place to ask for help would be [#rust-beginners]. +Most real-time collaboration happens in a variety of channels on the +[Rust Discord server][rust-discord], with channels dedicated for getting help, +community, documentation, and all major contribution areas in the Rust ecosystem. +A good place to ask for help would be the #help channel. The [rustc guide] might be a good place to start if you want to find out how various parts of the compiler work. Also, you may find the [rustdocs for the compiler itself][rustdocs] useful. -[IRC]: https://en.wikipedia.org/wiki/Internet_Relay_Chat -[#rust]: irc://irc.mozilla.org/rust -[#rust-beginners]: irc://irc.mozilla.org/rust-beginners +[rust-discord]: https://discord.gg/rust-lang [rustc guide]: https://rust-lang.github.io/rustc-guide/about-this-guide.html [rustdocs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ diff --git a/RELEASES.md b/RELEASES.md index 7ad739d06d54f..e6512bb6f6de9 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,113 @@ +Version 1.38.0 (2019-09-26) +========================== + +Language +-------- +- [The `#[global_allocator]` attribute can now be used in submodules.][62735] +- [The `#[deprecated]` attribute can now be used on macros.][62042] + +Compiler +-------- +- [Added pipelined compilation support to `rustc`.][62766] This will + improve compilation times in some cases. For further information please refer + to the [_"Evaluating pipelined rustc compilation"_][pipeline-internals] thread. +- [Added tier 3\* support for the `aarch64-uwp-windows-msvc`, `i686-uwp-windows-gnu`, + `i686-uwp-windows-msvc`, `x86_64-uwp-windows-gnu`, and + `x86_64-uwp-windows-msvc` targets.][60260] +- [Added tier 3 support for the `armv7-unknown-linux-gnueabi` and + `armv7-unknown-linux-musleabi` targets.][63107] +- [Added tier 3 support for the `hexagon-unknown-linux-musl` target.][62814] +- [Added tier 3 support for the `riscv32i-unknown-none-elf` target.][62784] + +\* Refer to Rust's [platform support page][forge-platform-support] for more +information on Rust's tiered platform support. + +Libraries +--------- +- [`ascii::EscapeDefault` now implements `Clone` and `Display`.][63421] +- [Derive macros for prelude traits (e.g. `Clone`, `Debug`, `Hash`) are now + available at the same path as the trait.][63056] (e.g. The `Clone` derive macro + is available at `std::clone::Clone`). This also makes all built-in macros + available in `std`/`core` root. e.g. `std::include_bytes!`. +- [`str::Chars` now implements `Debug`.][63000] +- [`slice::{concat, connect, join}` now accepts `&[T]` in addition to `&T`.][62528] +- [`*const T` and `*mut T` now implement `marker::Unpin`.][62583] +- [`Arc<[T]>` and `Rc<[T]>` now implement `FromIterator`.][61953] +- [Added euclidean remainder and division operations (`div_euclid`, + `rem_euclid`) to all numeric primitives.][61884] Additionally `checked`, + `overflowing`, and `wrapping` versions are available for all + integer primitives. +- [`thread::AccessError` now implements `Clone`, `Copy`, `Eq`, `Error`, and + `PartialEq`.][61491] +- [`iter::{StepBy, Peekable, Take}` now implement `DoubleEndedIterator`.][61457] + +Stabilized APIs +--------------- +- [`<*const T>::cast`] +- [`<*mut T>::cast`] +- [`Duration::as_secs_f32`] +- [`Duration::as_secs_f64`] +- [`Duration::div_f32`] +- [`Duration::div_f64`] +- [`Duration::from_secs_f32`] +- [`Duration::from_secs_f64`] +- [`Duration::mul_f32`] +- [`Duration::mul_f64`] +- [`any::type_name`] + +Cargo +----- +- [Added pipelined compilation support to `cargo`.][cargo/7143] +- [You can now pass the `--features` option multiple times to enable + multiple features.][cargo/7084] + +Misc +---- +- [`rustc` will now warn about some incorrect uses of + `mem::{uninitialized, zeroed}` that are known to cause undefined behaviour.][63346] + +Compatibility Notes +------------------- +- The [`x86_64-unknown-uefi` platform can not be built][62785] with rustc + 1.38.0. +- The [`armv7-unknown-linux-gnueabihf` platform is known to have + issues][62896] with certain crates such as libc. + +[60260]: https://github.com/rust-lang/rust/pull/60260/ +[61457]: https://github.com/rust-lang/rust/pull/61457/ +[61491]: https://github.com/rust-lang/rust/pull/61491/ +[61884]: https://github.com/rust-lang/rust/pull/61884/ +[61953]: https://github.com/rust-lang/rust/pull/61953/ +[62042]: https://github.com/rust-lang/rust/pull/62042/ +[62528]: https://github.com/rust-lang/rust/pull/62528/ +[62583]: https://github.com/rust-lang/rust/pull/62583/ +[62735]: https://github.com/rust-lang/rust/pull/62735/ +[62766]: https://github.com/rust-lang/rust/pull/62766/ +[62784]: https://github.com/rust-lang/rust/pull/62784/ +[62785]: https://github.com/rust-lang/rust/issues/62785/ +[62814]: https://github.com/rust-lang/rust/pull/62814/ +[62896]: https://github.com/rust-lang/rust/issues/62896/ +[63000]: https://github.com/rust-lang/rust/pull/63000/ +[63056]: https://github.com/rust-lang/rust/pull/63056/ +[63107]: https://github.com/rust-lang/rust/pull/63107/ +[63346]: https://github.com/rust-lang/rust/pull/63346/ +[63421]: https://github.com/rust-lang/rust/pull/63421/ +[cargo/7084]: https://github.com/rust-lang/cargo/pull/7084/ +[cargo/7143]: https://github.com/rust-lang/cargo/pull/7143/ +[`<*const T>::cast`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.cast +[`<*mut T>::cast`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.cast +[`Duration::as_secs_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_secs_f32 +[`Duration::as_secs_f64`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_secs_f64 +[`Duration::div_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.div_f32 +[`Duration::div_f64`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.div_f64 +[`Duration::from_secs_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.from_secs_f32 +[`Duration::from_secs_f64`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.from_secs_f64 +[`Duration::mul_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.mul_f32 +[`Duration::mul_f64`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.mul_f64 +[`any::type_name`]: https://doc.rust-lang.org/std/any/fn.type_name.html +[forge-platform-support]: https://forge.rust-lang.org/platform-support.html +[pipeline-internals]: https://internals.rust-lang.org/t/evaluating-pipelined-rustc-compilation/10199 + Version 1.37.0 (2019-08-15) ========================== @@ -22,7 +132,7 @@ Language - [You can now use `_` as an identifier for consts.][61347] e.g. You can write `const _: u32 = 5;`. - [You can now use `#[repr(align(X)]` on enums.][61229] -- [The `?`/_"Kleene"_ macro operator is now available in the +- [The `?` Kleene macro operator is now available in the 2015 edition.][60932] Compiler diff --git a/config.toml.example b/config.toml.example index cb9f388a8e47b..848147c2974c1 100644 --- a/config.toml.example +++ b/config.toml.example @@ -141,10 +141,10 @@ # library and facade crates. #compiler-docs = false -# Indicate whether submodules are managed and updated automatically. +# Indicate whether git submodules are managed and updated automatically. #submodules = true -# Update submodules only when the checked out commit in the submodules differs +# Update git submodules only when the checked out commit in the submodules differs # from what is committed in the main rustc repo. #fast-submodules = true @@ -184,7 +184,7 @@ # default. #extended = false -# Installs chosen set of extended tools if enables. By default builds all. +# Installs chosen set of extended tools if enabled. By default builds all. # If chosen tool failed to build the installation fails. #tools = ["cargo", "rls", "clippy", "rustfmt", "analysis", "src"] @@ -382,11 +382,6 @@ # This is the name of the directory in which codegen backends will get installed #codegen-backends-dir = "codegen-backends" -# Flag indicating whether `libstd` calls an imported function to handle basic IO -# when targeting WebAssembly. Enable this to debug tests for the `wasm32-unknown-unknown` -# target, as without this option the test output will not be captured. -#wasm-syscall = false - # Indicates whether LLD will be compiled and made available in the sysroot for # rustc to execute. #lld = false diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 589ee9276a5a3..c27c318f5ad07 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -44,7 +44,7 @@ cc = "1.0.35" libc = "0.2" serde = { version = "1.0.8", features = ["derive"] } serde_json = "1.0.2" -toml = "0.4" +toml = "0.5" lazy_static = "1.3.0" time = "0.1" petgraph = "0.4.13" diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 3e877fc4e317c..c501378bff549 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -328,6 +328,8 @@ are: `Config` struct. * Adding a sanity check? Take a look at `bootstrap/sanity.rs`. -If you have any questions feel free to reach out on `#rust-infra` on IRC or ask on -internals.rust-lang.org. When you encounter bugs, please file issues on the -rust-lang/rust issue tracker. +If you have any questions feel free to reach out on `#infra` channel in the +[Rust Discord server][rust-discord] or ask on internals.rust-lang.org. When +you encounter bugs, please file issues on the rust-lang/rust issue tracker. + +[rust-discord]: https://discord.gg/rust-lang diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs index bd1a87c5744d3..138b7f4b26104 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/bin/main.rs @@ -5,9 +5,6 @@ //! parent directory, and otherwise documentation can be found throughout the `build` //! directory in each respective module. -// NO-RUSTC-WRAPPER -#![deny(warnings, rust_2018_idioms, unused_lifetimes)] - use std::env; use bootstrap::{Config, Build}; diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 54b689fb062a5..475f2e904639c 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -15,11 +15,7 @@ //! switching compilers for the bootstrap and for build scripts will probably //! never get replaced. -// NO-RUSTC-WRAPPER -#![deny(warnings, rust_2018_idioms, unused_lifetimes)] - use std::env; -use std::ffi::OsString; use std::io; use std::path::PathBuf; use std::process::Command; @@ -27,35 +23,7 @@ use std::str::FromStr; use std::time::Instant; fn main() { - let mut args = env::args_os().skip(1).collect::>(); - - // Append metadata suffix for internal crates. See the corresponding entry - // in bootstrap/lib.rs for details. - if let Ok(s) = env::var("RUSTC_METADATA_SUFFIX") { - for i in 1..args.len() { - // Dirty code for borrowing issues - let mut new = None; - if let Some(current_as_str) = args[i].to_str() { - if (&*args[i - 1] == "-C" && current_as_str.starts_with("metadata")) || - current_as_str.starts_with("-Cmetadata") { - new = Some(format!("{}-{}", current_as_str, s)); - } - } - if let Some(new) = new { args[i] = new.into(); } - } - } - - // Drop `--error-format json` because despite our desire for json messages - // from Cargo we don't want any from rustc itself. - if let Some(n) = args.iter().position(|n| n == "--error-format") { - args.remove(n); - args.remove(n); - } - - if let Some(s) = env::var_os("RUSTC_ERROR_FORMAT") { - args.push("--error-format".into()); - args.push(s); - } + let args = env::args_os().skip(1).collect::>(); // Detect whether or not we're a build script depending on whether --target // is passed (a bit janky...) @@ -101,47 +69,19 @@ fn main() { if let Some(crate_name) = crate_name { if let Some(target) = env::var_os("RUSTC_TIME") { if target == "all" || - target.into_string().unwrap().split(",").any(|c| c.trim() == crate_name) + target.into_string().unwrap().split(",").any(|c| c.trim() == crate_name) { cmd.arg("-Ztime"); } } } - // Non-zero stages must all be treated uniformly to avoid problems when attempting to uplift - // compiler libraries and such from stage 1 to 2. - if stage == "0" { - cmd.arg("--cfg").arg("bootstrap"); - } - // Print backtrace in case of ICE if env::var("RUSTC_BACKTRACE_ON_ICE").is_ok() && env::var("RUST_BACKTRACE").is_err() { cmd.env("RUST_BACKTRACE", "1"); } - cmd.env("RUSTC_BREAK_ON_ICE", "1"); - - if let Ok(debuginfo_level) = env::var("RUSTC_DEBUGINFO_LEVEL") { - cmd.arg(format!("-Cdebuginfo={}", debuginfo_level)); - } - - if env::var_os("RUSTC_DENY_WARNINGS").is_some() && - env::var_os("RUSTC_EXTERNAL_TOOL").is_none() { - // When extending this list, search for `NO-RUSTC-WRAPPER` and add the new lints - // there as well, some code doesn't go through this `rustc` wrapper. - cmd.arg("-Dwarnings"); - cmd.arg("-Drust_2018_idioms"); - cmd.arg("-Dunused_lifetimes"); - // cfg(not(bootstrap)): Remove this during the next stage 0 compiler update. - // `-Drustc::internal` is a new feature and `rustc_version` mis-reports the `stage`. - let cfg_not_bootstrap = stage != "0" && crate_name != Some("rustc_version"); - if cfg_not_bootstrap && use_internal_lints(crate_name) { - cmd.arg("-Zunstable-options"); - cmd.arg("-Drustc::internal"); - } - } - - if let Some(target) = target { + if target.is_some() { // The stage0 compiler has a special sysroot distinct from what we // actually downloaded, so we just always pass the `--sysroot` option, // unless one is already set. @@ -149,43 +89,6 @@ fn main() { cmd.arg("--sysroot").arg(&sysroot); } - cmd.arg("-Zexternal-macro-backtrace"); - - // Link crates to the proc macro crate for the target, but use a host proc macro crate - // to actually run the macros - if env::var_os("RUST_DUAL_PROC_MACROS").is_some() { - cmd.arg("-Zdual-proc-macros"); - } - - // When we build Rust dylibs they're all intended for intermediate - // usage, so make sure we pass the -Cprefer-dynamic flag instead of - // linking all deps statically into the dylib. - if env::var_os("RUSTC_NO_PREFER_DYNAMIC").is_none() { - cmd.arg("-Cprefer-dynamic"); - } - - // Help the libc crate compile by assisting it in finding various - // sysroot native libraries. - if let Some(s) = env::var_os("MUSL_ROOT") { - if target.contains("musl") { - let mut root = OsString::from("native="); - root.push(&s); - root.push("/lib"); - cmd.arg("-L").arg(&root); - } - } - if let Some(s) = env::var_os("WASI_ROOT") { - let mut root = OsString::from("native="); - root.push(&s); - root.push("/lib/wasm32-wasi"); - cmd.arg("-L").arg(&root); - } - - // Override linker if necessary. - if let Ok(target_linker) = env::var("RUSTC_TARGET_LINKER") { - cmd.arg(format!("-Clinker={}", target_linker)); - } - // If we're compiling specifically the `panic_abort` crate then we pass // the `-C panic=abort` option. Note that we do not do this for any // other crate intentionally as this is the only crate for now that we @@ -212,86 +115,18 @@ fn main() { // The compiler builtins are pretty sensitive to symbols referenced in // libcore and such, so we never compile them with debug assertions. + // + // FIXME(rust-lang/cargo#7253) we should be doing this in `builder.rs` + // with env vars instead of doing it here in this script. if crate_name == Some("compiler_builtins") { cmd.arg("-C").arg("debug-assertions=no"); } else { cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions)); } - - if let Ok(s) = env::var("RUSTC_CODEGEN_UNITS") { - cmd.arg("-C").arg(format!("codegen-units={}", s)); - } - - // Emit save-analysis info. - if env::var("RUSTC_SAVE_ANALYSIS") == Ok("api".to_string()) { - cmd.arg("-Zsave-analysis"); - cmd.env("RUST_SAVE_ANALYSIS_CONFIG", - "{\"output_file\": null,\"full_docs\": false,\ - \"pub_only\": true,\"reachable_only\": false,\ - \"distro_crate\": true,\"signatures\": false,\"borrow_data\": false}"); - } - - // Dealing with rpath here is a little special, so let's go into some - // detail. First off, `-rpath` is a linker option on Unix platforms - // which adds to the runtime dynamic loader path when looking for - // dynamic libraries. We use this by default on Unix platforms to ensure - // that our nightlies behave the same on Windows, that is they work out - // of the box. This can be disabled, of course, but basically that's why - // we're gated on RUSTC_RPATH here. - // - // Ok, so the astute might be wondering "why isn't `-C rpath` used - // here?" and that is indeed a good question to task. This codegen - // option is the compiler's current interface to generating an rpath. - // Unfortunately it doesn't quite suffice for us. The flag currently - // takes no value as an argument, so the compiler calculates what it - // should pass to the linker as `-rpath`. This unfortunately is based on - // the **compile time** directory structure which when building with - // Cargo will be very different than the runtime directory structure. - // - // All that's a really long winded way of saying that if we use - // `-Crpath` then the executables generated have the wrong rpath of - // something like `$ORIGIN/deps` when in fact the way we distribute - // rustc requires the rpath to be `$ORIGIN/../lib`. - // - // So, all in all, to set up the correct rpath we pass the linker - // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it - // fun to pass a flag to a tool to pass a flag to pass a flag to a tool - // to change a flag in a binary? - if env::var("RUSTC_RPATH") == Ok("true".to_string()) { - let rpath = if target.contains("apple") { - - // Note that we need to take one extra step on macOS to also pass - // `-Wl,-instal_name,@rpath/...` to get things to work right. To - // do that we pass a weird flag to the compiler to get it to do - // so. Note that this is definitely a hack, and we should likely - // flesh out rpath support more fully in the future. - cmd.arg("-Z").arg("osx-rpath-install-name"); - Some("-Wl,-rpath,@loader_path/../lib") - } else if !target.contains("windows") && - !target.contains("wasm32") && - !target.contains("fuchsia") { - Some("-Wl,-rpath,$ORIGIN/../lib") - } else { - None - }; - if let Some(rpath) = rpath { - cmd.arg("-C").arg(format!("link-args={}", rpath)); - } - } - - if let Ok(s) = env::var("RUSTC_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 let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") { - cmd.arg("--remap-path-prefix").arg(&map); - } } else { + // FIXME(rust-lang/cargo#5754) we shouldn't be using special env vars + // here, but rather Cargo should know what flags to pass rustc itself. + // Override linker if necessary. if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") { cmd.arg(format!("-Clinker={}", host_linker)); @@ -307,6 +142,10 @@ fn main() { } } + if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") { + cmd.arg("--remap-path-prefix").arg(&map); + } + // Force all crates compiled by this compiler to (a) be unstable and (b) // allow the `rustc_private` feature to link to other unstable crates // also in the sysroot. We also do this for host crates, since those @@ -315,10 +154,6 @@ fn main() { cmd.arg("-Z").arg("force-unstable-if-unmarked"); } - if env::var_os("RUSTC_PARALLEL_COMPILER").is_some() { - cmd.arg("--cfg").arg("parallel_compiler"); - } - if verbose > 1 { eprintln!( "rustc command: {:?}={:?} {:?}", @@ -369,14 +204,6 @@ fn main() { std::process::exit(code); } -// Rustc crates for which internal lints are in effect. -fn use_internal_lints(crate_name: Option<&str>) -> bool { - crate_name.map_or(false, |crate_name| { - crate_name.starts_with("rustc") || crate_name.starts_with("syntax") || - ["arena", "fmt_macros"].contains(&crate_name) - }) -} - #[cfg(unix)] fn exec_cmd(cmd: &mut Command) -> io::Result { use std::os::unix::process::CommandExt; diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index ff38ee8788f56..a13ff69a7b56f 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -2,12 +2,10 @@ //! //! See comments in `src/bootstrap/rustc.rs` for more information. -// NO-RUSTC-WRAPPER -#![deny(warnings, rust_2018_idioms, unused_lifetimes)] - use std::env; use std::process::Command; use std::path::PathBuf; +use std::ffi::OsString; fn main() { let args = env::args_os().skip(1).collect::>(); @@ -47,7 +45,9 @@ fn main() { cmd.arg("-Z").arg("force-unstable-if-unmarked"); } if let Some(linker) = env::var_os("RUSTC_TARGET_LINKER") { - cmd.arg("--linker").arg(linker).arg("-Z").arg("unstable-options"); + let mut arg = OsString::from("-Clinker="); + arg.push(&linker); + cmd.arg(arg); } // Bootstrap's Cargo-command builder sets this variable to the current Rust version; let's pick diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 86901792d7974..65129eeeec504 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -320,7 +320,7 @@ class RustBuild(object): def __init__(self): self.cargo_channel = '' self.date = '' - self._download_url = 'https://static.rust-lang.org' + self._download_url = '' self.rustc_channel = '' self.build = '' self.build_dir = os.path.join(os.getcwd(), "build") @@ -523,6 +523,10 @@ def get_toml(self, key, section=None): 'value2' >>> rb.get_toml('key', 'c') is None True + + >>> rb.config_toml = 'key1 = true' + >>> rb.get_toml("key1") + 'true' """ cur_section = None @@ -571,6 +575,12 @@ def get_string(line): >>> RustBuild.get_string(' "devel" ') 'devel' + >>> RustBuild.get_string(" 'devel' ") + 'devel' + >>> RustBuild.get_string('devel') is None + True + >>> RustBuild.get_string(' "devel ') + '' """ start = line.find('"') if start != -1: @@ -631,6 +641,9 @@ def build_bootstrap(self): target_linker = self.get_toml("linker", build_section) if target_linker is not None: env["RUSTFLAGS"] += "-C linker=" + target_linker + " " + env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes " + if self.get_toml("deny-warnings", "rust") != "false": + env["RUSTFLAGS"] += "-Dwarnings " env["PATH"] = os.path.join(self.bin_root(), "bin") + \ os.pathsep + env["PATH"] @@ -666,7 +679,7 @@ def check_submodule(self, module, slow_submodules): def update_submodule(self, module, checked_out, recorded_submodules): module_path = os.path.join(self.rust_root, module) - if checked_out != None: + if checked_out is not None: default_encoding = sys.getdefaultencoding() checked_out = checked_out.communicate()[0].decode(default_encoding).strip() if recorded_submodules[module] == checked_out: @@ -695,6 +708,14 @@ def update_submodules(self): if (not os.path.exists(os.path.join(self.rust_root, ".git"))) or \ self.get_toml('submodules') == "false": return + + # check the existence of 'git' command + try: + subprocess.check_output(['git', '--version']) + except (subprocess.CalledProcessError, OSError): + print("error: `git` is not found, please make sure it's installed and in the path.") + sys.exit(1) + slow_submodules = self.get_toml('fast-submodules') == "false" start_time = time() if slow_submodules: @@ -731,9 +752,19 @@ def update_submodules(self): self.update_submodule(module[0], module[1], recorded_submodules) print("Submodules updated in %.2f seconds" % (time() - start_time)) + def set_normal_environment(self): + """Set download URL for normal environment""" + if 'RUSTUP_DIST_SERVER' in os.environ: + self._download_url = os.environ['RUSTUP_DIST_SERVER'] + else: + self._download_url = 'https://static.rust-lang.org' + def set_dev_environment(self): """Set download URL for development environment""" - self._download_url = 'https://dev-static.rust-lang.org' + if 'RUSTUP_DEV_DIST_SERVER' in os.environ: + self._download_url = os.environ['RUSTUP_DEV_DIST_SERVER'] + else: + self._download_url = 'https://dev-static.rust-lang.org' def check_vendored_status(self): """Check that vendoring is configured properly""" @@ -809,13 +840,13 @@ def bootstrap(help_triggered): except (OSError, IOError): pass - match = re.search(r'\nverbose = (\d+)', build.config_toml) - if match is not None: - build.verbose = max(build.verbose, int(match.group(1))) + config_verbose = build.get_toml('verbose', 'build') + if config_verbose is not None: + build.verbose = max(build.verbose, int(config_verbose)) - build.use_vendored_sources = '\nvendor = true' in build.config_toml + build.use_vendored_sources = build.get_toml('vendor', 'build') == 'true' - build.use_locked_deps = '\nlocked-deps = true' in build.config_toml + build.use_locked_deps = build.get_toml('locked-deps', 'build') == 'true' build.check_vendored_status() @@ -826,6 +857,8 @@ def bootstrap(help_triggered): if 'dev' in data: build.set_dev_environment() + else: + build.set_normal_environment() build.update_submodules() diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index e54c9360baece..7e3ae7f2cc907 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -3,6 +3,7 @@ use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; use std::collections::HashMap; use std::env; +use std::ffi::OsStr; use std::fmt::Debug; use std::fs; use std::hash::Hash; @@ -145,7 +146,7 @@ impl StepDescription { only_hosts: S::ONLY_HOSTS, should_run: S::should_run, make_run: S::make_run, - name: unsafe { ::std::intrinsics::type_name::() }, + name: std::any::type_name::(), } } @@ -337,7 +338,6 @@ impl<'a> Builder<'a> { match kind { Kind::Build => describe!( compile::Std, - compile::Test, compile::Rustc, compile::CodegenBackend, compile::StartupObjects, @@ -363,7 +363,6 @@ impl<'a> Builder<'a> { ), Kind::Check | Kind::Clippy | Kind::Fix => describe!( check::Std, - check::Test, check::Rustc, check::CodegenBackend, check::Rustdoc @@ -425,8 +424,6 @@ impl<'a> Builder<'a> { doc::TheBook, doc::Standalone, doc::Std, - doc::Test, - doc::WhitelistedRustc, doc::Rustc, doc::Rustdoc, doc::ErrorIndex, @@ -446,6 +443,7 @@ impl<'a> Builder<'a> { dist::Rustc, dist::DebuggerScripts, dist::Std, + dist::RustcDev, dist::Analysis, dist::Src, dist::PlainSourceTarball, @@ -618,13 +616,7 @@ impl<'a> Builder<'a> { } fn run(self, builder: &Builder<'_>) -> Interned { - let compiler = self.compiler; - let config = &builder.build.config; - let lib = if compiler.stage >= 1 && config.libdir_relative().is_some() { - builder.build.config.libdir_relative().unwrap() - } else { - Path::new("lib") - }; + let lib = builder.sysroot_libdir_relative(self.compiler); let sysroot = builder .sysroot(self.compiler) .join(lib) @@ -678,9 +670,21 @@ impl<'a> Builder<'a> { } } + /// Returns the compiler's relative libdir where the standard library and other artifacts are + /// found for a compiler's sysroot. + /// + /// For example this returns `lib` on Unix and Windows. + pub fn sysroot_libdir_relative(&self, compiler: Compiler) -> &Path { + match self.config.libdir_relative() { + Some(relative_libdir) if compiler.stage >= 1 + => relative_libdir, + _ => Path::new("lib") + } + } + /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic /// library lookup path. - pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Command) { + pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Cargo) { // Windows doesn't need dylib path munging because the dlls for the // compiler live next to the compiler and the system will find them // automatically. @@ -688,7 +692,7 @@ impl<'a> Builder<'a> { return; } - add_lib_path(vec![self.rustc_libdir(compiler)], cmd); + add_lib_path(vec![self.rustc_libdir(compiler)], &mut cmd.command); } /// Gets a path to the compiler specified. @@ -750,85 +754,39 @@ impl<'a> Builder<'a> { mode: Mode, target: Interned, cmd: &str, - ) -> Command { + ) -> Cargo { let mut cargo = Command::new(&self.initial_cargo); let out_dir = self.stage_out(compiler, mode); - // command specific path, we call clear_if_dirty with this - let mut my_out = match cmd { - "build" => self.cargo_out(compiler, mode, target), - - // This is the intended out directory for crate documentation. - "doc" | "rustdoc" => self.crate_doc_out(target), - - _ => self.stage_out(compiler, mode), - }; - - // This is for the original compiler, but if we're forced to use stage 1, then - // std/test/rustc stamps won't exist in stage 2, so we need to get those from stage 1, since - // we copy the libs forward. - let cmp = self.compiler_for(compiler.stage, compiler.host, target); - - let libstd_stamp = match cmd { - "check" | "clippy" | "fix" => check::libstd_stamp(self, cmp, target), - _ => compile::libstd_stamp(self, cmp, target), - }; - - let libtest_stamp = match cmd { - "check" | "clippy" | "fix" => check::libtest_stamp(self, cmp, target), - _ => compile::libtest_stamp(self, cmp, target), - }; - - let librustc_stamp = match cmd { - "check" | "clippy" | "fix" => check::librustc_stamp(self, cmp, target), - _ => compile::librustc_stamp(self, cmp, target), - }; + // Codegen backends are not yet tracked by -Zbinary-dep-depinfo, + // so we need to explicitly clear out if they've been updated. + for backend in self.codegen_backends(compiler) { + self.clear_if_dirty(&out_dir, &backend); + } if cmd == "doc" || cmd == "rustdoc" { - if mode == Mode::Rustc || mode == Mode::ToolRustc || mode == Mode::Codegen { + let my_out = match mode { // This is the intended out directory for compiler documentation. - my_out = self.compiler_doc_out(target); - } + Mode::Rustc | Mode::ToolRustc | Mode::Codegen => self.compiler_doc_out(target), + _ => self.crate_doc_out(target), + }; let rustdoc = self.rustdoc(compiler); self.clear_if_dirty(&my_out, &rustdoc); - } else if cmd != "test" { - match mode { - Mode::Std => { - self.clear_if_dirty(&my_out, &self.rustc(compiler)); - for backend in self.codegen_backends(compiler) { - self.clear_if_dirty(&my_out, &backend); - } - }, - Mode::Test => { - self.clear_if_dirty(&my_out, &libstd_stamp); - }, - Mode::Rustc => { - self.clear_if_dirty(&my_out, &self.rustc(compiler)); - self.clear_if_dirty(&my_out, &libstd_stamp); - self.clear_if_dirty(&my_out, &libtest_stamp); - }, - Mode::Codegen => { - self.clear_if_dirty(&my_out, &librustc_stamp); - }, - Mode::ToolBootstrap => { }, - Mode::ToolStd => { - self.clear_if_dirty(&my_out, &libstd_stamp); - }, - Mode::ToolTest => { - self.clear_if_dirty(&my_out, &libstd_stamp); - self.clear_if_dirty(&my_out, &libtest_stamp); - }, - Mode::ToolRustc => { - self.clear_if_dirty(&my_out, &libstd_stamp); - self.clear_if_dirty(&my_out, &libtest_stamp); - self.clear_if_dirty(&my_out, &librustc_stamp); - }, - } } cargo .env("CARGO_TARGET_DIR", out_dir) - .arg(cmd); + .arg(cmd) + .arg("-Zconfig-profile"); + + let profile_var = |name: &str| { + let profile = if self.config.rust_optimize { + "RELEASE" + } else { + "DEV" + }; + format!("CARGO_PROFILE_{}_{}", profile, name) + }; // See comment in librustc_llvm/build.rs for why this is necessary, largely llvm-config // needs to not accidentally link to libLLVM in stage0/lib. @@ -850,17 +808,56 @@ impl<'a> Builder<'a> { cargo.env("RUST_CHECK", "1"); } + let stage; + if compiler.stage == 0 && self.local_rebuild { + // Assume the local-rebuild rustc already has stage1 features. + stage = 1; + } else { + stage = compiler.stage; + } + + let mut rustflags = Rustflags::new(&target); + if stage != 0 { + if let Ok(s) = env::var("CARGOFLAGS_NOT_BOOTSTRAP") { + cargo.args(s.split_whitespace()); + } + rustflags.env("RUSTFLAGS_NOT_BOOTSTRAP"); + } else { + if let Ok(s) = env::var("CARGOFLAGS_BOOTSTRAP") { + cargo.args(s.split_whitespace()); + } + rustflags.env("RUSTFLAGS_BOOTSTRAP"); + rustflags.arg("--cfg=bootstrap"); + } + + if let Ok(s) = env::var("CARGOFLAGS") { + cargo.args(s.split_whitespace()); + } + match mode { - Mode::Std | Mode::Test | Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolTest=> {}, + Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {}, Mode::Rustc | Mode::Codegen | Mode::ToolRustc => { // Build proc macros both for the host and the target if target != compiler.host && cmd != "check" { cargo.arg("-Zdual-proc-macros"); - cargo.env("RUST_DUAL_PROC_MACROS", "1"); + rustflags.arg("-Zdual-proc-macros"); } }, } + // This tells Cargo (and in turn, rustc) to output more complete + // dependency information. Most importantly for rustbuild, this + // includes sysroot artifacts, like libstd, which means that we don't + // need to track those in rustbuild (an error prone process!). This + // feature is currently unstable as there may be some bugs and such, but + // it represents a big improvement in rustbuild's reliability on + // rebuilds, so we're using it here. + // + // For some additional context, see #63470 (the PR originally adding + // this), as well as #63012 which is the tracking issue for this + // feature on the rustc side. + cargo.arg("-Zbinary-dep-depinfo"); + cargo.arg("-j").arg(self.jobs().to_string()); // Remove make-related flags to ensure Cargo can correctly set things up cargo.env_remove("MAKEFLAGS"); @@ -889,44 +886,16 @@ impl<'a> Builder<'a> { // things still build right, please do! match mode { Mode::Std => metadata.push_str("std"), - Mode::Test => metadata.push_str("test"), _ => {}, } cargo.env("__CARGO_DEFAULT_LIB_METADATA", &metadata); - let stage; - if compiler.stage == 0 && self.local_rebuild { - // Assume the local-rebuild rustc already has stage1 features. - stage = 1; - } else { - stage = compiler.stage; - } - - let mut extra_args = env::var(&format!("RUSTFLAGS_STAGE_{}", stage)).unwrap_or_default(); - if stage != 0 { - let s = env::var("RUSTFLAGS_STAGE_NOT_0").unwrap_or_default(); - if !extra_args.is_empty() { - extra_args.push_str(" "); - } - extra_args.push_str(&s); - } - if cmd == "clippy" { - extra_args.push_str("-Zforce-unstable-if-unmarked -Zunstable-options \ - --json-rendered=termcolor"); - } - - if !extra_args.is_empty() { - cargo.env( - "RUSTFLAGS", - format!( - "{} {}", - env::var("RUSTFLAGS").unwrap_or_default(), - extra_args - ), - ); + rustflags.arg("-Zforce-unstable-if-unmarked"); } + rustflags.arg("-Zexternal-macro-backtrace"); + let want_rustdoc = self.doc_tests != DocTests::No; // We synthetically interpret a stage0 compiler used to build tools as a @@ -962,7 +931,6 @@ impl<'a> Builder<'a> { ) .env("RUSTC_SYSROOT", &sysroot) .env("RUSTC_LIBDIR", &libdir) - .env("RUSTC_RPATH", self.config.rust_rpath.to_string()) .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc")) .env( "RUSTDOC_REAL", @@ -972,16 +940,63 @@ impl<'a> Builder<'a> { PathBuf::from("/path/to/nowhere/rustdoc/not/required") }, ) - .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir()); + .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir()) + .env("RUSTC_BREAK_ON_ICE", "1"); + + // Dealing with rpath here is a little special, so let's go into some + // detail. First off, `-rpath` is a linker option on Unix platforms + // which adds to the runtime dynamic loader path when looking for + // dynamic libraries. We use this by default on Unix platforms to ensure + // that our nightlies behave the same on Windows, that is they work out + // of the box. This can be disabled, of course, but basically that's why + // we're gated on RUSTC_RPATH here. + // + // Ok, so the astute might be wondering "why isn't `-C rpath` used + // here?" and that is indeed a good question to task. This codegen + // option is the compiler's current interface to generating an rpath. + // Unfortunately it doesn't quite suffice for us. The flag currently + // takes no value as an argument, so the compiler calculates what it + // should pass to the linker as `-rpath`. This unfortunately is based on + // the **compile time** directory structure which when building with + // Cargo will be very different than the runtime directory structure. + // + // All that's a really long winded way of saying that if we use + // `-Crpath` then the executables generated have the wrong rpath of + // something like `$ORIGIN/deps` when in fact the way we distribute + // rustc requires the rpath to be `$ORIGIN/../lib`. + // + // So, all in all, to set up the correct rpath we pass the linker + // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it + // fun to pass a flag to a tool to pass a flag to pass a flag to a tool + // to change a flag in a binary? + if self.config.rust_rpath { + let rpath = if target.contains("apple") { + + // Note that we need to take one extra step on macOS to also pass + // `-Wl,-instal_name,@rpath/...` to get things to work right. To + // do that we pass a weird flag to the compiler to get it to do + // so. Note that this is definitely a hack, and we should likely + // flesh out rpath support more fully in the future. + rustflags.arg("-Zosx-rpath-install-name"); + Some("-Wl,-rpath,@loader_path/../lib") + } else if !target.contains("windows") && + !target.contains("wasm32") && + !target.contains("fuchsia") { + Some("-Wl,-rpath,$ORIGIN/../lib") + } else { + None + }; + if let Some(rpath) = rpath { + rustflags.arg(&format!("-Clink-args={}", rpath)); + } + } if let Some(host_linker) = self.linker(compiler.host) { cargo.env("RUSTC_HOST_LINKER", host_linker); } if let Some(target_linker) = self.linker(target) { - cargo.env("RUSTC_TARGET_LINKER", target_linker); - } - if let Some(ref error_format) = self.config.rustc_error_format { - cargo.env("RUSTC_ERROR_FORMAT", error_format); + let target = crate::envify(&target); + cargo.env(&format!("CARGO_TARGET_{}_LINKER", target), target_linker); } if !(["build", "check", "clippy", "fix", "rustc"].contains(&cmd)) && want_rustdoc { cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler)); @@ -989,36 +1004,22 @@ impl<'a> Builder<'a> { let debuginfo_level = match mode { Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc, - Mode::Std | Mode::Test => self.config.rust_debuginfo_level_std, + Mode::Std => self.config.rust_debuginfo_level_std, Mode::ToolBootstrap | Mode::ToolStd | - Mode::ToolTest | Mode::ToolRustc => self.config.rust_debuginfo_level_tools, + Mode::ToolRustc => self.config.rust_debuginfo_level_tools, }; - cargo.env("RUSTC_DEBUGINFO_LEVEL", debuginfo_level.to_string()); + cargo.env(profile_var("DEBUG"), debuginfo_level.to_string()); if !mode.is_tool() { cargo.env("RUSTC_FORCE_UNSTABLE", "1"); - - // Currently the compiler depends on crates from crates.io, and - // then other crates can depend on the compiler (e.g., proc-macro - // crates). Let's say, for example that rustc itself depends on the - // bitflags crate. If an external crate then depends on the - // bitflags crate as well, we need to make sure they don't - // conflict, even if they pick the same version of bitflags. We'll - // want to make sure that e.g., a plugin and rustc each get their - // own copy of bitflags. - - // Cargo ensures that this works in general through the -C metadata - // flag. This flag will frob the symbols in the binary to make sure - // they're different, even though the source code is the exact - // same. To solve this problem for the compiler we extend Cargo's - // already-passed -C metadata flag with our own. Our rustc.rs - // wrapper around the actual rustc will detect -C metadata being - // passed and frob it with this extra string we're passing in. - cargo.env("RUSTC_METADATA_SUFFIX", "rustc"); } if let Some(x) = self.crt_static(target) { - cargo.env("RUSTC_CRT_STATIC", x.to_string()); + if x { + rustflags.arg("-Ctarget-feature=+crt-static"); + } else { + rustflags.arg("-Ctarget-feature=-crt-static"); + } } if let Some(x) = self.crt_static(compiler.host) { @@ -1077,8 +1078,21 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_VERBOSE", self.verbosity.to_string()); - if self.config.deny_warnings { - cargo.env("RUSTC_DENY_WARNINGS", "1"); + if !mode.is_tool() { + // When extending this list, add the new lints to the RUSTFLAGS of the + // build_bootstrap function of src/bootstrap/bootstrap.py as well as + // some code doesn't go through this `rustc` wrapper. + rustflags.arg("-Wrust_2018_idioms"); + rustflags.arg("-Wunused_lifetimes"); + + if self.config.deny_warnings { + rustflags.arg("-Dwarnings"); + } + } + + if let Mode::Rustc | Mode::Codegen = mode { + rustflags.arg("-Zunstable-options"); + rustflags.arg("-Wrustc::internal"); } // Throughout the build Cargo can execute a number of build scripts @@ -1131,12 +1145,15 @@ impl<'a> Builder<'a> { } } - if (cmd == "build" || cmd == "rustc") - && mode == Mode::Std + if mode == Mode::Std && self.config.extended && compiler.is_final_stage(self) { - cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string()); + rustflags.arg("-Zsave-analysis"); + cargo.env("RUST_SAVE_ANALYSIS_CONFIG", + "{\"output_file\": null,\"full_docs\": false,\ + \"pub_only\": true,\"reachable_only\": false,\ + \"distro_crate\": true,\"signatures\": false,\"borrow_data\": false}"); } // For `cargo doc` invocations, make rustdoc print the Rust version into the docs @@ -1191,9 +1208,8 @@ impl<'a> Builder<'a> { match (mode, self.config.rust_codegen_units_std, self.config.rust_codegen_units) { (Mode::Std, Some(n), _) | - (Mode::Test, Some(n), _) | (_, _, Some(n)) => { - cargo.env("RUSTC_CODEGEN_UNITS", n.to_string()); + cargo.env(profile_var("CODEGEN_UNITS"), n.to_string()); } _ => { // Don't set anything @@ -1214,9 +1230,21 @@ impl<'a> Builder<'a> { cargo.arg("--frozen"); } + cargo.env("RUSTC_INSTALL_BINDIR", &self.config.bindir); + self.ci_env.force_coloring_in_ci(&mut cargo); - cargo + // When we build Rust dylibs they're all intended for intermediate + // usage, so make sure we pass the -Cprefer-dynamic flag instead of + // linking all deps statically into the dylib. + if let Mode::Std | Mode::Rustc | Mode::Codegen = mode { + rustflags.arg("-Cprefer-dynamic"); + } + + Cargo { + command: cargo, + rustflags, + } } /// Ensure that a given step is built, returning its output. This will @@ -1316,3 +1344,78 @@ impl<'a> Builder<'a> { #[cfg(test)] mod tests; + +#[derive(Debug)] +struct Rustflags(String); + +impl Rustflags { + fn new(target: &str) -> Rustflags { + let mut ret = Rustflags(String::new()); + + // Inherit `RUSTFLAGS` by default ... + ret.env("RUSTFLAGS"); + + // ... and also handle target-specific env RUSTFLAGS if they're + // configured. + let target_specific = format!("CARGO_TARGET_{}_RUSTFLAGS", crate::envify(target)); + ret.env(&target_specific); + + ret + } + + fn env(&mut self, env: &str) { + if let Ok(s) = env::var(env) { + for part in s.split_whitespace() { + self.arg(part); + } + } + } + + fn arg(&mut self, arg: &str) -> &mut Self { + assert_eq!(arg.split_whitespace().count(), 1); + if self.0.len() > 0 { + self.0.push_str(" "); + } + self.0.push_str(arg); + self + } +} + +#[derive(Debug)] +pub struct Cargo { + command: Command, + rustflags: Rustflags, +} + +impl Cargo { + pub fn rustflag(&mut self, arg: &str) -> &mut Cargo { + self.rustflags.arg(arg); + self + } + + pub fn arg(&mut self, arg: impl AsRef) -> &mut Cargo { + self.command.arg(arg.as_ref()); + self + } + + pub fn args(&mut self, args: I) -> &mut Cargo + where I: IntoIterator, S: AsRef + { + for arg in args { + self.arg(arg.as_ref()); + } + self + } + + pub fn env(&mut self, key: impl AsRef, value: impl AsRef) -> &mut Cargo { + self.command.env(key.as_ref(), value.as_ref()); + self + } +} + +impl From for Command { + fn from(mut cargo: Cargo) -> Command { + cargo.command.env("RUSTFLAGS", &cargo.rustflags.0); + cargo.command + } +} diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index d1542b1fca6b7..2bb90fdb04edc 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -365,27 +365,6 @@ fn dist_with_same_targets_and_hosts() { }, ] ); - assert_eq!( - first(builder.cache.all::()), - &[ - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - ] - ); assert_eq!( first(builder.cache.all::()), &[ @@ -415,7 +394,47 @@ fn build_default() { let b = INTERNER.intern_str("B"); let c = INTERNER.intern_str("C"); - assert!(!builder.cache.all::().is_empty()); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Std { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: b, stage: 2 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + compile::Std { + compiler: Compiler { host: b, stage: 2 }, + target: b, + }, + compile::Std { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + compile::Std { + compiler: Compiler { host: b, stage: 2 }, + target: c, + }, + ] + ); assert!(!builder.cache.all::().is_empty()); assert_eq!( first(builder.cache.all::()), @@ -450,63 +469,61 @@ fn build_default() { }, ] ); +} + +#[test] +fn build_with_target_flag() { + let mut config = configure(&["B"], &["C"]); + config.skip_only_host_steps = true; + let build = Build::new(config); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); + + let a = INTERNER.intern_str("A"); + let b = INTERNER.intern_str("B"); + let c = INTERNER.intern_str("C"); assert_eq!( - first(builder.cache.all::()), + first(builder.cache.all::()), &[ - compile::Test { + compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a, }, - compile::Test { + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a, }, - compile::Test { + compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a, }, - compile::Test { + compile::Std { compiler: Compiler { host: b, stage: 2 }, target: a, }, - compile::Test { + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b, }, - compile::Test { + compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b, }, - compile::Test { + compile::Std { compiler: Compiler { host: b, stage: 2 }, target: b, }, - compile::Test { + compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c, }, - compile::Test { + compile::Std { compiler: Compiler { host: b, stage: 2 }, target: c, }, ] ); -} - -#[test] -fn build_with_target_flag() { - let mut config = configure(&["B"], &["C"]); - config.skip_only_host_steps = true; - let build = Build::new(config); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); - - let a = INTERNER.intern_str("A"); - let b = INTERNER.intern_str("B"); - let c = INTERNER.intern_str("C"); - - assert!(!builder.cache.all::().is_empty()); assert_eq!( first(builder.cache.all::()), &[ @@ -541,48 +558,6 @@ fn build_with_target_flag() { }, ] ); - - assert_eq!( - first(builder.cache.all::()), - &[ - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: c, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: c, - }, - ] - ); } #[test] diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index c58a98bac3678..a4cb81d3d1b1b 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -46,7 +46,7 @@ fn cc2ar(cc: &Path, target: &str) -> Option { } else if target.contains("openbsd") { Some(PathBuf::from("ar")) } else if target.contains("vxworks") { - Some(PathBuf::from("vx-ar")) + Some(PathBuf::from("wr-ar")) } else { let parent = cc.parent().unwrap(); let file = cc.file_name().unwrap().to_str().unwrap(); diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 8e8d8f5e787a7..ef1b6e217a24f 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -13,7 +13,7 @@ use build_helper::output; use crate::Build; // The version number -pub const CFG_RELEASE_NUM: &str = "1.38.0"; +pub const CFG_RELEASE_NUM: &str = "1.40.0"; pub struct GitInfo { inner: Option, diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 11b082ac3f6d8..cadb9a7e441f2 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -1,6 +1,6 @@ //! Implementation of compiling the compiler and standard library, in "check"-based modes. -use crate::compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, rustc_cargo_env, +use crate::compile::{run_cargo, std_cargo, rustc_cargo, rustc_cargo_env, add_to_sysroot}; use crate::builder::{RunConfig, Builder, Kind, ShouldRun, Step}; use crate::tool::{prepare_tool_cargo, SourceType}; @@ -34,7 +34,7 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.all_krates("std") + run.all_krates("test") } fn make_run(run: RunConfig<'_>) { @@ -52,7 +52,7 @@ impl Step for Std { builder.info(&format!("Checking std artifacts ({} -> {})", &compiler.host, target)); run_cargo(builder, - &mut cargo, + cargo, args(builder.kind), &libstd_stamp(builder, compiler, target), true); @@ -92,7 +92,7 @@ impl Step for Rustc { let compiler = builder.compiler(0, builder.config.build); let target = self.target; - builder.ensure(Test { target }); + builder.ensure(Std { target }); let mut cargo = builder.cargo(compiler, Mode::Rustc, target, cargo_subcommand(builder.kind)); @@ -100,7 +100,7 @@ impl Step for Rustc { builder.info(&format!("Checking compiler artifacts ({} -> {})", &compiler.host, target)); run_cargo(builder, - &mut cargo, + cargo, args(builder.kind), &librustc_stamp(builder, compiler, target), true); @@ -152,54 +152,13 @@ impl Step for CodegenBackend { // We won't build LLVM if it's not available, as it shouldn't affect `check`. run_cargo(builder, - &mut cargo, + cargo, args(builder.kind), &codegen_backend_stamp(builder, compiler, target, backend), true); } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Test { - pub target: Interned, -} - -impl Step for Test { - type Output = (); - const DEFAULT: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.all_krates("test") - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Test { - target: run.target, - }); - } - - fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(0, builder.config.build); - let target = self.target; - - builder.ensure(Std { target }); - - let mut cargo = builder.cargo(compiler, Mode::Test, target, cargo_subcommand(builder.kind)); - test_cargo(builder, &compiler, target, &mut cargo); - - builder.info(&format!("Checking test artifacts ({} -> {})", &compiler.host, target)); - run_cargo(builder, - &mut cargo, - args(builder.kind), - &libtest_stamp(builder, compiler, target), - true); - - let libdir = builder.sysroot_libdir(compiler, target); - let hostdir = builder.sysroot_libdir(compiler, compiler.host); - add_to_sysroot(builder, &libdir, &hostdir, &libtest_stamp(builder, compiler, target)); - } -} - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Rustdoc { pub target: Interned, @@ -226,18 +185,18 @@ impl Step for Rustdoc { builder.ensure(Rustc { target }); - let mut cargo = prepare_tool_cargo(builder, - compiler, - Mode::ToolRustc, - target, - cargo_subcommand(builder.kind), - "src/tools/rustdoc", - SourceType::InTree, - &[]); + let cargo = prepare_tool_cargo(builder, + compiler, + Mode::ToolRustc, + target, + cargo_subcommand(builder.kind), + "src/tools/rustdoc", + SourceType::InTree, + &[]); println!("Checking rustdoc artifacts ({} -> {})", &compiler.host, target); run_cargo(builder, - &mut cargo, + cargo, args(builder.kind), &rustdoc_stamp(builder, compiler, target), true); @@ -245,7 +204,6 @@ impl Step for Rustdoc { let libdir = builder.sysroot_libdir(compiler, target); let hostdir = builder.sysroot_libdir(compiler, compiler.host); add_to_sysroot(&builder, &libdir, &hostdir, &rustdoc_stamp(builder, compiler, target)); - builder.cargo(compiler, Mode::ToolRustc, target, "clean"); } } @@ -259,16 +217,6 @@ pub fn libstd_stamp( builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp") } -/// Cargo's output path for libtest in a given stage, compiled by a particular -/// compiler for the specified target. -pub fn libtest_stamp( - builder: &Builder<'_>, - compiler: Compiler, - target: Interned, -) -> PathBuf { - builder.cargo_out(compiler, Mode::Test, target).join(".libtest-check.stamp") -} - /// Cargo's output path for librustc in a given stage, compiled by a particular /// compiler for the specified target. pub fn librustc_stamp( diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 4cd793adaf574..6ea32edfb208b 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -15,12 +15,13 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Stdio, exit}; use std::str; -use build_helper::{output, mtime, t, up_to_date}; +use build_helper::{output, t, up_to_date}; use filetime::FileTime; use serde::Deserialize; use serde_json; use crate::dist; +use crate::builder::Cargo; use crate::util::{exe, is_dylib}; use crate::{Compiler, Mode, GitRepo}; use crate::native; @@ -39,7 +40,7 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.all_krates("std") + run.all_krates("test") } fn make_run(run: RunConfig<'_>) { @@ -98,7 +99,7 @@ impl Step for Std { builder.info(&format!("Building stage{} std artifacts ({} -> {})", compiler.stage, &compiler.host, target)); run_cargo(builder, - &mut cargo, + cargo, vec![], &libstd_stamp(builder, compiler, target), false); @@ -156,7 +157,7 @@ fn copy_third_party_objects(builder: &Builder<'_>, compiler: &Compiler, target: pub fn std_cargo(builder: &Builder<'_>, compiler: &Compiler, target: Interned, - cargo: &mut Command) { + cargo: &mut Cargo) { if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") { cargo.env("MACOSX_DEPLOYMENT_TARGET", target); } @@ -212,21 +213,26 @@ pub fn std_cargo(builder: &Builder<'_>, emscripten: false, }); cargo.env("LLVM_CONFIG", llvm_config); + cargo.env("RUSTC_BUILD_SANITIZERS", "1"); } cargo.arg("--features").arg(features) .arg("--manifest-path") - .arg(builder.src.join("src/libstd/Cargo.toml")); + .arg(builder.src.join("src/libtest/Cargo.toml")); + // Help the libc crate compile by assisting it in finding various + // sysroot native libraries. if target.contains("musl") { if let Some(p) = builder.musl_root(target) { - cargo.env("MUSL_ROOT", p); + let root = format!("native={}/lib", p.to_str().unwrap()); + cargo.rustflag("-L").rustflag(&root); } } if target.ends_with("-wasi") { if let Some(p) = builder.wasi_root(target) { - cargo.env("WASI_ROOT", p); + let root = format!("native={}/lib/wasm32-wasi", p.to_str().unwrap()); + cargo.rustflag("-L").rustflag(&root); } } } @@ -274,8 +280,6 @@ impl Step for StdLink { // for reason why the sanitizers are not built in stage0. copy_apple_sanitizer_dylibs(builder, &builder.native_dir(target), "osx", &libdir); } - - builder.cargo(target_compiler, Mode::ToolStd, target, "clean"); } } @@ -360,131 +364,6 @@ impl Step for StartupObjects { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Test { - pub target: Interned, - pub compiler: Compiler, -} - -impl Step for Test { - type Output = (); - const DEFAULT: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.all_krates("test") - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Test { - compiler: run.builder.compiler(run.builder.top_stage, run.host), - target: run.target, - }); - } - - /// Builds libtest. - /// - /// This will build libtest and supporting libraries for a particular stage of - /// the build using the `compiler` targeting the `target` architecture. The - /// artifacts created will also be linked into the sysroot directory. - fn run(self, builder: &Builder<'_>) { - let target = self.target; - let compiler = self.compiler; - - builder.ensure(Std { compiler, target }); - - if builder.config.keep_stage.contains(&compiler.stage) { - builder.info("Warning: Using a potentially old libtest. This may not behave well."); - builder.ensure(TestLink { - compiler, - target_compiler: compiler, - target, - }); - return; - } - - let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); - if compiler_to_use != compiler { - builder.ensure(Test { - compiler: compiler_to_use, - target, - }); - builder.info( - &format!("Uplifting stage1 test ({} -> {})", builder.config.build, target)); - builder.ensure(TestLink { - compiler: compiler_to_use, - target_compiler: compiler, - target, - }); - return; - } - - let mut cargo = builder.cargo(compiler, Mode::Test, target, "build"); - test_cargo(builder, &compiler, target, &mut cargo); - - builder.info(&format!("Building stage{} test artifacts ({} -> {})", compiler.stage, - &compiler.host, target)); - run_cargo(builder, - &mut cargo, - vec![], - &libtest_stamp(builder, compiler, target), - false); - - builder.ensure(TestLink { - compiler: builder.compiler(compiler.stage, builder.config.build), - target_compiler: compiler, - target, - }); - } -} - -/// Same as `std_cargo`, but for libtest -pub fn test_cargo(builder: &Builder<'_>, - _compiler: &Compiler, - _target: Interned, - cargo: &mut Command) { - if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") { - cargo.env("MACOSX_DEPLOYMENT_TARGET", target); - } - cargo.arg("--manifest-path") - .arg(builder.src.join("src/libtest/Cargo.toml")); -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct TestLink { - pub compiler: Compiler, - pub target_compiler: Compiler, - pub target: Interned, -} - -impl Step for TestLink { - type Output = (); - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.never() - } - - /// Same as `std_link`, only for libtest - fn run(self, builder: &Builder<'_>) { - let compiler = self.compiler; - let target_compiler = self.target_compiler; - let target = self.target; - builder.info(&format!("Copying stage{} test from stage{} ({} -> {} / {})", - target_compiler.stage, - compiler.stage, - &compiler.host, - target_compiler.host, - target)); - add_to_sysroot( - builder, - &builder.sysroot_libdir(target_compiler, target), - &builder.sysroot_libdir(target_compiler, compiler.host), - &libtest_stamp(builder, compiler, target) - ); - - builder.cargo(target_compiler, Mode::ToolTest, target, "clean"); - } -} - #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] pub struct Rustc { pub target: Interned, @@ -516,7 +395,7 @@ impl Step for Rustc { let compiler = self.compiler; let target = self.target; - builder.ensure(Test { compiler, target }); + builder.ensure(Std { compiler, target }); if builder.config.keep_stage.contains(&compiler.stage) { builder.info("Warning: Using a potentially old librustc. This may not behave well."); @@ -545,7 +424,7 @@ impl Step for Rustc { } // Ensure that build scripts and proc macros have a std / libproc_macro to link against. - builder.ensure(Test { + builder.ensure(Std { compiler: builder.compiler(self.compiler.stage, builder.config.build), target: builder.config.build, }); @@ -556,7 +435,7 @@ impl Step for Rustc { builder.info(&format!("Building stage{} compiler artifacts ({} -> {})", compiler.stage, &compiler.host, target)); run_cargo(builder, - &mut cargo, + cargo, vec![], &librustc_stamp(builder, compiler, target), false); @@ -569,14 +448,14 @@ impl Step for Rustc { } } -pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Command) { +pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo) { cargo.arg("--features").arg(builder.rustc_features()) .arg("--manifest-path") .arg(builder.src.join("src/rustc/Cargo.toml")); rustc_cargo_env(builder, cargo); } -pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Command) { +pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo) { // Set some configuration variables picked up by build scripts and // the compiler alike cargo.env("CFG_RELEASE", builder.rust_release()) @@ -601,7 +480,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Command) { cargo.env("CFG_DEFAULT_LINKER", s); } if builder.config.rustc_parallel { - cargo.env("RUSTC_PARALLEL_COMPILER", "1"); + cargo.rustflag("--cfg=parallel_compiler"); } if builder.config.rust_verify_llvm_ir { cargo.env("RUSTC_VERIFY_LLVM_IR", "1"); @@ -639,7 +518,6 @@ impl Step for RustcLink { &builder.sysroot_libdir(target_compiler, compiler.host), &librustc_stamp(builder, compiler, target) ); - builder.cargo(target_compiler, Mode::ToolRustc, target, "clean"); } } @@ -704,14 +582,11 @@ impl Step for CodegenBackend { rustc_cargo_env(builder, &mut cargo); let features = build_codegen_backend(&builder, &mut cargo, &compiler, target, backend); + cargo.arg("--features").arg(features); let tmp_stamp = out_dir.join(".tmp.stamp"); - let files = run_cargo(builder, - cargo.arg("--features").arg(features), - vec![], - &tmp_stamp, - false); + let files = run_cargo(builder, cargo, vec![], &tmp_stamp, false); if builder.config.dry_run { return; } @@ -736,7 +611,7 @@ impl Step for CodegenBackend { } pub fn build_codegen_backend(builder: &Builder<'_>, - cargo: &mut Command, + cargo: &mut Cargo, compiler: &Compiler, target: Interned, backend: Interned) -> String { @@ -795,6 +670,9 @@ pub fn build_codegen_backend(builder: &Builder<'_>, if builder.config.llvm_use_libcxx { cargo.env("LLVM_USE_LIBCXX", "1"); } + if builder.config.llvm_optimize && !builder.config.llvm_release_debuginfo { + cargo.env("LLVM_NDEBUG", "1"); + } } _ => panic!("unknown backend: {}", backend), } @@ -874,16 +752,6 @@ pub fn libstd_stamp( builder.cargo_out(compiler, Mode::Std, target).join(".libstd.stamp") } -/// Cargo's output path for libtest in a given stage, compiled by a particular -/// compiler for the specified target. -pub fn libtest_stamp( - builder: &Builder<'_>, - compiler: Compiler, - target: Interned, -) -> PathBuf { - builder.cargo_out(compiler, Mode::Test, target).join(".libtest.stamp") -} - /// Cargo's output path for librustc in a given stage, compiled by a particular /// compiler for the specified target. pub fn librustc_stamp( @@ -1083,7 +951,7 @@ pub fn add_to_sysroot( } pub fn run_cargo(builder: &Builder<'_>, - cargo: &mut Command, + cargo: Cargo, tail_args: Vec, stamp: &Path, is_check: bool) @@ -1116,10 +984,6 @@ pub fn run_cargo(builder: &Builder<'_>, }, .. } => (filenames, crate_types), - CargoMessage::CompilerMessage { message } => { - eprintln!("{}", message.rendered); - return; - } _ => return, }; for filename in filenames { @@ -1206,58 +1070,35 @@ pub fn run_cargo(builder: &Builder<'_>, deps.push((path_to_add.into(), false)); } - // Now we want to update the contents of the stamp file, if necessary. First - // we read off the previous contents along with its mtime. If our new - // contents (the list of files to copy) is different or if any dep's mtime - // is newer then we rewrite the stamp file. deps.sort(); - let stamp_contents = fs::read(stamp); - let stamp_mtime = mtime(&stamp); let mut new_contents = Vec::new(); - let mut max = None; - let mut max_path = None; for (dep, proc_macro) in deps.iter() { - let mtime = mtime(dep); - if Some(mtime) > max { - max = Some(mtime); - max_path = Some(dep.clone()); - } new_contents.extend(if *proc_macro { b"h" } else { b"t" }); new_contents.extend(dep.to_str().unwrap().as_bytes()); new_contents.extend(b"\0"); } - let max = max.unwrap(); - let max_path = max_path.unwrap(); - let contents_equal = stamp_contents - .map(|contents| contents == new_contents) - .unwrap_or_default(); - if contents_equal && max <= stamp_mtime { - builder.verbose(&format!("not updating {:?}; contents equal and {:?} <= {:?}", - stamp, max, stamp_mtime)); - return deps.into_iter().map(|(d, _)| d).collect() - } - if max > stamp_mtime { - builder.verbose(&format!("updating {:?} as {:?} changed", stamp, max_path)); - } else { - builder.verbose(&format!("updating {:?} as deps changed", stamp)); - } t!(fs::write(&stamp, &new_contents)); deps.into_iter().map(|(d, _)| d).collect() } pub fn stream_cargo( builder: &Builder<'_>, - cargo: &mut Command, + cargo: Cargo, tail_args: Vec, cb: &mut dyn FnMut(CargoMessage<'_>), ) -> bool { + let mut cargo = Command::from(cargo); if builder.config.dry_run { return true; } // Instruct Cargo to give us json messages on stdout, critically leaving // stderr as piped so we can get those pretty colors. - cargo.arg("--message-format").arg("json") - .stdout(Stdio::piped()); + let mut message_format = String::from("json-render-diagnostics"); + if let Some(s) = &builder.config.rustc_error_format { + message_format.push_str(",json-diagnostic-"); + message_format.push_str(s); + } + cargo.arg("--message-format").arg(message_format).stdout(Stdio::piped()); for arg in tail_args { cargo.arg(arg); @@ -1310,12 +1151,4 @@ pub enum CargoMessage<'a> { BuildScriptExecuted { package_id: Cow<'a, str>, }, - CompilerMessage { - message: ClippyMessage<'a> - } -} - -#[derive(Deserialize)] -pub struct ClippyMessage<'a> { - rendered: Cow<'a, str>, } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index a5bfafdfdb4dc..52b5cd888df9c 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -122,7 +122,6 @@ pub struct Config { // libstd features pub backtrace: bool, // support for RUST_BACKTRACE - pub wasm_syscall: bool, // misc pub low_priority: bool, @@ -138,7 +137,7 @@ pub struct Config { pub sysconfdir: Option, pub datadir: Option, pub docdir: Option, - pub bindir: Option, + pub bindir: PathBuf, pub libdir: Option, pub mandir: Option, pub codegen_tests: bool, @@ -318,7 +317,6 @@ struct Rust { save_toolstates: Option, codegen_backends: Option>, codegen_backends_dir: Option, - wasm_syscall: Option, lld: Option, lldb: Option, llvm_tools: Option, @@ -402,6 +400,7 @@ impl Config { config.incremental = flags.incremental; config.dry_run = flags.dry_run; config.keep_stage = flags.keep_stage; + config.bindir = "bin".into(); // default if let Some(value) = flags.deny_warnings { config.deny_warnings = value; } @@ -484,7 +483,7 @@ impl Config { config.sysconfdir = install.sysconfdir.clone().map(PathBuf::from); config.datadir = install.datadir.clone().map(PathBuf::from); config.docdir = install.docdir.clone().map(PathBuf::from); - config.bindir = install.bindir.clone().map(PathBuf::from); + set(&mut config.bindir, install.bindir.clone().map(PathBuf::from)); config.libdir = install.libdir.clone().map(PathBuf::from); config.mandir = install.mandir.clone().map(PathBuf::from); } @@ -558,7 +557,6 @@ impl Config { if let Some(true) = rust.incremental { config.incremental = true; } - set(&mut config.wasm_syscall, rust.wasm_syscall); set(&mut config.lld_enabled, rust.lld); set(&mut config.lldb_enabled, rust.lldb); set(&mut config.llvm_tools_enabled, rust.llvm_tools); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index bd012a887c26e..e5a43dcb29f63 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -18,7 +18,7 @@ use build_helper::{output, t}; use crate::{Compiler, Mode, LLVM_TOOLS}; use crate::channel; -use crate::util::{is_dylib, exe}; +use crate::util::{is_dylib, exe, timeit}; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::compile; use crate::tool::{self, Tool}; @@ -91,14 +91,15 @@ impl Step for Docs { let name = pkgname(builder, "rust-docs"); - builder.info(&format!("Dist docs ({})", host)); if !builder.config.docs { - builder.info("\tskipping - docs disabled"); return distdir(builder).join(format!("{}-{}.tar.gz", name, host)); } builder.default_doc(None); + builder.info(&format!("Dist docs ({})", host)); + let _time = timeit(builder); + let image = tmpdir(builder).join(format!("{}-{}-image", name, host)); let _ = fs::remove_dir_all(&image); @@ -151,9 +152,7 @@ impl Step for RustcDocs { let name = pkgname(builder, "rustc-docs"); - builder.info(&format!("Dist compiler docs ({})", host)); if !builder.config.compiler_docs { - builder.info("\tskipping - compiler docs disabled"); return distdir(builder).join(format!("{}-{}.tar.gz", name, host)); } @@ -179,6 +178,9 @@ impl Step for RustcDocs { .arg("--component-name=rustc-docs") .arg("--legacy-manifest-dirs=rustlib,cargo") .arg("--bulk-dirs=share/doc/rust/html"); + + builder.info(&format!("Dist compiler docs ({})", host)); + let _time = timeit(builder); builder.run(&mut cmd); builder.remove_dir(&image); @@ -350,6 +352,7 @@ impl Step for Mingw { } builder.info(&format!("Dist mingw ({})", host)); + let _time = timeit(builder); let name = pkgname(builder, "rust-mingw"); let image = tmpdir(builder).join(format!("{}-{}-image", name, host)); let _ = fs::remove_dir_all(&image); @@ -403,7 +406,6 @@ impl Step for Rustc { let compiler = self.compiler; let host = self.compiler.host; - builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, host)); let name = pkgname(builder, "rustc"); let image = tmpdir(builder).join(format!("{}-{}-image", name, host)); let _ = fs::remove_dir_all(&image); @@ -460,6 +462,9 @@ impl Step for Rustc { .arg(format!("--package-name={}-{}", name, host)) .arg("--component-name=rustc") .arg("--legacy-manifest-dirs=rustlib,cargo"); + + builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, host)); + let _time = timeit(builder); builder.run(&mut cmd); builder.remove_dir(&image); builder.remove_dir(&overlay); @@ -469,7 +474,6 @@ impl Step for Rustc { fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) { let host = compiler.host; let src = builder.sysroot(compiler); - let libdir = builder.rustc_libdir(compiler); // Copy rustc/rustdoc binaries t!(fs::create_dir_all(image.join("bin"))); @@ -481,11 +485,14 @@ impl Step for Rustc { // Copy runtime DLLs needed by the compiler if libdir_relative.to_str() != Some("bin") { + let libdir = builder.rustc_libdir(compiler); for entry in builder.read_dir(&libdir) { let name = entry.file_name(); if let Some(s) = name.to_str() { if is_dylib(s) { - builder.install(&entry.path(), &image.join(&libdir_relative), 0o644); + // Don't use custom libdir here because ^lib/ will be resolved again + // with installer + builder.install(&entry.path(), &image.join("lib"), 0o644); } } } @@ -493,8 +500,11 @@ impl Step for Rustc { // Copy over the codegen backends let backends_src = builder.sysroot_codegen_backends(compiler); - let backends_rel = backends_src.strip_prefix(&src).unwrap(); - let backends_dst = image.join(&backends_rel); + let backends_rel = backends_src.strip_prefix(&src).unwrap() + .strip_prefix(builder.sysroot_libdir_relative(compiler)).unwrap(); + // Don't use custom libdir here because ^lib/ will be resolved again with installer + let backends_dst = image.join("lib").join(&backends_rel); + t!(fs::create_dir_all(&backends_dst)); builder.cp_r(&backends_src, &backends_dst); @@ -627,6 +637,28 @@ impl Step for DebuggerScripts { } } +fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool { + // The only true set of target libraries came from the build triple, so + // let's reduce redundant work by only producing archives from that host. + if compiler.host != builder.config.build { + builder.info("\tskipping, not a build host"); + true + } else { + false + } +} + +/// Copy stamped files into an image's `target/lib` directory. +fn copy_target_libs(builder: &Builder<'_>, target: &str, image: &Path, stamp: &Path) { + let dst = image.join("lib/rustlib").join(target).join("lib"); + t!(fs::create_dir_all(&dst)); + for (path, host) in builder.read_stamp_file(stamp) { + if !host || builder.config.build == target { + builder.copy(&path, &dst.join(path.file_name().unwrap())); + } + } +} + #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Std { pub compiler: Compiler, @@ -657,66 +689,104 @@ impl Step for Std { let target = self.target; let name = pkgname(builder, "rust-std"); + let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target)); + if skip_host_target_lib(builder, compiler) { + return archive; + } + + builder.ensure(compile::Std { compiler, target }); + + let image = tmpdir(builder).join(format!("{}-{}-image", name, target)); + let _ = fs::remove_dir_all(&image); + + let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); + let stamp = compile::libstd_stamp(builder, compiler_to_use, target); + copy_target_libs(builder, &target, &image, &stamp); + + let mut cmd = rust_installer(builder); + cmd.arg("generate") + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=std-is-standing-at-the-ready.") + .arg("--image-dir").arg(&image) + .arg("--work-dir").arg(&tmpdir(builder)) + .arg("--output-dir").arg(&distdir(builder)) + .arg(format!("--package-name={}-{}", name, target)) + .arg(format!("--component-name=rust-std-{}", target)) + .arg("--legacy-manifest-dirs=rustlib,cargo"); + builder.info(&format!("Dist std stage{} ({} -> {})", compiler.stage, &compiler.host, target)); + let _time = timeit(builder); + builder.run(&mut cmd); + builder.remove_dir(&image); + archive + } +} - // The only true set of target libraries came from the build triple, so - // let's reduce redundant work by only producing archives from that host. - if compiler.host != builder.config.build { - builder.info("\tskipping, not a build host"); - return distdir(builder).join(format!("{}-{}.tar.gz", name, target)); - } +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +pub struct RustcDev { + pub compiler: Compiler, + pub target: Interned, +} - // We want to package up as many target libraries as possible - // for the `rust-std` package, so if this is a host target we - // depend on librustc and otherwise we just depend on libtest. - if builder.hosts.iter().any(|t| t == target) { - builder.ensure(compile::Rustc { compiler, target }); - } else { - if builder.no_std(target) == Some(true) { - // the `test` doesn't compile for no-std targets - builder.ensure(compile::Std { compiler, target }); - } else { - builder.ensure(compile::Test { compiler, target }); - } +impl Step for RustcDev { + type Output = PathBuf; + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("rustc-dev") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(RustcDev { + compiler: run.builder.compiler_for( + run.builder.top_stage, + run.builder.config.build, + run.target, + ), + target: run.target, + }); + } + + fn run(self, builder: &Builder<'_>) -> PathBuf { + let compiler = self.compiler; + let target = self.target; + + let name = pkgname(builder, "rustc-dev"); + let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target)); + if skip_host_target_lib(builder, compiler) { + return archive; } + builder.ensure(compile::Rustc { compiler, target }); + let image = tmpdir(builder).join(format!("{}-{}-image", name, target)); let _ = fs::remove_dir_all(&image); - let dst = image.join("lib/rustlib").join(target); - t!(fs::create_dir_all(&dst)); - let mut src = builder.sysroot_libdir(compiler, target).to_path_buf(); - src.pop(); // Remove the trailing /lib folder from the sysroot_libdir - builder.cp_filtered(&src, &dst, &|path| { - if let Some(name) = path.file_name().and_then(|s| s.to_str()) { - if name == builder.config.rust_codegen_backends_dir.as_str() { - return false - } - if name == "bin" { - return false - } - if name.contains("LLVM") { - return false - } - } - true - }); + let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); + let stamp = compile::librustc_stamp(builder, compiler_to_use, target); + copy_target_libs(builder, &target, &image, &stamp); let mut cmd = rust_installer(builder); cmd.arg("generate") .arg("--product-name=Rust") .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=std-is-standing-at-the-ready.") + .arg("--success-message=Rust-is-ready-to-develop.") .arg("--image-dir").arg(&image) .arg("--work-dir").arg(&tmpdir(builder)) .arg("--output-dir").arg(&distdir(builder)) .arg(format!("--package-name={}-{}", name, target)) - .arg(format!("--component-name=rust-std-{}", target)) + .arg(format!("--component-name=rustc-dev-{}", target)) .arg("--legacy-manifest-dirs=rustlib,cargo"); + + builder.info(&format!("Dist rustc-dev stage{} ({} -> {})", + compiler.stage, &compiler.host, target)); + let _time = timeit(builder); builder.run(&mut cmd); builder.remove_dir(&image); - distdir(builder).join(format!("{}-{}.tar.gz", name, target)) + archive } } @@ -754,15 +824,13 @@ impl Step for Analysis { let compiler = self.compiler; let target = self.target; assert!(builder.config.extended); - builder.info("Dist analysis"); let name = pkgname(builder, "rust-analysis"); if &compiler.host != builder.config.build { - builder.info("\tskipping, not a build host"); return distdir(builder).join(format!("{}-{}.tar.gz", name, target)); } - builder.ensure(Std { compiler, target }); + builder.ensure(compile::Std { compiler, target }); let image = tmpdir(builder).join(format!("{}-{}-image", name, target)); @@ -786,6 +854,9 @@ impl Step for Analysis { .arg(format!("--package-name={}-{}", name, target)) .arg(format!("--component-name=rust-analysis-{}", target)) .arg("--legacy-manifest-dirs=rustlib,cargo"); + + builder.info("Dist analysis"); + let _time = timeit(builder); builder.run(&mut cmd); builder.remove_dir(&image); distdir(builder).join(format!("{}-{}.tar.gz", name, target)) @@ -808,6 +879,7 @@ fn copy_src_dirs(builder: &Builder<'_>, src_dirs: &[&str], exclude_dirs: &[&str] "llvm-project/lld", "llvm-project\\lld", "llvm-project/lldb", "llvm-project\\lldb", "llvm-project/llvm", "llvm-project\\llvm", + "llvm-project/compiler-rt", "llvm-project\\compiler-rt", ]; if spath.contains("llvm-project") && !spath.ends_with("llvm-project") && !LLVM_PROJECTS.iter().any(|path| spath.contains(path)) @@ -873,8 +945,6 @@ impl Step for Src { /// Creates the `rust-src` installer component fn run(self, builder: &Builder<'_>) -> PathBuf { - builder.info("Dist src"); - let name = pkgname(builder, "rust-src"); let image = tmpdir(builder).join(format!("{}-image", name)); let _ = fs::remove_dir_all(&image); @@ -907,6 +977,7 @@ impl Step for Src { "src/libproc_macro", "src/tools/rustc-std-workspace-core", "src/tools/rustc-std-workspace-alloc", + "src/tools/rustc-std-workspace-std", "src/librustc", "src/libsyntax", ]; @@ -928,6 +999,9 @@ impl Step for Src { .arg(format!("--package-name={}", name)) .arg("--component-name=rust-src") .arg("--legacy-manifest-dirs=rustlib,cargo"); + + builder.info("Dist src"); + let _time = timeit(builder); builder.run(&mut cmd); builder.remove_dir(&image); @@ -955,8 +1029,6 @@ impl Step for PlainSourceTarball { /// Creates the plain source tarball fn run(self, builder: &Builder<'_>) -> PathBuf { - builder.info("Create plain source tarball"); - // Make sure that the root folder of tarball has the correct name let plain_name = format!("{}-src", pkgname(builder, "rustc")); let plain_dst_src = tmpdir(builder).join(&plain_name); @@ -1018,6 +1090,9 @@ impl Step for PlainSourceTarball { .arg("--output").arg(&tarball) .arg("--work-dir=.") .current_dir(tmpdir(builder)); + + builder.info("Create plain source tarball"); + let _time = timeit(builder); builder.run(&mut cmd); distdir(builder).join(&format!("{}.tar.gz", plain_name)) } @@ -1071,7 +1146,6 @@ impl Step for Cargo { let compiler = self.compiler; let target = self.target; - builder.info(&format!("Dist cargo stage{} ({})", compiler.stage, target)); let src = builder.src.join("src/tools/cargo"); let etc = src.join("src/etc"); let release_num = builder.release_num("cargo"); @@ -1124,6 +1198,9 @@ impl Step for Cargo { .arg(format!("--package-name={}-{}", name, target)) .arg("--component-name=cargo") .arg("--legacy-manifest-dirs=rustlib,cargo"); + + builder.info(&format!("Dist cargo stage{} ({})", compiler.stage, target)); + let _time = timeit(builder); builder.run(&mut cmd); distdir(builder).join(format!("{}-{}.tar.gz", name, target)) } @@ -1159,7 +1236,6 @@ impl Step for Rls { let target = self.target; assert!(builder.config.extended); - builder.info(&format!("Dist RLS stage{} ({})", compiler.stage, target)); let src = builder.src.join("src/tools/rls"); let release_num = builder.release_num("rls"); let name = pkgname(builder, "rls"); @@ -1208,6 +1284,8 @@ impl Step for Rls { .arg("--legacy-manifest-dirs=rustlib,cargo") .arg("--component-name=rls-preview"); + builder.info(&format!("Dist RLS stage{} ({})", compiler.stage, target)); + let _time = timeit(builder); builder.run(&mut cmd); Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) } @@ -1243,7 +1321,6 @@ impl Step for Clippy { let target = self.target; assert!(builder.config.extended); - builder.info(&format!("Dist clippy stage{} ({})", compiler.stage, target)); let src = builder.src.join("src/tools/clippy"); let release_num = builder.release_num("clippy"); let name = pkgname(builder, "clippy"); @@ -1297,6 +1374,8 @@ impl Step for Clippy { .arg("--legacy-manifest-dirs=rustlib,cargo") .arg("--component-name=clippy-preview"); + builder.info(&format!("Dist clippy stage{} ({})", compiler.stage, target)); + let _time = timeit(builder); builder.run(&mut cmd); Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) } @@ -1332,7 +1411,6 @@ impl Step for Miri { let target = self.target; assert!(builder.config.extended); - builder.info(&format!("Dist miri stage{} ({})", compiler.stage, target)); let src = builder.src.join("src/tools/miri"); let release_num = builder.release_num("miri"); let name = pkgname(builder, "miri"); @@ -1387,6 +1465,8 @@ impl Step for Miri { .arg("--legacy-manifest-dirs=rustlib,cargo") .arg("--component-name=miri-preview"); + builder.info(&format!("Dist miri stage{} ({})", compiler.stage, target)); + let _time = timeit(builder); builder.run(&mut cmd); Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) } @@ -1421,7 +1501,6 @@ impl Step for Rustfmt { let compiler = self.compiler; let target = self.target; - builder.info(&format!("Dist Rustfmt stage{} ({})", compiler.stage, target)); let src = builder.src.join("src/tools/rustfmt"); let release_num = builder.release_num("rustfmt"); let name = pkgname(builder, "rustfmt"); @@ -1474,6 +1553,8 @@ impl Step for Rustfmt { .arg("--legacy-manifest-dirs=rustlib,cargo") .arg("--component-name=rustfmt-preview"); + builder.info(&format!("Dist Rustfmt stage{} ({})", compiler.stage, target)); + let _time = timeit(builder); builder.run(&mut cmd); Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) } @@ -1574,6 +1655,7 @@ impl Step for Extended { input_tarballs.push(tarball); } + builder.info("building combined installer"); let mut cmd = rust_installer(builder); cmd.arg("combine") .arg("--product-name=Rust") @@ -1585,7 +1667,9 @@ impl Step for Extended { .arg("--legacy-manifest-dirs=rustlib,cargo") .arg("--input-tarballs").arg(input_tarballs) .arg("--non-installed-overlay").arg(&overlay); + let time = timeit(&builder); builder.run(&mut cmd); + drop(time); let mut license = String::new(); license += &builder.read(&builder.src.join("COPYRIGHT")); @@ -1641,6 +1725,7 @@ impl Step for Extended { }; if target.contains("apple-darwin") { + builder.info("building pkg installer"); let pkg = tmp.join("pkg"); let _ = fs::remove_dir_all(&pkg); @@ -1690,6 +1775,7 @@ impl Step for Extended { pkgname(builder, "rust"), target))) .arg("--package-path").arg(&pkg); + let _time = timeit(builder); builder.run(&mut cmd); } @@ -1740,14 +1826,18 @@ impl Step for Extended { builder.create(&exe.join("LICENSE.txt"), &license); // Generate exe installer + builder.info("building `exe` installer with `iscc`"); let mut cmd = Command::new("iscc"); cmd.arg("rust.iss") + .arg("/Q") .current_dir(&exe); if target.contains("windows-gnu") { cmd.arg("/dMINGW"); } add_env(builder, &mut cmd, target); + let time = timeit(builder); builder.run(&mut cmd); + drop(time); builder.install(&exe.join(format!("{}-{}.exe", pkgname(builder, "rust"), target)), &distdir(builder), 0o755); @@ -1912,6 +2002,7 @@ impl Step for Extended { builder.install(&etc.join("gfx/banner.bmp"), &exe, 0o644); builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644); + builder.info(&format!("building `msi` installer with {:?}", light)); let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target); let mut cmd = Command::new(&light); cmd.arg("-nologo") @@ -1944,6 +2035,7 @@ impl Step for Extended { // ICE57 wrongly complains about the shortcuts cmd.arg("-sice:ICE57"); + let _time = timeit(builder); builder.run(&mut cmd); if !builder.config.dry_run { @@ -1998,6 +2090,8 @@ impl Step for HashSign { } fn run(self, builder: &Builder<'_>) { + // This gets called by `promote-release` + // (https://github.com/rust-lang/rust-central-station/tree/master/promote-release). let mut cmd = builder.tool_cmd(Tool::BuildManifest); if builder.config.dry_run { return; @@ -2008,10 +2102,14 @@ impl Step for HashSign { let addr = builder.config.dist_upload_addr.as_ref().unwrap_or_else(|| { panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n") }); - let file = builder.config.dist_gpg_password_file.as_ref().unwrap_or_else(|| { - panic!("\n\nfailed to specify `dist.gpg-password-file` in `config.toml`\n\n") - }); - let pass = t!(fs::read_to_string(&file)); + let pass = if env::var("BUILD_MANIFEST_DISABLE_SIGNING").is_err() { + let file = builder.config.dist_gpg_password_file.as_ref().unwrap_or_else(|| { + panic!("\n\nfailed to specify `dist.gpg-password-file` in `config.toml`\n\n") + }); + t!(fs::read_to_string(&file)) + } else { + String::new() + }; let today = output(Command::new("date").arg("+%Y-%m-%d")); @@ -2106,6 +2204,7 @@ impl Step for LlvmTools { } builder.info(&format!("Dist LlvmTools ({})", target)); + let _time = timeit(builder); let src = builder.src.join("src/llvm-project/llvm"); let name = pkgname(builder, "llvm-tools"); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 36229720e42cd..4ee8cd2485c02 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -375,7 +375,7 @@ impl Step for Standalone { up_to_date(&footer, &html) && up_to_date(&favicon, &html) && up_to_date(&full_toc, &html) && - up_to_date(&version_info, &html) && + (builder.config.dry_run || up_to_date(&version_info, &html)) && (builder.config.dry_run || up_to_date(&rustdoc, &html)) { continue } @@ -413,7 +413,7 @@ impl Step for Std { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.all_krates("std").default_condition(builder.config.docs) + run.all_krates("test").default_condition(builder.config.docs) } fn make_run(run: RunConfig<'_>) { @@ -475,137 +475,11 @@ impl Step for Std { .arg("--resource-suffix").arg(crate::channel::CFG_RELEASE_NUM) .arg("--index-page").arg(&builder.src.join("src/doc/index.md")); - builder.run(&mut cargo); - builder.cp_r(&my_out, &out); + builder.run(&mut cargo.into()); }; - for krate in &["alloc", "core", "std"] { + for krate in &["alloc", "core", "std", "proc_macro", "test"] { run_cargo_rustdoc_for(krate); } - } -} - -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub struct Test { - stage: u32, - target: Interned, -} - -impl Step for Test { - type Output = (); - const DEFAULT: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - let builder = run.builder; - run.krate("test").default_condition(builder.config.docs) - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Test { - stage: run.builder.top_stage, - target: run.target, - }); - } - - /// Compile all libtest documentation. - /// - /// This will generate all documentation for libtest and its dependencies. This - /// is largely just a wrapper around `cargo doc`. - fn run(self, builder: &Builder<'_>) { - let stage = self.stage; - let target = self.target; - builder.info(&format!("Documenting stage{} test ({})", stage, target)); - let out = builder.doc_out(target); - t!(fs::create_dir_all(&out)); - let compiler = builder.compiler_for(stage, builder.config.build, target); - - // Build libstd docs so that we generate relative links - builder.ensure(Std { stage, target }); - - builder.ensure(compile::Test { compiler, target }); - let out_dir = builder.stage_out(compiler, Mode::Test) - .join(target).join("doc"); - - // See docs in std above for why we symlink - let my_out = builder.crate_doc_out(target); - t!(symlink_dir_force(&builder.config, &my_out, &out_dir)); - - let mut cargo = builder.cargo(compiler, Mode::Test, target, "doc"); - compile::test_cargo(builder, &compiler, target, &mut cargo); - - cargo.arg("--no-deps") - .arg("-p").arg("test") - .env("RUSTDOC_RESOURCE_SUFFIX", crate::channel::CFG_RELEASE_NUM) - .env("RUSTDOC_GENERATE_REDIRECT_PAGES", "1"); - - builder.run(&mut cargo); - builder.cp_r(&my_out, &out); - } -} - -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub struct WhitelistedRustc { - stage: u32, - target: Interned, -} - -impl Step for WhitelistedRustc { - type Output = (); - const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - let builder = run.builder; - run.krate("rustc-main").default_condition(builder.config.docs) - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(WhitelistedRustc { - stage: run.builder.top_stage, - target: run.target, - }); - } - - /// Generates whitelisted compiler crate documentation. - /// - /// This will generate all documentation for crates that are whitelisted - /// to be included in the standard documentation. This documentation is - /// included in the standard Rust documentation, so we should always - /// document it and symlink to merge with the rest of the std and test - /// documentation. We don't build other compiler documentation - /// here as we want to be able to keep it separate from the standard - /// documentation. This is largely just a wrapper around `cargo doc`. - fn run(self, builder: &Builder<'_>) { - let stage = self.stage; - let target = self.target; - builder.info(&format!("Documenting stage{} whitelisted compiler ({})", stage, target)); - let out = builder.doc_out(target); - t!(fs::create_dir_all(&out)); - let compiler = builder.compiler_for(stage, builder.config.build, target); - - // Build libstd docs so that we generate relative links - builder.ensure(Std { stage, target }); - - builder.ensure(compile::Rustc { compiler, target }); - let out_dir = builder.stage_out(compiler, Mode::Rustc) - .join(target).join("doc"); - - // See docs in std above for why we symlink - let my_out = builder.crate_doc_out(target); - t!(symlink_dir_force(&builder.config, &my_out, &out_dir)); - - let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc"); - compile::rustc_cargo(builder, &mut cargo); - - // We don't want to build docs for internal compiler dependencies in this - // step (there is another step for that). Therefore, we whitelist the crates - // for which docs must be built. - for krate in &["proc_macro"] { - cargo.arg("-p").arg(krate) - .env("RUSTDOC_RESOURCE_SUFFIX", crate::channel::CFG_RELEASE_NUM) - .env("RUSTDOC_GENERATE_REDIRECT_PAGES", "1"); - } - - builder.run(&mut cargo); builder.cp_r(&my_out, &out); } } @@ -687,7 +561,7 @@ impl Step for Rustc { cargo.arg("-p").arg(krate); } - builder.run(&mut cargo); + builder.run(&mut cargo.into()); } } @@ -782,7 +656,7 @@ impl Step for Rustdoc { cargo.arg("-p").arg("rustdoc"); cargo.env("RUSTDOCFLAGS", "--document-private-items"); - builder.run(&mut cargo); + builder.run(&mut cargo.into()); } } @@ -825,8 +699,7 @@ impl Step for ErrorIndex { index.arg(crate::channel::CFG_RELEASE_NUM); // FIXME: shouldn't have to pass this env var - index.env("CFG_BUILD", &builder.config.build) - .env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir()); + index.env("CFG_BUILD", &builder.config.build); builder.run(&mut index); } diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 828865f10ffba..d9580b598155e 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -36,7 +36,7 @@ pub struct Flags { // This overrides the deny-warnings configuation option, // which passes -Dwarnings to the compiler invocations. // - // true => deny, false => allow + // true => deny, false => warn pub deny_warnings: Option, } @@ -556,10 +556,10 @@ fn split(s: &[String]) -> Vec { fn parse_deny_warnings(matches: &getopts::Matches) -> Option { match matches.opt_str("warnings").as_ref().map(|v| v.as_str()) { Some("deny") => Some(true), - Some("allow") => Some(false), + Some("warn") => Some(false), Some(value) => { eprintln!( - r#"invalid value for --warnings: {:?}, expected "allow" or "deny""#, + r#"invalid value for --warnings: {:?}, expected "warn" or "deny""#, value, ); process::exit(1); diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 557586709c612..384219c38fd04 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -67,7 +67,6 @@ fn install_sh( let sysconfdir_default = PathBuf::from("/etc"); let datadir_default = PathBuf::from("share"); let docdir_default = datadir_default.join("doc/rust"); - let bindir_default = PathBuf::from("bin"); let libdir_default = PathBuf::from("lib"); let mandir_default = datadir_default.join("man"); let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| { @@ -76,7 +75,7 @@ fn install_sh( let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default); let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default); let docdir = builder.config.docdir.as_ref().unwrap_or(&docdir_default); - let bindir = builder.config.bindir.as_ref().unwrap_or(&bindir_default); + let bindir = &builder.config.bindir; let libdir = builder.config.libdir.as_ref().unwrap_or(&libdir_default); let mandir = builder.config.mandir.as_ref().unwrap_or(&mandir_default); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index b72aa78f3de19..9203a558f6465 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -103,9 +103,6 @@ //! More documentation can be found in each respective module below, and you can //! also check out the `src/bootstrap/README.md` file for more information. -// NO-RUSTC-WRAPPER -#![deny(warnings, rust_2018_idioms, unused_lifetimes)] - #![feature(core_intrinsics)] #![feature(drain_filter)] @@ -297,9 +294,6 @@ pub enum Mode { /// Build the standard library, placing output in the "stageN-std" directory. Std, - /// Build libtest, placing output in the "stageN-test" directory. - Test, - /// Build librustc, and compiler libraries, placing output in the "stageN-rustc" directory. Rustc, @@ -315,7 +309,6 @@ pub enum Mode { /// Compile a tool which uses all libraries we compile (up to rustc). /// Doesn't use the stage0 compiler libraries like "other", and includes /// tools like rustdoc, cargo, rls, etc. - ToolTest, ToolStd, ToolRustc, } @@ -502,9 +495,6 @@ impl Build { if self.config.profiler { features.push_str(" profiler"); } - if self.config.wasm_syscall { - features.push_str(" wasm_syscall"); - } features } @@ -536,11 +526,10 @@ impl Build { fn stage_out(&self, compiler: Compiler, mode: Mode) -> PathBuf { let suffix = match mode { Mode::Std => "-std", - Mode::Test => "-test", Mode::Rustc => "-rustc", Mode::Codegen => "-codegen", Mode::ToolBootstrap => "-bootstrap-tools", - Mode::ToolStd | Mode::ToolTest | Mode::ToolRustc => "-tools", + Mode::ToolStd | Mode::ToolRustc => "-tools", }; self.out.join(&*compiler.host) .join(format!("stage{}{}", compiler.stage, suffix)) @@ -1331,3 +1320,13 @@ impl Compiler { self.stage >= final_stage } } + +fn envify(s: &str) -> String { + s.chars() + .map(|c| match c { + '-' => '_', + c => c, + }) + .flat_map(|c| c.to_uppercase()) + .collect() +} diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 73d6fe532c8b3..e0a1f46078d32 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -81,5 +81,14 @@ ci-subset-1: ci-subset-2: $(Q)$(BOOTSTRAP) test $(TESTS_IN_2) +TESTS_IN_MINGW_2 := \ + src/test/ui \ + src/test/compile-fail + +ci-mingw-subset-1: + $(Q)$(BOOTSTRAP) test $(TESTS_IN_MINGW_2:%=--exclude %) +ci-mingw-subset-2: + $(Q)$(BOOTSTRAP) test $(TESTS_IN_MINGW_2) + .PHONY: dist diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index f02def3e1b05d..7bf9ea2688f4c 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -81,26 +81,29 @@ impl Step for Llvm { (info, "src/llvm-project/llvm", builder.llvm_out(target), dir.join("bin")) }; - if !llvm_info.is_git() { - println!( - "git could not determine the LLVM submodule commit hash. \ - Assuming that an LLVM build is necessary.", - ); - } - let build_llvm_config = llvm_config_ret_dir .join(exe("llvm-config", &*builder.config.build)); let done_stamp = out_dir.join("llvm-finished-building"); - if let Some(llvm_commit) = llvm_info.sha() { - if done_stamp.exists() { + if done_stamp.exists() { + if let Some(llvm_commit) = llvm_info.sha() { let done_contents = t!(fs::read(&done_stamp)); // If LLVM was already built previously and the submodule's commit didn't change // from the previous build, then no action is required. if done_contents == llvm_commit.as_bytes() { - return build_llvm_config + return build_llvm_config; } + } else { + builder.info( + "Could not determine the LLVM submodule commit hash. \ + Assuming that an LLVM rebuild is not necessary.", + ); + builder.info(&format!( + "To force LLVM to rebuild, remove the file `{}`", + done_stamp.display() + )); + return build_llvm_config; } } @@ -303,9 +306,7 @@ impl Step for Llvm { cfg.build(); - if let Some(llvm_commit) = llvm_info.sha() { - t!(fs::write(&done_stamp, llvm_commit)); - } + t!(fs::write(&done_stamp, llvm_info.sha().unwrap_or(""))); build_llvm_config } diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 4e3930c8da7fc..bffe748f37cc1 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -202,10 +202,6 @@ pub fn check(build: &mut Build) { panic!("couldn't find libc.a in musl dir: {}", root.join("lib").display()); } - if fs::metadata(root.join("lib/libunwind.a")).is_err() { - panic!("couldn't find libunwind.a in musl dir: {}", - root.join("lib").display()); - } } None => { panic!("when targeting MUSL either the rust.musl-root \ diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index c2c134bfd1d7d..b7ce9c7b39709 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -23,7 +23,7 @@ use crate::tool::{self, Tool, SourceType}; use crate::toolstate::ToolState; use crate::util::{self, dylib_path, dylib_path_var}; use crate::Crate as CargoCrate; -use crate::{DocTests, Mode, GitRepo}; +use crate::{DocTests, Mode, GitRepo, envify}; const ADB_TEST_DIR: &str = "/data/tmp/work"; @@ -233,10 +233,9 @@ impl Step for Cargo { // those features won't be able to land. cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1"); - try_run( - builder, - cargo.env("PATH", &path_for_cargo(builder, compiler)), - ); + cargo.env("PATH", &path_for_cargo(builder, compiler)); + + try_run(builder, &mut cargo.into()); } } @@ -290,7 +289,7 @@ impl Step for Rls { cargo.arg("--") .args(builder.config.cmd.test_args()); - if try_run(builder, &mut cargo) { + if try_run(builder, &mut cargo.into()) { builder.save_toolstate("rls", ToolState::TestPass); } } @@ -348,7 +347,7 @@ impl Step for Rustfmt { builder.add_rustc_lib_path(compiler, &mut cargo); - if try_run(builder, &mut cargo) { + if try_run(builder, &mut cargo.into()) { builder.save_toolstate("rustfmt", ToolState::TestPass); } } @@ -418,6 +417,7 @@ impl Step for Miri { cargo.env("CARGO_INSTALL_ROOT", &builder.out); // cargo adds a `bin/` cargo.env("XARGO", builder.out.join("bin").join("xargo")); + let mut cargo = Command::from(cargo); if !try_run(builder, &mut cargo) { return; } @@ -467,7 +467,7 @@ impl Step for Miri { builder.add_rustc_lib_path(compiler, &mut cargo); - if !try_run(builder, &mut cargo) { + if !try_run(builder, &mut cargo.into()) { return; } @@ -502,16 +502,16 @@ impl Step for CompiletestTest { let host = self.host; let compiler = builder.compiler(0, host); - let mut cargo = tool::prepare_tool_cargo(builder, - compiler, - Mode::ToolBootstrap, - host, - "test", - "src/tools/compiletest", - SourceType::InTree, - &[]); + let cargo = tool::prepare_tool_cargo(builder, + compiler, + Mode::ToolBootstrap, + host, + "test", + "src/tools/compiletest", + SourceType::InTree, + &[]); - try_run(builder, &mut cargo); + try_run(builder, &mut cargo.into()); } } @@ -571,7 +571,7 @@ impl Step for Clippy { builder.add_rustc_lib_path(compiler, &mut cargo); - if try_run(builder, &mut cargo) { + if try_run(builder, &mut cargo.into()) { builder.save_toolstate("clippy-driver", ToolState::TestPass); } } else { @@ -1040,21 +1040,10 @@ impl Step for Compiletest { builder.ensure(compile::Rustc { compiler, target }); } - if builder.no_std(target) == Some(true) { - // the `test` doesn't compile for no-std targets - builder.ensure(compile::Std { compiler, target }); - } else { - builder.ensure(compile::Test { compiler, target }); - } - - if builder.no_std(target) == Some(true) { - // for no_std run-make (e.g., thumb*), - // we need a host compiler which is called by cargo. - builder.ensure(compile::Std { compiler, target: compiler.host }); - } + builder.ensure(compile::Std { compiler, target }); + // ensure that `libproc_macro` is available on the host. + builder.ensure(compile::Std { compiler, target: compiler.host }); - // HACK(eddyb) ensure that `libproc_macro` is available on the host. - builder.ensure(compile::Test { compiler, target: compiler.host }); // Also provide `rust_test_helpers` for the host. builder.ensure(native::TestHelpers { target: compiler.host }); @@ -1338,7 +1327,10 @@ impl Step for Compiletest { cmd.env("RUSTC_PROFILER_SUPPORT", "1"); } - cmd.env("RUST_TEST_TMPDIR", builder.out.join("tmp")); + let tmp = builder.out.join("tmp"); + std::fs::create_dir_all(&tmp).unwrap(); + cmd.env("RUST_TEST_TMPDIR", tmp); + cmd.arg("--adb-path").arg("adb"); cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR); @@ -1399,7 +1391,7 @@ impl Step for DocTest { fn run(self, builder: &Builder<'_>) { let compiler = self.compiler; - builder.ensure(compile::Test { + builder.ensure(compile::Std { compiler, target: compiler.host, }); @@ -1535,8 +1527,7 @@ impl Step for ErrorIndex { ); tool.arg("markdown") .arg(&output) - .env("CFG_BUILD", &builder.config.build) - .env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir()); + .env("CFG_BUILD", &builder.config.build); builder.info(&format!("Testing error-index stage{}", compiler.stage)); let _time = util::timeit(&builder); @@ -1710,8 +1701,7 @@ impl Step for Crate { fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run = run.krate("test"); - for krate in run.builder.in_tree_crates("std") { + for krate in run.builder.in_tree_crates("test") { if !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) { run = run.path(krate.local_path(&builder).to_str().unwrap()); } @@ -1735,14 +1725,9 @@ impl Step for Crate { }); }; - for krate in builder.in_tree_crates("std") { - if run.path.ends_with(&krate.local_path(&builder)) { - make(Mode::Std, krate); - } - } for krate in builder.in_tree_crates("test") { if run.path.ends_with(&krate.local_path(&builder)) { - make(Mode::Test, krate); + make(Mode::Std, krate); } } } @@ -1762,7 +1747,7 @@ impl Step for Crate { let test_kind = self.test_kind; let krate = self.krate; - builder.ensure(compile::Test { compiler, target }); + builder.ensure(compile::Std { compiler, target }); builder.ensure(RemoteCopyLibs { compiler, target }); // If we're not doing a full bootstrap but we're testing a stage2 @@ -1776,9 +1761,6 @@ impl Step for Crate { Mode::Std => { compile::std_cargo(builder, &compiler, target, &mut cargo); } - Mode::Test => { - compile::test_cargo(builder, &compiler, target, &mut cargo); - } Mode::Rustc => { builder.ensure(compile::Rustc { compiler, target }); compile::rustc_cargo(builder, &mut cargo); @@ -1832,20 +1814,6 @@ impl Step for Crate { .expect("nodejs not configured"), ); } else if target.starts_with("wasm32") { - // Warn about running tests without the `wasm_syscall` feature enabled. - // The javascript shim implements the syscall interface so that test - // output can be correctly reported. - if !builder.config.wasm_syscall { - builder.info( - "Libstd was built without `wasm_syscall` feature enabled: \ - test output may not be visible." - ); - } - - // On the wasm32-unknown-unknown target we're using LTO which is - // incompatible with `-C prefer-dynamic`, so disable that here - cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); - let node = builder .config .nodejs @@ -1869,7 +1837,7 @@ impl Step for Crate { test_kind, krate, compiler.stage, &compiler.host, target )); let _time = util::timeit(&builder); - try_run(builder, &mut cargo); + try_run(builder, &mut cargo.into()); } } @@ -1937,20 +1905,10 @@ impl Step for CrateRustdoc { )); let _time = util::timeit(&builder); - try_run(builder, &mut cargo); + try_run(builder, &mut cargo.into()); } } -fn envify(s: &str) -> String { - s.chars() - .map(|c| match c { - '-' => '_', - c => c, - }) - .flat_map(|c| c.to_uppercase()) - .collect() -} - /// Some test suites are run inside emulators or on remote devices, and most /// of our test binaries are linked dynamically which means we need to ship /// the standard library and such to the emulator ahead of time. This step @@ -1980,7 +1938,7 @@ impl Step for RemoteCopyLibs { return; } - builder.ensure(compile::Test { compiler, target }); + builder.ensure(compile::Std { compiler, target }); builder.info(&format!("REMOTE copy libs to emulator ({})", target)); t!(fs::create_dir_all(builder.out.join("tmp"))); diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 15a329a5b9152..f1baeafe26afb 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -8,8 +8,8 @@ use build_helper::t; use crate::Mode; use crate::Compiler; -use crate::builder::{Step, RunConfig, ShouldRun, Builder}; -use crate::util::{exe, add_lib_path}; +use crate::builder::{Step, RunConfig, ShouldRun, Builder, Cargo as CargoCommand}; +use crate::util::{exe, add_lib_path, CiEnv}; use crate::compile; use crate::channel::GitInfo; use crate::channel; @@ -63,7 +63,7 @@ impl Step for ToolBuild { _ => panic!("unexpected Mode for tool build") } - let mut cargo = prepare_tool_cargo( + let cargo = prepare_tool_cargo( builder, compiler, self.mode, @@ -76,7 +76,7 @@ impl Step for ToolBuild { builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target)); let mut duplicates = Vec::new(); - let is_expected = compile::stream_cargo(builder, &mut cargo, vec![], &mut |msg| { + let is_expected = compile::stream_cargo(builder, cargo, vec![], &mut |msg| { // Only care about big things like the RLS/Cargo for now match tool { | "rls" @@ -229,15 +229,11 @@ pub fn prepare_tool_cargo( path: &'static str, source_type: SourceType, extra_features: &[String], -) -> Command { +) -> CargoCommand { let mut cargo = builder.cargo(compiler, mode, target, command); let dir = builder.src.join(path); cargo.arg("--manifest-path").arg(dir.join("Cargo.toml")); - // We don't want to build tools dynamically as they'll be running across - // stages and such and it's just easier if they're not dynamically linked. - cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); - if source_type == SourceType::Submodule { cargo.env("RUSTC_EXTERNAL_TOOL", "1"); } @@ -279,11 +275,26 @@ pub fn prepare_tool_cargo( cargo } +fn rustbook_features() -> Vec { + let mut features = Vec::new(); + + // Due to CI budged and risk of spurious failures we want to limit jobs running this check. + // At same time local builds should run it regardless of the platform. + // `CiEnv::None` means it's local build and `CHECK_LINKS` is defined in x86_64-gnu-tools to + // explicitly enable it on single job + if CiEnv::current() == CiEnv::None || env::var("CHECK_LINKS").is_ok() { + features.push("linkcheck".to_string()); + } + + features +} + macro_rules! bootstrap_tool { ($( $name:ident, $path:expr, $tool_name:expr $(,llvm_tools = $llvm:expr)* $(,is_external_tool = $external:expr)* + $(,features = $features:expr)* ; )+) => { #[derive(Copy, PartialEq, Eq, Clone)] @@ -350,7 +361,12 @@ macro_rules! bootstrap_tool { } else { SourceType::InTree }, - extra_features: Vec::new(), + extra_features: { + // FIXME(#60643): avoid this lint by using `_` + let mut _tmp = Vec::new(); + $(_tmp.extend($features);)* + _tmp + }, }).expect("expected to build -- essential tool") } } @@ -359,7 +375,7 @@ macro_rules! bootstrap_tool { } bootstrap_tool!( - Rustbook, "src/tools/rustbook", "rustbook"; + Rustbook, "src/tools/rustbook", "rustbook", features = rustbook_features(); UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen"; Tidy, "src/tools/tidy", "tidy"; Linkchecker, "src/tools/linkchecker", "linkchecker"; @@ -497,7 +513,7 @@ impl Step for Rustdoc { // libraries here. The intuition here is that If we've built a compiler, we should be able // to build rustdoc. - let mut cargo = prepare_tool_cargo( + let cargo = prepare_tool_cargo( builder, build_compiler, Mode::ToolRustc, @@ -510,7 +526,7 @@ impl Step for Rustdoc { builder.info(&format!("Building rustdoc for stage{} ({})", target_compiler.stage, target_compiler.host)); - builder.run(&mut cargo); + builder.run(&mut cargo.into()); // Cargo adds a number of paths to the dylib search path on windows, which results in // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" @@ -557,12 +573,6 @@ impl Step for Cargo { } fn run(self, builder: &Builder<'_>) -> PathBuf { - // Cargo depends on procedural macros, so make sure the host - // libstd/libproc_macro is available. - builder.ensure(compile::Test { - compiler: self.compiler, - target: builder.config.build, - }); builder.ensure(ToolBuild { compiler: self.compiler, target: self.target, @@ -630,31 +640,10 @@ macro_rules! tool_extended { tool_extended!((self, builder), Cargofmt, rustfmt, "src/tools/rustfmt", "cargo-fmt", {}; - CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", { - // Clippy depends on procedural macros, so make sure that's built for - // the compiler itself. - builder.ensure(compile::Test { - compiler: self.compiler, - target: builder.config.build, - }); - }; - Clippy, clippy, "src/tools/clippy", "clippy-driver", { - // Clippy depends on procedural macros, so make sure that's built for - // the compiler itself. - builder.ensure(compile::Test { - compiler: self.compiler, - target: builder.config.build, - }); - }; + CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", {}; + Clippy, clippy, "src/tools/clippy", "clippy-driver", {}; Miri, miri, "src/tools/miri", "miri", {}; - CargoMiri, miri, "src/tools/miri", "cargo-miri", { - // Miri depends on procedural macros, so make sure that's built for - // the compiler itself. - builder.ensure(compile::Test { - compiler: self.compiler, - target: builder.config.build, - }); - }; + CargoMiri, miri, "src/tools/miri", "cargo-miri", {}; Rls, rls, "src/tools/rls", "rls", { let clippy = builder.ensure(Clippy { compiler: self.compiler, @@ -664,12 +653,6 @@ tool_extended!((self, builder), if clippy.is_some() { self.extra_features.push("clippy".to_owned()); } - // RLS depends on procedural macros, so make sure that's built for - // the compiler itself. - builder.ensure(compile::Test { - compiler: self.compiler, - target: builder.config.build, - }); }; Rustfmt, rustfmt, "src/tools/rustfmt", "rustfmt", {}; ); diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index a1aa18922b5c5..f035a7119188a 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -1,6 +1,3 @@ -// NO-RUSTC-WRAPPER -#![deny(warnings, rust_2018_idioms, unused_lifetimes)] - use std::fs::File; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; @@ -262,7 +259,7 @@ pub fn native_lib_boilerplate( if !up_to_date(Path::new("build.rs"), ×tamp) || !up_to_date(src_dir, ×tamp) { Ok(NativeLibBoilerplate { src_dir: src_dir.to_path_buf(), - out_dir: out_dir, + out_dir, }) } else { Err(()) diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml index 687856cca6b62..5f7761297095c 100644 --- a/src/ci/azure-pipelines/auto.yml +++ b/src/ci/azure-pipelines/auto.yml @@ -7,7 +7,7 @@ trigger: - auto variables: -- group: real-prod-credentials +- group: prod-credentials jobs: - job: Linux @@ -236,10 +236,16 @@ jobs: MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc SCRIPT: make ci-subset-1 + # FIXME(#59637) + NO_DEBUG_ASSERTIONS: 1 + NO_LLVM_ASSERTIONS: 1 i686-msvc-2: MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc SCRIPT: make ci-subset-2 + # FIXME(#59637) + NO_DEBUG_ASSERTIONS: 1 + NO_LLVM_ASSERTIONS: 1 # MSVC aux tests x86_64-msvc-aux: MSYS_BITS: 64 @@ -250,6 +256,9 @@ jobs: SCRIPT: python x.py test src/tools/cargotest src/tools/cargo RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc VCVARS_BAT: vcvars64.bat + # FIXME(#59637) + NO_DEBUG_ASSERTIONS: 1 + NO_LLVM_ASSERTIONS: 1 # MSVC tools tests x86_64-msvc-tools: MSYS_BITS: 64 @@ -272,8 +281,8 @@ jobs: i686-mingw-1: MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu - SCRIPT: make ci-subset-1 - MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror + SCRIPT: make ci-mingw-subset-1 + MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z MINGW_DIR: mingw32 # FIXME(#59637) @@ -282,15 +291,15 @@ jobs: i686-mingw-2: MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu - SCRIPT: make ci-subset-2 - MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror + SCRIPT: make ci-mingw-subset-2 + MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z MINGW_DIR: mingw32 x86_64-mingw-1: MSYS_BITS: 64 - SCRIPT: make ci-subset-1 + SCRIPT: make ci-mingw-subset-1 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu - MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror + MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z MINGW_DIR: mingw64 # FIXME(#59637) @@ -298,9 +307,9 @@ jobs: NO_LLVM_ASSERTIONS: 1 x86_64-mingw-2: MSYS_BITS: 64 - SCRIPT: make ci-subset-2 + SCRIPT: make ci-mingw-subset-2 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu - MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror + MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z MINGW_DIR: mingw64 @@ -327,7 +336,7 @@ jobs: MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler SCRIPT: python x.py dist - MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror + MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z MINGW_DIR: mingw32 DIST_REQUIRE_ALL_TOOLS: 1 @@ -336,7 +345,7 @@ jobs: MSYS_BITS: 64 SCRIPT: python x.py dist RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler - MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror + MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z MINGW_DIR: mingw64 DIST_REQUIRE_ALL_TOOLS: 1 diff --git a/src/ci/azure-pipelines/master.yml b/src/ci/azure-pipelines/master.yml index 9742c71965851..e2baa923d99f7 100644 --- a/src/ci/azure-pipelines/master.yml +++ b/src/ci/azure-pipelines/master.yml @@ -7,7 +7,7 @@ trigger: - master variables: -- group: real-prod-credentials +- group: prod-credentials pool: vmImage: ubuntu-16.04 diff --git a/src/ci/azure-pipelines/steps/install-clang.yml b/src/ci/azure-pipelines/steps/install-clang.yml index 45ec767e0b875..14daf81b43075 100644 --- a/src/ci/azure-pipelines/steps/install-clang.yml +++ b/src/ci/azure-pipelines/steps/install-clang.yml @@ -36,7 +36,7 @@ steps: set -e mkdir -p citools cd citools - curl -f https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/LLVM-7.0.0-win64.tar.gz | tar xzf - + curl -f https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/LLVM-7.0.0-win64.tar.gz | tar xzf - echo "##vso[task.setvariable variable=RUST_CONFIGURE_ARGS]$RUST_CONFIGURE_ARGS --set llvm.clang-cl=`pwd`/clang-rust/bin/clang-cl.exe" condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['MINGW_URL'],'')) displayName: Install clang (Windows) diff --git a/src/ci/azure-pipelines/steps/install-sccache.yml b/src/ci/azure-pipelines/steps/install-sccache.yml index 427e50f571f76..d4679c1c6733e 100644 --- a/src/ci/azure-pipelines/steps/install-sccache.yml +++ b/src/ci/azure-pipelines/steps/install-sccache.yml @@ -2,14 +2,14 @@ steps: - bash: | set -e - curl -fo /usr/local/bin/sccache https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2018-04-02-sccache-x86_64-apple-darwin + curl -fo /usr/local/bin/sccache https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2018-04-02-sccache-x86_64-apple-darwin chmod +x /usr/local/bin/sccache displayName: Install sccache (OSX) condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin')) - script: | md sccache - powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf sccache\sccache.exe https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2018-04-26-sccache-x86_64-pc-windows-msvc" + powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf sccache\sccache.exe https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2018-04-26-sccache-x86_64-pc-windows-msvc" echo ##vso[task.prependpath]%CD%\sccache displayName: Install sccache (Windows) condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) diff --git a/src/ci/azure-pipelines/steps/install-windows-build-deps.yml b/src/ci/azure-pipelines/steps/install-windows-build-deps.yml index c42c2311b493f..bd4f1ed0cea43 100644 --- a/src/ci/azure-pipelines/steps/install-windows-build-deps.yml +++ b/src/ci/azure-pipelines/steps/install-windows-build-deps.yml @@ -4,7 +4,7 @@ steps: # https://github.com/wixtoolset/wix3 originally - bash: | set -e - curl -O https://rust-lang-ci2.s3-us-west-1.amazonaws.com/rust-ci-mirror/wix311-binaries.zip + curl -O https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/wix311-binaries.zip echo "##vso[task.setvariable variable=WIX]`pwd`/wix" mkdir -p wix/bin cd wix/bin @@ -18,9 +18,9 @@ steps: # one is MSI installers and one is EXE, but they're not used so frequently at # this point anyway so perhaps it's a wash! - script: | - powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf is-install.exe https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2017-08-22-is.exe" - is-install.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- echo ##vso[task.prependpath]C:\Program Files (x86)\Inno Setup 5 + curl.exe -o is-install.exe https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2017-08-22-is.exe + is-install.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- displayName: Install InnoSetup condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) @@ -43,24 +43,18 @@ steps: # FIXME: we should probe the default azure image and see if we can use the MSYS2 # toolchain there. (if there's even one there). For now though this gets the job # done. -- script: | - set MSYS_PATH=%CD%\citools\msys64 - choco install msys2 --params="/InstallDir:%MSYS_PATH% /NoPath" -y - set PATH=%MSYS_PATH%\usr\bin;%PATH% - pacman -S --noconfirm --needed base-devel ca-certificates make diffutils tar - IF "%MINGW_URL%"=="" ( - IF "%MSYS_BITS%"=="32" pacman -S --noconfirm --needed mingw-w64-i686-toolchain mingw-w64-i686-cmake mingw-w64-i686-gcc mingw-w64-i686-python2 - IF "%MSYS_BITS%"=="64" pacman -S --noconfirm --needed mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc mingw-w64-x86_64-python2 - ) - where rev - rev --help - where make - - echo ##vso[task.setvariable variable=MSYS_PATH]%MSYS_PATH% - echo ##vso[task.prependpath]%MSYS_PATH%\usr\bin +- bash: | + set -e + choco install msys2 --params="/InstallDir:$(System.Workfolder)/msys2 /NoPath" -y --no-progress + echo "##vso[task.prependpath]$(System.Workfolder)/msys2/usr/bin" + mkdir -p "$(System.Workfolder)/msys2/home/$USERNAME" displayName: Install msys2 condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) +- bash: pacman -S --noconfirm --needed base-devel ca-certificates make diffutils tar + displayName: Install msys2 base deps + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) + # If we need to download a custom MinGW, do so here and set the path # appropriately. # @@ -81,39 +75,46 @@ steps: # # Note that we don't literally overwrite the gdb.exe binary because it appears # to just use gdborig.exe, so that's the binary we deal with instead. -- script: | - powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf %MINGW_ARCHIVE% %MINGW_URL%/%MINGW_ARCHIVE%" - 7z x -y %MINGW_ARCHIVE% > nul - powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf 2017-04-20-%MSYS_BITS%bit-gdborig.exe %MINGW_URL%/2017-04-20-%MSYS_BITS%bit-gdborig.exe" - mv 2017-04-20-%MSYS_BITS%bit-gdborig.exe %MINGW_DIR%\bin\gdborig.exe - echo ##vso[task.prependpath]%CD%\%MINGW_DIR%\bin +- bash: | + set -e + curl -o mingw.7z $MINGW_URL/$MINGW_ARCHIVE + 7z x -y mingw.7z > /dev/null + curl -o $MINGW_DIR/bin/gdborig.exe $MINGW_URL/2017-04-20-${MSYS_BITS}bit-gdborig.exe + echo "##vso[task.prependpath]`pwd`/$MINGW_DIR/bin" condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), ne(variables['MINGW_URL'],'')) displayName: Download custom MinGW -# Otherwise pull in the MinGW installed on appveyor -- script: | - echo ##vso[task.prependpath]%MSYS_PATH%\mingw%MSYS_BITS%\bin +# Otherwise install MinGW through `pacman` +- bash: | + set -e + arch=i686 + if [ "$MSYS_BITS" = "64" ]; then + arch=x86_64 + fi + pacman -S --noconfirm --needed mingw-w64-$arch-toolchain mingw-w64-$arch-cmake mingw-w64-$arch-gcc mingw-w64-$arch-python2 + echo "##vso[task.prependpath]$(System.Workfolder)/msys2/mingw$MSYS_BITS/bin" condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['MINGW_URL'],'')) - displayName: Add MinGW to path + displayName: Download standard MinGW # Make sure we use the native python interpreter instead of some msys equivalent # one way or another. The msys interpreters seem to have weird path conversions # baked in which break LLVM's build system one way or another, so let's use the # native version which keeps everything as native as possible. -- script: | - copy C:\Python27amd64\python.exe C:\Python27amd64\python2.7.exe - echo ##vso[task.prependpath]C:\Python27amd64 +- bash: | + set -e + cp C:/Python27amd64/python.exe C:/Python27amd64/python2.7.exe + echo "##vso[task.prependpath]C:/Python27amd64" displayName: Prefer the "native" Python as LLVM has trouble building with MSYS sometimes condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) # Note that this is originally from the github releases patch of Ninja -- script: | - md ninja - powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf 2017-03-15-ninja-win.zip https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2017-03-15-ninja-win.zip" - 7z x -oninja 2017-03-15-ninja-win.zip - del 2017-03-15-ninja-win.zip - set RUST_CONFIGURE_ARGS=%RUST_CONFIGURE_ARGS% --enable-ninja - echo ##vso[task.setvariable variable=RUST_CONFIGURE_ARGS]%RUST_CONFIGURE_ARGS% - echo ##vso[task.prependpath]%CD%\ninja +- bash: | + set -e + mkdir ninja + curl -o ninja.zip https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2017-03-15-ninja-win.zip + 7z x -oninja ninja.zip + rm ninja.zip + echo "##vso[task.setvariable variable=RUST_CONFIGURE_ARGS]$RUST_CONFIGURE_ARGS --enable-ninja" + echo "##vso[task.prependpath]`pwd`/ninja" displayName: Download and install ninja condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) diff --git a/src/ci/azure-pipelines/steps/run.yml b/src/ci/azure-pipelines/steps/run.yml index ca32888b74c34..15a2499e4609e 100644 --- a/src/ci/azure-pipelines/steps/run.yml +++ b/src/ci/azure-pipelines/steps/run.yml @@ -147,8 +147,15 @@ steps: git clone --depth=1 https://github.com/rust-lang-nursery/rust-toolstate.git cd rust-toolstate python2.7 "$BUILD_SOURCESDIRECTORY/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "" "" + # Only check maintainers if this build is supposed to publish toolstate. + # Builds that are not supposed to publish don't have the access token. + if [ -n "${TOOLSTATE_PUBLISH+is_set}" ]; then + TOOLSTATE_VALIDATE_MAINTAINERS_REPO=rust-lang/rust python2.7 "${BUILD_SOURCESDIRECTORY}/src/tools/publish_toolstate.py" + fi cd .. rm -rf rust-toolstate + env: + TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN) condition: and(succeeded(), not(variables.SKIP_JOB), eq(variables['IMAGE'], 'mingw-check')) displayName: Verify the publish_toolstate script works @@ -168,7 +175,8 @@ steps: env: CI: true SRC: . - AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY) + AWS_ACCESS_KEY_ID: $(SCCACHE_AWS_ACCESS_KEY_ID) + AWS_SECRET_ACCESS_KEY: $(SCCACHE_AWS_SECRET_ACCESS_KEY) TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN) condition: and(succeeded(), not(variables.SKIP_JOB)) displayName: Run build @@ -192,16 +200,18 @@ steps: fi retry aws s3 cp --no-progress --recursive --acl public-read ./$upload_dir s3://$DEPLOY_BUCKET/$deploy_dir/$BUILD_SOURCEVERSION env: - AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY) + AWS_ACCESS_KEY_ID: $(UPLOAD_AWS_ACCESS_KEY_ID) + AWS_SECRET_ACCESS_KEY: $(UPLOAD_AWS_SECRET_ACCESS_KEY) condition: and(succeeded(), not(variables.SKIP_JOB), or(eq(variables.DEPLOY, '1'), eq(variables.DEPLOY_ALT, '1'))) displayName: Upload artifacts # Upload CPU usage statistics that we've been gathering this whole time. Always # execute this step in case we want to inspect failed builds, but don't let # errors here ever fail the build since this is just informational. -- bash: aws s3 cp --acl public-read cpu-usage.csv s3://$DEPLOY_BUCKET/rustc-builds/$BUILD_SOURCEVERSION/cpu-$SYSTEM_JOBNAME.csv +- bash: aws s3 cp --acl public-read cpu-usage.csv s3://$DEPLOY_BUCKET/rustc-builds/$BUILD_SOURCEVERSION/cpu-$CI_JOB_NAME.csv env: - AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY) - condition: variables['AWS_SECRET_ACCESS_KEY'] + AWS_ACCESS_KEY_ID: $(UPLOAD_AWS_ACCESS_KEY_ID) + AWS_SECRET_ACCESS_KEY: $(UPLOAD_AWS_SECRET_ACCESS_KEY) + condition: variables['UPLOAD_AWS_SECRET_ACCESS_KEY'] continueOnError: true displayName: Upload CPU usage statistics diff --git a/src/ci/azure-pipelines/try.yml b/src/ci/azure-pipelines/try.yml index 0df6c6c951f24..c919b1023a0eb 100644 --- a/src/ci/azure-pipelines/try.yml +++ b/src/ci/azure-pipelines/try.yml @@ -3,7 +3,7 @@ trigger: - try variables: -- group: real-prod-credentials +- group: prod-credentials jobs: - job: Linux diff --git a/src/ci/docker/armhf-gnu/Dockerfile b/src/ci/docker/armhf-gnu/Dockerfile index 235920833f839..9493b33698708 100644 --- a/src/ci/docker/armhf-gnu/Dockerfile +++ b/src/ci/docker/armhf-gnu/Dockerfile @@ -72,7 +72,7 @@ RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static # TODO: What is this?! # Source of the file: https://github.com/vfdev-5/qemu-rpi2-vexpress/raw/master/vexpress-v2p-ca15-tc1.dtb -RUN curl -O https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/vexpress-v2p-ca15-tc1.dtb +RUN curl -O https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/vexpress-v2p-ca15-tc1.dtb COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/dist-i586-gnu-i586-i686-musl/Dockerfile b/src/ci/docker/dist-i586-gnu-i586-i686-musl/Dockerfile index ba2d32a9296b4..61c363fbfd675 100644 --- a/src/ci/docker/dist-i586-gnu-i586-i686-musl/Dockerfile +++ b/src/ci/docker/dist-i586-gnu-i586-i686-musl/Dockerfile @@ -32,7 +32,6 @@ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS \ --musl-root-i586=/musl-i586 \ --musl-root-i686=/musl-i686 \ - --enable-extended \ --disable-docs # Newer binutils broke things on some vms/distros (i.e., linking against diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index ae2ea8ef95a6a..105791194628b 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -104,9 +104,7 @@ ENV TARGETS=$TARGETS,armv5te-unknown-linux-musleabi ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabihf ENV TARGETS=$TARGETS,aarch64-unknown-linux-musl ENV TARGETS=$TARGETS,sparc64-unknown-linux-gnu -# FIXME: temporarily disable the redox builder, -# see: https://github.com/rust-lang/rust/issues/63160 -# ENV TARGETS=$TARGETS,x86_64-unknown-redox +ENV TARGETS=$TARGETS,x86_64-unknown-redox ENV TARGETS=$TARGETS,thumbv6m-none-eabi ENV TARGETS=$TARGETS,thumbv7m-none-eabi ENV TARGETS=$TARGETS,thumbv7em-none-eabi @@ -132,7 +130,7 @@ ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ CC_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-gcc \ AR_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-ar \ CXX_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-g++ - + ENV RUST_CONFIGURE_ARGS \ --musl-root-armv5te=/musl-armv5te \ --musl-root-arm=/musl-arm \ diff --git a/src/ci/docker/dist-various-1/install-mips-musl.sh b/src/ci/docker/dist-various-1/install-mips-musl.sh index 60a96e3b8e952..29cfb5d96083e 100755 --- a/src/ci/docker/dist-various-1/install-mips-musl.sh +++ b/src/ci/docker/dist-various-1/install-mips-musl.sh @@ -5,7 +5,7 @@ mkdir /usr/local/mips-linux-musl # originally from # https://downloads.openwrt.org/snapshots/trunk/ar71xx/generic/ # OpenWrt-Toolchain-ar71xx-generic_gcc-5.3.0_musl-1.1.16.Linux-x86_64.tar.bz2 -URL="https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror" +URL="https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc" FILE="OpenWrt-Toolchain-ar71xx-generic_gcc-5.3.0_musl-1.1.16.Linux-x86_64.tar.bz2" curl -L "$URL/$FILE" | tar xjf - -C /usr/local/mips-linux-musl --strip-components=2 diff --git a/src/ci/docker/dist-various-1/install-mipsel-musl.sh b/src/ci/docker/dist-various-1/install-mipsel-musl.sh index 9ae41218ee4fb..de8c359d16757 100755 --- a/src/ci/docker/dist-various-1/install-mipsel-musl.sh +++ b/src/ci/docker/dist-various-1/install-mipsel-musl.sh @@ -5,7 +5,7 @@ mkdir /usr/local/mipsel-linux-musl # Note that this originally came from: # https://downloads.openwrt.org/snapshots/trunk/malta/generic/ # OpenWrt-Toolchain-malta-le_gcc-5.3.0_musl-1.1.15.Linux-x86_64.tar.bz2 -URL="https://rust-lang-ci2.s3.amazonaws.com/libc" +URL="https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc" FILE="OpenWrt-Toolchain-malta-le_gcc-5.3.0_musl-1.1.15.Linux-x86_64.tar.bz2" curl -L "$URL/$FILE" | tar xjf - -C /usr/local/mipsel-linux-musl --strip-components=2 diff --git a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh index 7bf8946c4f136..f04ee78157167 100755 --- a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh +++ b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh @@ -5,7 +5,7 @@ set -ex # Originally from https://releases.llvm.org/8.0.0/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz -curl https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/clang%2Bllvm-8.0.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz | \ +curl https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/clang%2Bllvm-8.0.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz | \ tar xJf - export PATH=`pwd`/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-14.04/bin:$PATH diff --git a/src/ci/docker/dist-x86_64-linux/build-curl.sh b/src/ci/docker/dist-x86_64-linux/build-curl.sh index fb8b63d7920b1..8200bbe2fdce5 100755 --- a/src/ci/docker/dist-x86_64-linux/build-curl.sh +++ b/src/ci/docker/dist-x86_64-linux/build-curl.sh @@ -3,9 +3,11 @@ set -ex source shared.sh -VERSION=7.51.0 +VERSION=7.66.0 -curl http://cool.haxx.se/download/curl-$VERSION.tar.bz2 | tar xjf - +curl https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/curl-$VERSION.tar.xz \ + | xz --decompress \ + | tar xf - mkdir curl-build cd curl-build diff --git a/src/ci/docker/dist-x86_64-linux/build-openssl.sh b/src/ci/docker/dist-x86_64-linux/build-openssl.sh index 13dae6169053a..be8a6c93945e9 100755 --- a/src/ci/docker/dist-x86_64-linux/build-openssl.sh +++ b/src/ci/docker/dist-x86_64-linux/build-openssl.sh @@ -4,7 +4,7 @@ set -ex source shared.sh VERSION=1.0.2k -URL=https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/openssl-$VERSION.tar.gz +URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/openssl-$VERSION.tar.gz curl $URL | tar xzf - diff --git a/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh index 2e9b9dcc2344e..797f674b954f2 100755 --- a/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh +++ b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh @@ -25,7 +25,7 @@ cd netbsd mkdir -p /x-tools/x86_64-unknown-netbsd/sysroot -URL=https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror +URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc # Originally from ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-$BSD/source/sets/*.tgz curl $URL/2018-03-01-netbsd-src.tgz | tar xzf - diff --git a/src/ci/docker/i686-gnu-nopt/Dockerfile b/src/ci/docker/i686-gnu-nopt/Dockerfile index 2041ba50bc9a0..517b59c38dcb0 100644 --- a/src/ci/docker/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/i686-gnu-nopt/Dockerfile @@ -19,3 +19,6 @@ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests ENV SCRIPT python2.7 ../x.py test + +# FIXME(#59637) takes too long on CI right now +ENV NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 diff --git a/src/ci/docker/i686-gnu/Dockerfile b/src/ci/docker/i686-gnu/Dockerfile index 17441ddb4546b..03db3ba0995d6 100644 --- a/src/ci/docker/i686-gnu/Dockerfile +++ b/src/ci/docker/i686-gnu/Dockerfile @@ -25,3 +25,6 @@ ENV SCRIPT python2.7 ../x.py test \ --exclude src/test/rustdoc-js \ --exclude src/tools/error_index_generator \ --exclude src/tools/linkchecker + +# FIXME(#59637) takes too long on CI right now +ENV NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 diff --git a/src/ci/docker/scripts/android-sdk-manager.py b/src/ci/docker/scripts/android-sdk-manager.py index 7c9a8b82e9282..c9e2961f6eb15 100755 --- a/src/ci/docker/scripts/android-sdk-manager.py +++ b/src/ci/docker/scripts/android-sdk-manager.py @@ -23,8 +23,9 @@ HOST_OS = "linux" # Mirroring options -MIRROR_BUCKET = "rust-lang-ci2" -MIRROR_BASE_DIR = "rust-ci-mirror/android/" +MIRROR_BUCKET = "rust-lang-ci-mirrors" +MIRROR_BUCKET_REGION = "us-west-1" +MIRROR_BASE_DIR = "rustc/android/" import argparse import hashlib @@ -144,7 +145,8 @@ def cli_install(args): lockfile = Lockfile(args.lockfile) for package in lockfile.packages.values(): # Download the file from the mirror into a temp file - url = "https://" + MIRROR_BUCKET + ".s3.amazonaws.com/" + MIRROR_BASE_DIR + url = "https://" + MIRROR_BUCKET + ".s3-" + MIRROR_BUCKET_REGION + \ + ".amazonaws.com/" + MIRROR_BASE_DIR downloaded = package.download(url) # Extract the file in a temporary directory extract_dir = tempfile.mkdtemp() diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh index 8cef69d9c26bb..70155e770a960 100755 --- a/src/ci/docker/scripts/freebsd-toolchain.sh +++ b/src/ci/docker/scripts/freebsd-toolchain.sh @@ -59,7 +59,7 @@ done # Originally downloaded from: # https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz -URL=https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2019-04-04-freebsd-${freebsd_arch}-${freebsd_version}-RELEASE-base.txz +URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2019-04-04-freebsd-${freebsd_arch}-${freebsd_version}-RELEASE-base.txz curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}" # Fix up absolute symlinks from the system image. This can be removed diff --git a/src/ci/docker/scripts/musl-toolchain.sh b/src/ci/docker/scripts/musl-toolchain.sh index 55899fa6c3e69..74ba2f0eadb25 100644 --- a/src/ci/docker/scripts/musl-toolchain.sh +++ b/src/ci/docker/scripts/musl-toolchain.sh @@ -54,29 +54,3 @@ if [ "$REPLACE_CC" = "1" ]; then ln -s $TARGET-g++ /usr/local/bin/$exec done fi - -export CC=$TARGET-gcc -export CXX=$TARGET-g++ - -LLVM=70 - -# may have been downloaded in a previous run -if [ ! -d libunwind-release_$LLVM ]; then - curl -L https://github.com/llvm-mirror/llvm/archive/release_$LLVM.tar.gz | tar xzf - - curl -L https://github.com/llvm-mirror/libunwind/archive/release_$LLVM.tar.gz | tar xzf - -fi - -# fixme(mati865): Replace it with https://github.com/rust-lang/rust/pull/59089 -mkdir libunwind-build -cd libunwind-build -cmake ../libunwind-release_$LLVM \ - -DLLVM_PATH=/build/llvm-release_$LLVM \ - -DLIBUNWIND_ENABLE_SHARED=0 \ - -DCMAKE_C_COMPILER=$CC \ - -DCMAKE_CXX_COMPILER=$CXX \ - -DCMAKE_C_FLAGS="$CFLAGS" \ - -DCMAKE_CXX_FLAGS="$CXXFLAGS" - -hide_output make -j$(nproc) -cp lib/libunwind.a $OUTPUT/$TARGET/lib -cd - && rm -rf libunwind-build diff --git a/src/ci/docker/scripts/musl.sh b/src/ci/docker/scripts/musl.sh index c2cf77d56cb3b..d847c407aba67 100644 --- a/src/ci/docker/scripts/musl.sh +++ b/src/ci/docker/scripts/musl.sh @@ -20,6 +20,8 @@ exit 1 TAG=$1 shift +# Ancient binutils versions don't understand debug symbols produced by more recent tools. +# Apparently applying `-fPIC` everywhere allows them to link successfully. export CFLAGS="-fPIC $CFLAGS" MUSL=musl-1.1.22 @@ -38,27 +40,3 @@ else fi hide_output make install hide_output make clean - -cd .. - -LLVM=70 - -# may have been downloaded in a previous run -if [ ! -d libunwind-release_$LLVM ]; then - curl -L https://github.com/llvm-mirror/llvm/archive/release_$LLVM.tar.gz | tar xzf - - curl -L https://github.com/llvm-mirror/libunwind/archive/release_$LLVM.tar.gz | tar xzf - -fi - -mkdir libunwind-build -cd libunwind-build -cmake ../libunwind-release_$LLVM \ - -DLLVM_PATH=/build/llvm-release_$LLVM \ - -DLIBUNWIND_ENABLE_SHARED=0 \ - -DCMAKE_C_COMPILER=$CC \ - -DCMAKE_CXX_COMPILER=$CXX \ - -DCMAKE_C_FLAGS="$CFLAGS" \ - -DCMAKE_CXX_FLAGS="$CXXFLAGS" - -hide_output make -j$(nproc) -cp lib/libunwind.a /musl-$TAG/lib -cd ../ && rm -rf libunwind-build diff --git a/src/ci/docker/scripts/sccache.sh b/src/ci/docker/scripts/sccache.sh index 194de3c339f8c..efeb0ed0d72d0 100644 --- a/src/ci/docker/scripts/sccache.sh +++ b/src/ci/docker/scripts/sccache.sh @@ -1,6 +1,6 @@ set -ex curl -fo /usr/local/bin/sccache \ - https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2018-04-02-sccache-x86_64-unknown-linux-musl + https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2018-04-02-sccache-x86_64-unknown-linux-musl chmod +x /usr/local/bin/sccache diff --git a/src/ci/docker/x86_64-gnu-tools/Dockerfile b/src/ci/docker/x86_64-gnu-tools/Dockerfile index f11ae7a34cb91..8035195c6ed0a 100644 --- a/src/ci/docker/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/x86_64-gnu-tools/Dockerfile @@ -21,6 +21,9 @@ COPY x86_64-gnu-tools/checkregression.py /tmp/ COPY x86_64-gnu-tools/checktools.sh /tmp/ COPY x86_64-gnu-tools/repo.sh /tmp/ +# Run rustbook with `linkcheck` feature enabled +ENV CHECK_LINKS 1 + ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --save-toolstates=/tmp/toolstates.json diff --git a/src/ci/install-awscli.sh b/src/ci/install-awscli.sh index d491b9fbcdcf8..69c8d2e3099ab 100755 --- a/src/ci/install-awscli.sh +++ b/src/ci/install-awscli.sh @@ -16,7 +16,7 @@ set -euo pipefail IFS=$'\n\t' -MIRROR="https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2019-07-27-awscli.tar" +MIRROR="https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2019-07-27-awscli.tar" DEPS_DIR="/tmp/awscli-deps" pip="pip" diff --git a/src/ci/run.sh b/src/ci/run.sh index f1eb417cdf982..0d5ea371245e4 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -55,6 +55,9 @@ if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions" elif [ "$DEPLOY_ALT" != "" ]; then + if [ "$NO_PARALLEL_COMPILER" = "" ]; then + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.parallel-compiler" + fi RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-assertions" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.verify-llvm-ir" fi @@ -78,6 +81,21 @@ if [ "$RUST_RELEASE_CHANNEL" = "nightly" ] || [ "$DIST_REQUIRE_ALL_TOOLS" = "" ] RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-missing-tools" fi +# Print the date from the local machine and the date from an external source to +# check for clock drifts. An HTTP URL is used instead of HTTPS since on Azure +# Pipelines it happened that the certificates were marked as expired. +datecheck() { + echo "== clock drift check ==" + echo -n " local time: " + date + echo -n " network time: " + curl -fs --head http://detectportal.firefox.com/success.txt | grep ^Date: \ + | sed 's/Date: //g' || true + echo "== end clock drift check ==" +} +datecheck +trap datecheck EXIT + # We've had problems in the past of shell scripts leaking fds into the sccache # server (#48192) which causes Cargo to erroneously think that a build script # hasn't finished yet. Try to solve that problem by starting a very long-lived diff --git a/src/doc/book b/src/doc/book index 7ddc46460f09a..04806c80be0f5 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 7ddc46460f09a5cd9bd2a620565bdc20b3315ea9 +Subproject commit 04806c80be0f54b1290287e3f85e84bdfc0b6ec7 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index c5da1e11915d3..5ca585c4a7552 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit c5da1e11915d3f28266168baaf55822f7e3fe999 +Subproject commit 5ca585c4a7552efb546e7681c3de0712f4ae4fdc diff --git a/src/doc/grammar.md b/src/doc/grammar.md index ee9135b6578f6..4501d74073e90 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -1,812 +1,7 @@ % Grammar -# Introduction +The Rust grammar may now be found in the [reference]. Additionally, the [grammar +working group] is working on producing a testable grammar. -This document is the primary reference for the Rust programming language grammar. It -provides only one kind of material: - - - Chapters that formally define the language grammar. - -This document does not serve as an introduction to the language. Background -familiarity with the language is assumed. A separate [guide] is available to -help acquire such background. - -This document also does not serve as a reference to the [standard] library -included in the language distribution. Those libraries are documented -separately by extracting documentation attributes from their source code. Many -of the features that one might expect to be language features are library -features in Rust, so what you're looking for may be there, not here. - -[guide]: guide.html -[standard]: std/index.html - -# Notation - -Rust's grammar is defined over Unicode codepoints, each conventionally denoted -`U+XXXX`, for 4 or more hexadecimal digits `X`. _Most_ of Rust's grammar is -confined to the ASCII range of Unicode, and is described in this document by a -dialect of Extended Backus-Naur Form (EBNF), specifically a dialect of EBNF -supported by common automated LL(k) parsing tools such as `llgen`, rather than -the dialect given in ISO 14977. The dialect can be defined self-referentially -as follows: - -```antlr -grammar : rule + ; -rule : nonterminal ':' productionrule ';' ; -productionrule : production [ '|' production ] * ; -production : term * ; -term : element repeats ; -element : LITERAL | IDENTIFIER | '[' productionrule ']' ; -repeats : [ '*' | '+' ] NUMBER ? | NUMBER ? | '?' ; -``` - -Where: - -- Whitespace in the grammar is ignored. -- Square brackets are used to group rules. -- `LITERAL` is a single printable ASCII character, or an escaped hexadecimal - ASCII code of the form `\xQQ`, in single quotes, denoting the corresponding - Unicode codepoint `U+00QQ`. -- `IDENTIFIER` is a nonempty string of ASCII letters and underscores. -- The `repeat` forms apply to the adjacent `element`, and are as follows: - - `?` means zero or one repetition - - `*` means zero or more repetitions - - `+` means one or more repetitions - - NUMBER trailing a repeat symbol gives a maximum repetition count - - NUMBER on its own gives an exact repetition count - -This EBNF dialect should hopefully be familiar to many readers. - -## Unicode productions - -A few productions in Rust's grammar permit Unicode codepoints outside the ASCII -range. We define these productions in terms of character properties specified -in the Unicode standard, rather than in terms of ASCII-range codepoints. The -section [Special Unicode Productions](#special-unicode-productions) lists these -productions. - -## String table productions - -Some rules in the grammar — notably [unary -operators](#unary-operator-expressions), [binary -operators](#binary-operator-expressions), and [keywords](#keywords) — are -given in a simplified form: as a listing of a table of unquoted, printable -whitespace-separated strings. These cases form a subset of the rules regarding -the [token](#tokens) rule, and are assumed to be the result of a -lexical-analysis phase feeding the parser, driven by a DFA, operating over the -disjunction of all such string table entries. - -When such a string enclosed in double-quotes (`"`) occurs inside the grammar, -it is an implicit reference to a single member of such a string table -production. See [tokens](#tokens) for more information. - -# Lexical structure - -## Input format - -Rust input is interpreted as a sequence of Unicode codepoints encoded in UTF-8. -Most Rust grammar rules are defined in terms of printable ASCII-range -codepoints, but a small number are defined in terms of Unicode properties or -explicit codepoint lists. [^inputformat] - -[^inputformat]: Substitute definitions for the special Unicode productions are - provided to the grammar verifier, restricted to ASCII range, when verifying the - grammar in this document. - -## Special Unicode Productions - -The following productions in the Rust grammar are defined in terms of Unicode -properties: `ident`, `non_null`, `non_eol`, `non_single_quote` and -`non_double_quote`. - -### Identifiers - -The `ident` production is any nonempty Unicode string of -the following form: - -- The first character is in one of the following ranges `U+0041` to `U+005A` -("A" to "Z"), `U+0061` to `U+007A` ("a" to "z"), or `U+005F` ("\_"). -- The remaining characters are in the range `U+0030` to `U+0039` ("0" to "9"), -or any of the prior valid initial characters. - -as long as the identifier does _not_ occur in the set of [keywords](#keywords). - -### Delimiter-restricted productions - -Some productions are defined by exclusion of particular Unicode characters: - -- `non_null` is any single Unicode character aside from `U+0000` (null) -- `non_eol` is any single Unicode character aside from `U+000A` (`'\n'`) -- `non_single_quote` is any single Unicode character aside from `U+0027` (`'`) -- `non_double_quote` is any single Unicode character aside from `U+0022` (`"`) - -## Comments - -```antlr -comment : block_comment | line_comment ; -block_comment : "/*" block_comment_body * "*/" ; -block_comment_body : [block_comment | character] * ; -line_comment : "//" non_eol * ; -``` - -**FIXME:** add doc grammar? - -## Whitespace - -```antlr -whitespace_char : '\x20' | '\x09' | '\x0a' | '\x0d' ; -whitespace : [ whitespace_char | comment ] + ; -``` - -## Tokens - -```antlr -simple_token : keyword | unop | binop ; -token : simple_token | ident | literal | symbol | whitespace token ; -``` - -### Keywords - -

- -| | | | | | -|----------|----------|----------|----------|----------| -| _ | abstract | alignof | as | become | -| box | break | const | continue | crate | -| do | else | enum | extern | false | -| final | fn | for | if | impl | -| in | let | loop | macro | match | -| mod | move | mut | offsetof | override | -| priv | proc | pub | pure | ref | -| return | Self | self | sizeof | static | -| struct | super | trait | true | type | -| typeof | unsafe | unsized | use | virtual | -| where | while | yield | | | - - -Each of these keywords has special meaning in its grammar, and all of them are -excluded from the `ident` rule. - -Not all of these keywords are used by the language. Some of them were used -before Rust 1.0, and were left reserved once their implementations were -removed. Some of them were reserved before 1.0 to make space for possible -future features. - -### Literals - -```antlr -lit_suffix : ident; -literal : [ string_lit | char_lit | byte_string_lit | byte_lit | num_lit | bool_lit ] lit_suffix ?; -``` - -The optional `lit_suffix` production is only used for certain numeric literals, -but is reserved for future extension. That is, the above gives the lexical -grammar, but a Rust parser will reject everything but the 12 special cases -mentioned in [Number literals](reference/tokens.html#number-literals) in the -reference. - -#### Character and string literals - -```antlr -char_lit : '\x27' char_body '\x27' ; -string_lit : '"' string_body * '"' | 'r' raw_string ; - -char_body : non_single_quote - | '\x5c' [ '\x27' | common_escape | unicode_escape ] ; - -string_body : non_double_quote - | '\x5c' [ '\x22' | common_escape | unicode_escape ] ; -raw_string : '"' raw_string_body '"' | '#' raw_string '#' ; - -common_escape : '\x5c' - | 'n' | 'r' | 't' | '0' - | 'x' hex_digit 2 -unicode_escape : 'u' '{' hex_digit+ 6 '}'; - -hex_digit : 'a' | 'b' | 'c' | 'd' | 'e' | 'f' - | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' - | dec_digit ; -oct_digit : '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' ; -dec_digit : '0' | nonzero_dec ; -nonzero_dec: '1' | '2' | '3' | '4' - | '5' | '6' | '7' | '8' | '9' ; -``` - -#### Byte and byte string literals - -```antlr -byte_lit : "b\x27" byte_body '\x27' ; -byte_string_lit : "b\x22" string_body * '\x22' | "br" raw_byte_string ; - -byte_body : ascii_non_single_quote - | '\x5c' [ '\x27' | common_escape ] ; - -byte_string_body : ascii_non_double_quote - | '\x5c' [ '\x22' | common_escape ] ; -raw_byte_string : '"' raw_byte_string_body '"' | '#' raw_byte_string '#' ; - -``` - -#### Number literals - -```antlr -num_lit : nonzero_dec [ dec_digit | '_' ] * float_suffix ? - | '0' [ [ dec_digit | '_' ] * float_suffix ? - | 'b' [ '1' | '0' | '_' ] + - | 'o' [ oct_digit | '_' ] + - | 'x' [ hex_digit | '_' ] + ] ; - -float_suffix : [ exponent | '.' dec_lit exponent ? ] ? ; - -exponent : ['E' | 'e'] ['-' | '+' ] ? dec_lit ; -dec_lit : [ dec_digit | '_' ] + ; -``` - -#### Boolean literals - -```antlr -bool_lit : [ "true" | "false" ] ; -``` - -The two values of the boolean type are written `true` and `false`. - -### Symbols - -```antlr -symbol : "::" | "->" - | '#' | '[' | ']' | '(' | ')' | '{' | '}' - | ',' | ';' ; -``` - -Symbols are a general class of printable [tokens](#tokens) that play structural -roles in a variety of grammar productions. They are cataloged here for -completeness as the set of remaining miscellaneous printable tokens that do not -otherwise appear as [unary operators](#unary-operator-expressions), [binary -operators](#binary-operator-expressions), or [keywords](#keywords). - -## Paths - -```antlr -expr_path : [ "::" ] ident [ "::" expr_path_tail ] + ; -expr_path_tail : '<' type_expr [ ',' type_expr ] + '>' - | expr_path ; - -type_path : ident [ type_path_tail ] + ; -type_path_tail : '<' type_expr [ ',' type_expr ] + '>' - | "::" type_path ; -``` - -# Syntax extensions - -## Macros - -```antlr -expr_macro_rules : "macro_rules" '!' ident '(' macro_rule * ')' ';' - | "macro_rules" '!' ident '{' macro_rule * '}' ; -macro_rule : '(' matcher * ')' "=>" '(' transcriber * ')' ';' ; -matcher : '(' matcher * ')' | '[' matcher * ']' - | '{' matcher * '}' | '$' ident ':' ident - | '$' '(' matcher * ')' sep_token? [ '*' | '+' ] - | non_special_token ; -transcriber : '(' transcriber * ')' | '[' transcriber * ']' - | '{' transcriber * '}' | '$' ident - | '$' '(' transcriber * ')' sep_token? [ '*' | '+' ] - | non_special_token ; -``` - -# Crates and source files - -**FIXME:** grammar? What production covers #![crate_id = "foo"] ? - -# Items and attributes - -**FIXME:** grammar? - -## Items - -```antlr -item : vis ? mod_item | fn_item | type_item | struct_item | enum_item - | const_item | static_item | trait_item | impl_item | extern_block_item ; -``` - -### Type Parameters - -**FIXME:** grammar? - -### Modules - -```antlr -mod_item : "mod" ident ( ';' | '{' mod '}' ); -mod : [ view_item | item ] * ; -``` - -#### View items - -```antlr -view_item : extern_crate_decl | use_decl ';' ; -``` - -##### Extern crate declarations - -```antlr -extern_crate_decl : "extern" "crate" crate_name -crate_name: ident | ( ident "as" ident ) -``` - -##### Use declarations - -```antlr -use_decl : vis ? "use" [ path "as" ident - | path_glob ] ; - -path_glob : ident [ "::" [ path_glob - | '*' ] ] ? - | '{' path_item [ ',' path_item ] * '}' ; - -path_item : ident | "self" ; -``` - -### Functions - -**FIXME:** grammar? - -#### Generic functions - -**FIXME:** grammar? - -#### Unsafety - -**FIXME:** grammar? - -##### Unsafe functions - -**FIXME:** grammar? - -##### Unsafe blocks - -**FIXME:** grammar? - -#### Diverging functions - -**FIXME:** grammar? - -### Type definitions - -**FIXME:** grammar? - -### Structures - -**FIXME:** grammar? - -### Enumerations - -**FIXME:** grammar? - -### Constant items - -```antlr -const_item : "const" ident ':' type '=' expr ';' ; -``` - -### Static items - -```antlr -static_item : "static" ident ':' type '=' expr ';' ; -``` - -#### Mutable statics - -**FIXME:** grammar? - -### Traits - -**FIXME:** grammar? - -### Implementations - -**FIXME:** grammar? - -### External blocks - -```antlr -extern_block_item : "extern" '{' extern_block '}' ; -extern_block : [ foreign_fn ] * ; -``` - -## Visibility and Privacy - -```antlr -vis : "pub" ; -``` -### Re-exporting and Visibility - -See [Use declarations](#use-declarations). - -## Attributes - -```antlr -attribute : '#' '!' ? '[' meta_item ']' ; -meta_item : ident [ '=' literal - | '(' meta_seq ')' ] ? ; -meta_seq : meta_item [ ',' meta_seq ] ? ; -``` - -# Statements and expressions - -## Statements - -```antlr -stmt : decl_stmt | expr_stmt | ';' ; -``` - -### Declaration statements - -```antlr -decl_stmt : item | let_decl ; -``` - -#### Item declarations - -See [Items](#items). - -#### Variable declarations - -```antlr -let_decl : "let" pat [':' type ] ? [ init ] ? ';' ; -init : [ '=' ] expr ; -``` - -### Expression statements - -```antlr -expr_stmt : expr ';' ; -``` - -## Expressions - -```antlr -expr : literal | path | tuple_expr | unit_expr | struct_expr - | block_expr | method_call_expr | field_expr | array_expr - | idx_expr | range_expr | unop_expr | binop_expr - | paren_expr | call_expr | lambda_expr | while_expr - | loop_expr | break_expr | continue_expr | for_expr - | if_expr | match_expr | if_let_expr | while_let_expr - | return_expr ; -``` - -#### Lvalues, rvalues and temporaries - -**FIXME:** grammar? - -#### Moved and copied types - -**FIXME:** Do we want to capture this in the grammar as different productions? - -### Literal expressions - -See [Literals](#literals). - -### Path expressions - -See [Paths](#paths). - -### Tuple expressions - -```antlr -tuple_expr : '(' [ expr [ ',' expr ] * | expr ',' ] ? ')' ; -``` - -### Unit expressions - -```antlr -unit_expr : "()" ; -``` - -### Structure expressions - -```antlr -struct_expr_field_init : ident | ident ':' expr ; -struct_expr : expr_path '{' struct_expr_field_init - [ ',' struct_expr_field_init ] * - [ ".." expr ] '}' | - expr_path '(' expr - [ ',' expr ] * ')' | - expr_path ; -``` - -### Block expressions - -```antlr -block_expr : '{' [ stmt | item ] * - [ expr ] '}' ; -``` - -### Method-call expressions - -```antlr -method_call_expr : expr '.' ident paren_expr_list ; -``` - -### Field expressions - -```antlr -field_expr : expr '.' ident ; -``` - -### Array expressions - -```antlr -array_expr : '[' "mut" ? array_elems? ']' ; - -array_elems : [expr [',' expr]*] | [expr ';' expr] ; -``` - -### Index expressions - -```antlr -idx_expr : expr '[' expr ']' ; -``` - -### Range expressions - -```antlr -range_expr : expr ".." expr | - expr ".." | - ".." expr | - ".." ; -``` - -### Unary operator expressions - -```antlr -unop_expr : unop expr ; -unop : '-' | '*' | '!' ; -``` - -### Binary operator expressions - -```antlr -binop_expr : expr binop expr | type_cast_expr - | assignment_expr | compound_assignment_expr ; -binop : arith_op | bitwise_op | lazy_bool_op | comp_op -``` - -#### Arithmetic operators - -```antlr -arith_op : '+' | '-' | '*' | '/' | '%' ; -``` - -#### Bitwise operators - -```antlr -bitwise_op : '&' | '|' | '^' | "<<" | ">>" ; -``` - -#### Lazy boolean operators - -```antlr -lazy_bool_op : "&&" | "||" ; -``` - -#### Comparison operators - -```antlr -comp_op : "==" | "!=" | '<' | '>' | "<=" | ">=" ; -``` - -#### Type cast expressions - -```antlr -type_cast_expr : value "as" type ; -``` - -#### Assignment expressions - -```antlr -assignment_expr : expr '=' expr ; -``` - -#### Compound assignment expressions - -```antlr -compound_assignment_expr : expr [ arith_op | bitwise_op ] '=' expr ; -``` - -### Grouped expressions - -```antlr -paren_expr : '(' expr ')' ; -``` - -### Call expressions - -```antlr -expr_list : [ expr [ ',' expr ]* ] ? ; -paren_expr_list : '(' expr_list ')' ; -call_expr : expr paren_expr_list ; -``` - -### Lambda expressions - -```antlr -ident_list : [ ident [ ',' ident ]* ] ? ; -lambda_expr : '|' ident_list '|' expr ; -``` - -### While loops - -```antlr -while_expr : [ lifetime ':' ] ? "while" no_struct_literal_expr '{' block '}' ; -``` - -### Infinite loops - -```antlr -loop_expr : [ lifetime ':' ] ? "loop" '{' block '}'; -``` - -### Break expressions - -```antlr -break_expr : "break" [ lifetime ] ?; -``` - -### Continue expressions - -```antlr -continue_expr : "continue" [ lifetime ] ?; -``` - -### For expressions - -```antlr -for_expr : [ lifetime ':' ] ? "for" pat "in" no_struct_literal_expr '{' block '}' ; -``` - -### If expressions - -```antlr -if_expr : "if" no_struct_literal_expr '{' block '}' - else_tail ? ; - -else_tail : "else" [ if_expr | if_let_expr - | '{' block '}' ] ; -``` - -### Match expressions - -```antlr -match_expr : "match" no_struct_literal_expr '{' match_arm * '}' ; - -match_arm : attribute * match_pat "=>" [ expr "," | '{' block '}' ] ; - -match_pat : pat [ '|' pat ] * [ "if" expr ] ? ; -``` - -### If let expressions - -```antlr -if_let_expr : "if" "let" pat '=' expr '{' block '}' - else_tail ? ; -``` - -### While let loops - -```antlr -while_let_expr : [ lifetime ':' ] ? "while" "let" pat '=' expr '{' block '}' ; -``` - -### Return expressions - -```antlr -return_expr : "return" expr ? ; -``` - -# Type system - -**FIXME:** is this entire chapter relevant here? Or should it all have been covered by some production already? - -## Types - -### Primitive types - -**FIXME:** grammar? - -#### Machine types - -**FIXME:** grammar? - -#### Machine-dependent integer types - -**FIXME:** grammar? - -### Textual types - -**FIXME:** grammar? - -### Tuple types - -**FIXME:** grammar? - -### Array, and Slice types - -**FIXME:** grammar? - -### Structure types - -**FIXME:** grammar? - -### Enumerated types - -**FIXME:** grammar? - -### Pointer types - -**FIXME:** grammar? - -### Function types - -**FIXME:** grammar? - -### Closure types - -```antlr -closure_type := [ 'unsafe' ] [ '<' lifetime-list '>' ] '|' arg-list '|' - [ ':' bound-list ] [ '->' type ] -lifetime-list := lifetime | lifetime ',' lifetime-list -arg-list := ident ':' type | ident ':' type ',' arg-list -``` - -### Never type -An empty type - -```antlr -never_type : "!" ; -``` - -### Object types - -**FIXME:** grammar? - -### Type parameters - -**FIXME:** grammar? - -### Type parameter bounds - -```antlr -bound-list := bound | bound '+' bound-list '+' ? -bound := ty_bound | lt_bound -lt_bound := lifetime -ty_bound := ty_bound_noparen | (ty_bound_noparen) -ty_bound_noparen := [?] [ for ] simple_path -``` - -### Self types - -**FIXME:** grammar? - -## Type kinds - -**FIXME:** this is probably not relevant to the grammar... - -# Memory and concurrency models - -**FIXME:** is this entire chapter relevant here? Or should it all have been covered by some production already? - -## Memory model - -### Memory allocation and lifetime - -### Memory ownership - -### Variables - -### Boxes - -## Threads - -### Communication between threads - -### Thread lifecycle +[reference]: https://doc.rust-lang.org/reference/ +[grammar working group]: https://github.com/rust-lang/wg-grammar diff --git a/src/doc/nomicon b/src/doc/nomicon index 8a7d05615e5bc..4374786f0b4bf 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 8a7d05615e5bc0a7fb961b4919c44f5221ee54da +Subproject commit 4374786f0b4bf0606b35d5c30a9681f342e5707b diff --git a/src/doc/reference b/src/doc/reference index b4b3536839042..5b9d2fcefadfc 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit b4b3536839042a6743fc76f0d9ad2a812020aeaa +Subproject commit 5b9d2fcefadfc32fceafacfc0dd9441d9b57dd94 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index f2c15ba5ee89a..a6288e7407a6c 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit f2c15ba5ee89ae9469a2cf60494977749901d764 +Subproject commit a6288e7407a6c4c19ea29de6d43f40c803883f21 diff --git a/src/doc/rustc-guide b/src/doc/rustc-guide index 6f4ba673ff9d4..941968db2fd9c 160000 --- a/src/doc/rustc-guide +++ b/src/doc/rustc-guide @@ -1 +1 @@ -Subproject commit 6f4ba673ff9d4613e98415bc095347a6a0031e9c +Subproject commit 941968db2fd9c85788a4f971c8e425d46b4cb734 diff --git a/src/doc/rustc-ux-guidelines.md b/src/doc/rustc-ux-guidelines.md index e3684fc9f320a..dfd8e9db3c5c9 100644 --- a/src/doc/rustc-ux-guidelines.md +++ b/src/doc/rustc-ux-guidelines.md @@ -70,7 +70,7 @@ for details on how to format and write long error codes. [librustc_privacy](https://github.com/rust-lang/rust/blob/master/src/librustc_privacy/error_codes.rs), [librustc_resolve](https://github.com/rust-lang/rust/blob/master/src/librustc_resolve/error_codes.rs), [librustc_codegen_llvm](https://github.com/rust-lang/rust/blob/master/src/librustc_codegen_llvm/error_codes.rs), - [librustc_plugin](https://github.com/rust-lang/rust/blob/master/src/librustc_plugin/error_codes.rs), + [librustc_plugin_impl](https://github.com/rust-lang/rust/blob/master/src/librustc_plugin/error_codes.rs), [librustc_typeck](https://github.com/rust-lang/rust/blob/master/src/librustc_typeck/error_codes.rs). * Explanations have full markdown support. Use it, especially to highlight code with backticks. diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 5c41acc6581c5..e73fd43f19a51 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -105,7 +105,7 @@ flag will turn that behavior off. ## no-vectorize-slp -By default, `rustc` will attempt to vectorize loops using [superword-level +By default, `rustc` will attempt to vectorize code using [superword-level parallelism](https://llvm.org/docs/Vectorizers.html#the-slp-vectorizer). This flag will turn that behavior off. diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index d774e465118b3..5eea9c8687900 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -304,3 +304,10 @@ to customize the output: Note that it is invalid to combine the `--json` argument with the `--color` argument, and it is required to combine `--json` with `--error-format=json`. + +## `@path`: load command-line flags from a path + +If you specify `@path` on the command-line, then it will open `path` and read +command line options from it. These options are one per line; a blank line indicates +an empty option. The file can use Unix or Windows style line endings, and must be +encoded as UTF-8. diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md index 2ae726c4ba61d..6f1bbe60569fd 100644 --- a/src/doc/rustc/src/linker-plugin-lto.md +++ b/src/doc/rustc/src/linker-plugin-lto.md @@ -105,5 +105,6 @@ The following table shows known good combinations of toolchain versions. | Rust 1.34 | ✗ | ✓ | | Rust 1.35 | ✗ | ✓ | | Rust 1.36 | ✗ | ✓ | +| Rust 1.37 | ✗ | ✓ | Note that the compatibility policy for this feature might change in the future. diff --git a/src/doc/rustc/src/lints/listing/allowed-by-default.md b/src/doc/rustc/src/lints/listing/allowed-by-default.md index a6e4e166d7bc6..d3dfc3197e2f6 100644 --- a/src/doc/rustc/src/lints/listing/allowed-by-default.md +++ b/src/doc/rustc/src/lints/listing/allowed-by-default.md @@ -208,7 +208,7 @@ error: missing documentation for a function To fix the lint, add documentation to all items. -## single-use-lifetime +## single-use-lifetimes This lint detects lifetimes that are only used once. Some example code that triggers this lint: diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 6e32468b64dee..49d05b5038df7 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -311,19 +311,6 @@ When `rustdoc` receives this flag, it will print an extra "Version (version)" in the crate root's docs. You can use this flag to differentiate between different versions of your library's documentation. -### `--linker`: control the linker used for documentation tests - -Using this flag looks like this: - -```bash -$ rustdoc --test src/lib.rs -Z unstable-options --linker foo -$ rustdoc --test README.md -Z unstable-options --linker foo -``` - -When `rustdoc` runs your documentation tests, it needs to compile and link the tests as executables -before running them. This flag can be used to change the linker used on these executables. It's -equivalent to passing `-C linker=foo` to `rustc`. - ### `--sort-modules-by-appearance`: control how items on module pages are sorted Using this flag looks like this: @@ -484,3 +471,53 @@ Some methodology notes about what rustdoc counts in this metric: Public items that are not documented can be seen with the built-in `missing_docs` lint. Private items that are not documented can be seen with Clippy's `missing_docs_in_private_items` lint. + +### `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests + +Using this flag looks like this: + +```bash +$ rustdoc src/lib.rs -Z unstable-options --enable-per-target-ignores +``` + +This flag allows you to tag doctests with compiltest style `ignore-foo` filters that prevent +rustdoc from running that test if the target triple string contains foo. For example: + +```rust +///```ignore-foo,ignore-bar +///assert!(2 == 2); +///``` +struct Foo; +``` + +This will not be run when the build target is `super-awesome-foo` or `less-bar-awesome`. +If the flag is not enabled, then rustdoc will consume the filter, but do nothing with it, and +the above example will be run for all targets. +If you want to preserve backwards compatibility for older versions of rustdoc, you can use + +```rust +///```ignore,ignore-foo +///assert!(2 == 2); +///``` +struct Foo; +``` + +In older versions, this will be ignored on all targets, but on newer versions `ignore-gnu` will +override `ignore`. + +### `--runtool`, `--runtool-arg`: program to run tests with; args to pass to it + +Using thses options looks like this: + +```bash +$ rustdoc src/lib.rs -Z unstable-options --runtool runner --runtool-arg --do-thing --runtool-arg --do-other-thing +``` + +These options can be used to run the doctest under a program, and also pass arguments to +that program. For example, if you want to run your doctests under valgrind you might run + +```bash +$ rustdoc src/lib.rs -Z unstable-options --runtool valgrind +``` + +Another use case would be to run a test inside an emulator, or through a Virtual Machine. diff --git a/src/doc/unstable-book/src/compiler-flags/report-time.md b/src/doc/unstable-book/src/compiler-flags/report-time.md new file mode 100644 index 0000000000000..ed4e9c6b56842 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/report-time.md @@ -0,0 +1,80 @@ +# `report-time` + +The tracking issue for this feature is: [#64888] + +[#64888]: https://github.com/rust-lang/rust/issues/64888 + +------------------------ + +The `report-time` feature adds a possibility to report execution time of the +tests generated via `libtest`. + +This is unstable feature, so you have to provide `-Zunstable-options` to get +this feature working. + +Sample usage command: + +```sh +./test_executable -Zunstable-options --report-time +``` + +Available options: + +```sh +--report-time [plain|colored] + Show execution time of each test. Awailable values: + plain = do not colorize the execution time (default); + colored = colorize output according to the `color` + parameter value; + Threshold values for colorized output can be + configured via + `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` + and + `RUST_TEST_TIME_DOCTEST` environment variables. + Expected format of environment variable is + `VARIABLE=WARN_TIME,CRITICAL_TIME`. + Not available for --format=terse +--ensure-time + Treat excess of the test execution time limit as + error. + Threshold values for this option can be configured via + `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` + and + `RUST_TEST_TIME_DOCTEST` environment variables. + Expected format of environment variable is + `VARIABLE=WARN_TIME,CRITICAL_TIME`. + `CRITICAL_TIME` here means the limit that should not be + exceeded by test. +``` + +Example of the environment variable format: + +```sh +RUST_TEST_TIME_UNIT=100,200 +``` + +where 100 stands for warn time, and 200 stands for critical time. + +## Examples + +```sh +cargo test --tests -- -Zunstable-options --report-time + Finished dev [unoptimized + debuginfo] target(s) in 0.02s + Running target/debug/deps/example-27fb188025bec02c + +running 3 tests +test tests::unit_test_quick ... ok <0.000s> +test tests::unit_test_warn ... ok <0.055s> +test tests::unit_test_critical ... ok <0.110s> + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + + Running target/debug/deps/tests-cedb06f6526d15d9 + +running 3 tests +test unit_test_quick ... ok <0.000s> +test unit_test_warn ... ok <0.550s> +test unit_test_critical ... ok <1.100s> + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +``` diff --git a/src/doc/unstable-book/src/language-features/or-patterns.md b/src/doc/unstable-book/src/language-features/or-patterns.md new file mode 100644 index 0000000000000..8ebacb44d37cc --- /dev/null +++ b/src/doc/unstable-book/src/language-features/or-patterns.md @@ -0,0 +1,36 @@ +# `or_patterns` + +The tracking issue for this feature is: [#54883] + +[#54883]: https://github.com/rust-lang/rust/issues/54883 + +------------------------ + +The `or_pattern` language feature allows `|` to be arbitrarily nested within +a pattern, for example, `Some(A(0) | B(1 | 2))` becomes a valid pattern. + +## Examples + +```rust,ignore +#![feature(or_patterns)] + +pub enum Foo { + Bar, + Baz, + Quux, +} + +pub fn example(maybe_foo: Option) { + match maybe_foo { + Some(Foo::Bar | Foo::Baz) => { + println!("The value contained `Bar` or `Baz`"); + } + Some(_) => { + println!("The value did not contain `Bar` or `Baz`"); + } + None => { + println!("The value was `None`"); + } + } +} +``` diff --git a/src/doc/unstable-book/src/language-features/param-attrs.md b/src/doc/unstable-book/src/language-features/param-attrs.md deleted file mode 100644 index 4b83c204ba105..0000000000000 --- a/src/doc/unstable-book/src/language-features/param-attrs.md +++ /dev/null @@ -1,27 +0,0 @@ -# `param_attrs` - -The tracking issue for this feature is: [#60406] - -[#60406]: https://github.com/rust-lang/rust/issues/60406 - -Allow attributes in formal function parameter position so external tools and compiler internals can -take advantage of the additional information that the parameters provide. - -Enables finer conditional compilation with `#[cfg(..)]` and linting control of variables. Moreover, -opens the path to richer DSLs created by users. - ------------------------- - -Example: - -```rust -#![feature(param_attrs)] - -fn len( - #[cfg(windows)] slice: &[u16], - #[cfg(not(windows))] slice: &[u8], -) -> usize -{ - slice.len() -} -``` diff --git a/src/doc/unstable-book/src/language-features/plugin.md b/src/doc/unstable-book/src/language-features/plugin.md index 8be4d16998276..68877b48433d5 100644 --- a/src/doc/unstable-book/src/language-features/plugin.md +++ b/src/doc/unstable-book/src/language-features/plugin.md @@ -18,7 +18,7 @@ extend the compiler's behavior with new syntax extensions, lint checks, etc. A plugin is a dynamic library crate with a designated *registrar* function that registers extensions with `rustc`. Other crates can load these extensions using the crate attribute `#![plugin(...)]`. See the -`rustc_plugin` documentation for more about the +`rustc_driver::plugin` documentation for more about the mechanics of defining and loading a plugin. If present, arguments passed as `#![plugin(foo(... args ...))]` are not @@ -54,15 +54,15 @@ that implements Roman numeral integer literals. extern crate syntax; extern crate syntax_pos; extern crate rustc; -extern crate rustc_plugin; +extern crate rustc_driver; use syntax::parse::token::{self, Token}; -use syntax::tokenstream::TokenTree; +use syntax::tokenstream::{TokenTree, TokenStream}; use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; use syntax_pos::Span; -use rustc_plugin::Registry; +use rustc_driver::plugin::Registry; -fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) +fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: TokenStream) -> Box { static NUMERALS: &'static [(&'static str, usize)] = &[ @@ -78,7 +78,7 @@ fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) return DummyResult::any(sp); } - let text = match args[0] { + let text = match args.into_trees().next().unwrap() { TokenTree::Token(Token { kind: token::Ident(s, _), .. }) => s.to_string(), _ => { cx.span_err(sp, "argument should be a single identifier"); @@ -180,11 +180,11 @@ extern crate syntax; // Load rustc as a plugin to get macros #[macro_use] extern crate rustc; -extern crate rustc_plugin; +extern crate rustc_driver; use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, EarlyLintPassObject, LintArray}; -use rustc_plugin::Registry; +use rustc_driver::plugin::Registry; use syntax::ast; declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); diff --git a/src/doc/unstable-book/src/language-features/track-caller.md b/src/doc/unstable-book/src/language-features/track-caller.md new file mode 100644 index 0000000000000..afc11a2b9492c --- /dev/null +++ b/src/doc/unstable-book/src/language-features/track-caller.md @@ -0,0 +1,5 @@ +# `track_caller` + +The tracking issue for this feature is: [#47809](https://github.com/rust-lang/rust/issues/47809). + +------------------------ diff --git a/src/etc/generate-deriving-span-tests.py b/src/etc/generate-deriving-span-tests.py index 1c525101c76f6..66a3c8e555405 100755 --- a/src/etc/generate-deriving-span-tests.py +++ b/src/etc/generate-deriving-span-tests.py @@ -14,6 +14,8 @@ os.path.join(os.path.dirname(__file__), '../test/ui/derives/')) TEMPLATE = """\ +// ignore-x86 +// ^ due to stderr output differences // This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' {error_deriving} diff --git a/src/etc/installer/exe/rust.iss b/src/etc/installer/exe/rust.iss index c22d60b6c5df1..70648beac38b0 100644 --- a/src/etc/installer/exe/rust.iss +++ b/src/etc/installer/exe/rust.iss @@ -25,9 +25,9 @@ SourceDir=.\ OutputBaseFilename={#CFG_PACKAGE_NAME}-{#CFG_BUILD} DefaultDirName={sd}\Rust -Compression=lzma2/ultra -InternalCompressLevel=ultra -SolidCompression=true +Compression=lzma2/normal +InternalCompressLevel=normal +SolidCompression=no ChangesEnvironment=true ChangesAssociations=no diff --git a/src/etc/installer/msi/rust.wxs b/src/etc/installer/msi/rust.wxs index a471ccc6f5b48..a2e378f7b1db4 100644 --- a/src/etc/installer/msi/rust.wxs +++ b/src/etc/installer/msi/rust.wxs @@ -152,7 +152,7 @@ - + diff --git a/src/etc/lldb_batchmode.py b/src/etc/lldb_batchmode.py index 537b419b3279f..7c2e91474c1f1 100644 --- a/src/etc/lldb_batchmode.py +++ b/src/etc/lldb_batchmode.py @@ -45,7 +45,10 @@ def normalize_whitespace(s): def breakpoint_callback(frame, bp_loc, dict): """This callback is registered with every breakpoint and makes sure that the - frame containing the breakpoint location is selected""" + frame containing the breakpoint location is selected """ + + # HACK(eddyb) print a newline to avoid continuing an unfinished line. + print("") print("Hit breakpoint " + str(bp_loc)) # Select the frame and the thread containing it diff --git a/src/etc/wasm32-shim.js b/src/etc/wasm32-shim.js index 2a89c0d321d6a..262a53eabe3c7 100644 --- a/src/etc/wasm32-shim.js +++ b/src/etc/wasm32-shim.js @@ -15,113 +15,7 @@ const buffer = fs.readFileSync(process.argv[2]); Error.stackTraceLimit = 20; let m = new WebAssembly.Module(buffer); - -let memory = null; - -function viewstruct(data, fields) { - return new Uint32Array(memory.buffer).subarray(data/4, data/4 + fields); -} - -function copystr(a, b) { - let view = new Uint8Array(memory.buffer).subarray(a, a + b); - return String.fromCharCode.apply(null, view); -} - -function syscall_write([fd, ptr, len]) { - let s = copystr(ptr, len); - switch (fd) { - case 1: process.stdout.write(s); break; - case 2: process.stderr.write(s); break; - } -} - -function syscall_exit([code]) { - process.exit(code); -} - -function syscall_args(params) { - let [ptr, len] = params; - - // Calculate total required buffer size - let totalLen = -1; - for (let i = 2; i < process.argv.length; ++i) { - totalLen += Buffer.byteLength(process.argv[i]) + 1; - } - if (totalLen < 0) { totalLen = 0; } - params[2] = totalLen; - - // If buffer is large enough, copy data - if (len >= totalLen) { - let view = new Uint8Array(memory.buffer); - for (let i = 2; i < process.argv.length; ++i) { - let value = process.argv[i]; - Buffer.from(value).copy(view, ptr); - ptr += Buffer.byteLength(process.argv[i]) + 1; - } - } -} - -function syscall_getenv(params) { - let [keyPtr, keyLen, valuePtr, valueLen] = params; - - let key = copystr(keyPtr, keyLen); - let value = process.env[key]; - - if (value == null) { - params[4] = 0xFFFFFFFF; - } else { - let view = new Uint8Array(memory.buffer); - let totalLen = Buffer.byteLength(value); - params[4] = totalLen; - if (valueLen >= totalLen) { - Buffer.from(value).copy(view, valuePtr); - } - } -} - -function syscall_time(params) { - let t = Date.now(); - let secs = Math.floor(t / 1000); - let millis = t % 1000; - params[1] = Math.floor(secs / 0x100000000); - params[2] = secs % 0x100000000; - params[3] = Math.floor(millis * 1000000); -} - -let imports = {}; -imports.env = { - // These are generated by LLVM itself for various intrinsic calls. Hopefully - // one day this is not necessary and something will automatically do this. - fmod: function(x, y) { return x % y; }, - exp2: function(x) { return Math.pow(2, x); }, - exp2f: function(x) { return Math.pow(2, x); }, - ldexp: function(x, y) { return x * Math.pow(2, y); }, - ldexpf: function(x, y) { return x * Math.pow(2, y); }, - sin: Math.sin, - sinf: Math.sin, - cos: Math.cos, - cosf: Math.cos, - log: Math.log, - log2: Math.log2, - log10: Math.log10, - log10f: Math.log10, - - rust_wasm_syscall: function(index, data) { - switch (index) { - case 1: syscall_write(viewstruct(data, 3)); return true; - case 2: syscall_exit(viewstruct(data, 1)); return true; - case 3: syscall_args(viewstruct(data, 3)); return true; - case 4: syscall_getenv(viewstruct(data, 5)); return true; - case 6: syscall_time(viewstruct(data, 4)); return true; - default: - console.log("Unsupported syscall: " + index); - return false; - } - } -}; - -let instance = new WebAssembly.Instance(m, imports); -memory = instance.exports.memory; +let instance = new WebAssembly.Instance(m, {}); try { instance.exports.main(); } catch (e) { diff --git a/src/grammar/.gitignore b/src/grammar/.gitignore deleted file mode 100644 index 3e4498759434f..0000000000000 --- a/src/grammar/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.class -*.java -*.tokens diff --git a/src/grammar/lexer.l b/src/grammar/lexer.l deleted file mode 100644 index 1feb781b2b39f..0000000000000 --- a/src/grammar/lexer.l +++ /dev/null @@ -1,350 +0,0 @@ -%{ -#include -#include - -static int num_hashes; -static int end_hashes; -static int saw_non_hash; - -%} - -%option stack -%option yylineno - -%x str -%x rawstr -%x rawstr_esc_begin -%x rawstr_esc_body -%x rawstr_esc_end -%x byte -%x bytestr -%x rawbytestr -%x rawbytestr_nohash -%x pound -%x shebang_or_attr -%x ltorchar -%x linecomment -%x doc_line -%x blockcomment -%x doc_block -%x suffix - -ident [a-zA-Z\x80-\xff_][a-zA-Z0-9\x80-\xff_]* - -%% - -{ident} { BEGIN(INITIAL); } -(.|\n) { yyless(0); BEGIN(INITIAL); } - -[ \n\t\r] { } - -\xef\xbb\xbf { - // UTF-8 byte order mark (BOM), ignore if in line 1, error otherwise - if (yyget_lineno() != 1) { - return -1; - } -} - -\/\/(\/|\!) { BEGIN(doc_line); yymore(); } -\n { BEGIN(INITIAL); - yyleng--; - yytext[yyleng] = 0; - return ((yytext[2] == '!') ? INNER_DOC_COMMENT : OUTER_DOC_COMMENT); - } -[^\n]* { yymore(); } - -\/\/|\/\/\/\/ { BEGIN(linecomment); } -\n { BEGIN(INITIAL); } -[^\n]* { } - -\/\*(\*|\!)[^*] { yy_push_state(INITIAL); yy_push_state(doc_block); yymore(); } -\/\* { yy_push_state(doc_block); yymore(); } -\*\/ { - yy_pop_state(); - if (yy_top_state() == doc_block) { - yymore(); - } else { - return ((yytext[2] == '!') ? INNER_DOC_COMMENT : OUTER_DOC_COMMENT); - } -} -(.|\n) { yymore(); } - -\/\* { yy_push_state(blockcomment); } -\/\* { yy_push_state(blockcomment); } -\*\/ { yy_pop_state(); } -(.|\n) { } - -_ { return UNDERSCORE; } -abstract { return ABSTRACT; } -alignof { return ALIGNOF; } -as { return AS; } -become { return BECOME; } -box { return BOX; } -break { return BREAK; } -catch { return CATCH; } -const { return CONST; } -continue { return CONTINUE; } -crate { return CRATE; } -default { return DEFAULT; } -do { return DO; } -else { return ELSE; } -enum { return ENUM; } -extern { return EXTERN; } -false { return FALSE; } -final { return FINAL; } -fn { return FN; } -for { return FOR; } -if { return IF; } -impl { return IMPL; } -in { return IN; } -let { return LET; } -loop { return LOOP; } -macro { return MACRO; } -match { return MATCH; } -mod { return MOD; } -move { return MOVE; } -mut { return MUT; } -offsetof { return OFFSETOF; } -override { return OVERRIDE; } -priv { return PRIV; } -proc { return PROC; } -pure { return PURE; } -pub { return PUB; } -ref { return REF; } -return { return RETURN; } -self { return SELF; } -sizeof { return SIZEOF; } -static { return STATIC; } -struct { return STRUCT; } -super { return SUPER; } -trait { return TRAIT; } -true { return TRUE; } -type { return TYPE; } -typeof { return TYPEOF; } -union { return UNION; } -unsafe { return UNSAFE; } -unsized { return UNSIZED; } -use { return USE; } -virtual { return VIRTUAL; } -where { return WHERE; } -while { return WHILE; } -yield { return YIELD; } - -{ident} { return IDENT; } - -0x[0-9a-fA-F_]+ { BEGIN(suffix); return LIT_INTEGER; } -0o[0-7_]+ { BEGIN(suffix); return LIT_INTEGER; } -0b[01_]+ { BEGIN(suffix); return LIT_INTEGER; } -[0-9][0-9_]* { BEGIN(suffix); return LIT_INTEGER; } -[0-9][0-9_]*\.(\.|[a-zA-Z]) { yyless(yyleng - 2); BEGIN(suffix); return LIT_INTEGER; } - -[0-9][0-9_]*\.[0-9_]*([eE][-\+]?[0-9_]+)? { BEGIN(suffix); return LIT_FLOAT; } -[0-9][0-9_]*(\.[0-9_]*)?[eE][-\+]?[0-9_]+ { BEGIN(suffix); return LIT_FLOAT; } - -; { return ';'; } -, { return ','; } -\.\.\. { return DOTDOTDOT; } -\.\. { return DOTDOT; } -\. { return '.'; } -\( { return '('; } -\) { return ')'; } -\{ { return '{'; } -\} { return '}'; } -\[ { return '['; } -\] { return ']'; } -@ { return '@'; } -# { BEGIN(pound); yymore(); } -\! { BEGIN(shebang_or_attr); yymore(); } -\[ { - BEGIN(INITIAL); - yyless(2); - return SHEBANG; -} -[^\[\n]*\n { - // Since the \n was eaten as part of the token, yylineno will have - // been incremented to the value 2 if the shebang was on the first - // line. This yyless undoes that, setting yylineno back to 1. - yyless(yyleng - 1); - if (yyget_lineno() == 1) { - BEGIN(INITIAL); - return SHEBANG_LINE; - } else { - BEGIN(INITIAL); - yyless(2); - return SHEBANG; - } -} -. { BEGIN(INITIAL); yyless(1); return '#'; } - -\~ { return '~'; } -:: { return MOD_SEP; } -: { return ':'; } -\$ { return '$'; } -\? { return '?'; } - -== { return EQEQ; } -=> { return FAT_ARROW; } -= { return '='; } -\!= { return NE; } -\! { return '!'; } -\<= { return LE; } -\<\< { return SHL; } -\<\<= { return SHLEQ; } -\< { return '<'; } -\>= { return GE; } -\>\> { return SHR; } -\>\>= { return SHREQ; } -\> { return '>'; } - -\x27 { BEGIN(ltorchar); yymore(); } -static { BEGIN(INITIAL); return STATIC_LIFETIME; } -{ident} { BEGIN(INITIAL); return LIFETIME; } -\\[nrt\\\x27\x220]\x27 { BEGIN(suffix); return LIT_CHAR; } -\\x[0-9a-fA-F]{2}\x27 { BEGIN(suffix); return LIT_CHAR; } -\\u\{([0-9a-fA-F]_*){1,6}\}\x27 { BEGIN(suffix); return LIT_CHAR; } -.\x27 { BEGIN(suffix); return LIT_CHAR; } -[\x80-\xff]{2,4}\x27 { BEGIN(suffix); return LIT_CHAR; } -<> { BEGIN(INITIAL); return -1; } - -b\x22 { BEGIN(bytestr); yymore(); } -\x22 { BEGIN(suffix); return LIT_BYTE_STR; } - -<> { return -1; } -\\[n\nrt\\\x27\x220] { yymore(); } -\\x[0-9a-fA-F]{2} { yymore(); } -\\u\{([0-9a-fA-F]_*){1,6}\} { yymore(); } -\\[^n\nrt\\\x27\x220] { return -1; } -(.|\n) { yymore(); } - -br\x22 { BEGIN(rawbytestr_nohash); yymore(); } -\x22 { BEGIN(suffix); return LIT_BYTE_STR_RAW; } -(.|\n) { yymore(); } -<> { return -1; } - -br/# { - BEGIN(rawbytestr); - yymore(); - num_hashes = 0; - saw_non_hash = 0; - end_hashes = 0; -} -# { - if (!saw_non_hash) { - num_hashes++; - } else if (end_hashes != 0) { - end_hashes++; - if (end_hashes == num_hashes) { - BEGIN(INITIAL); - return LIT_BYTE_STR_RAW; - } - } - yymore(); -} -\x22# { - end_hashes = 1; - if (end_hashes == num_hashes) { - BEGIN(INITIAL); - return LIT_BYTE_STR_RAW; - } - yymore(); -} -(.|\n) { - if (!saw_non_hash) { - saw_non_hash = 1; - } - if (end_hashes != 0) { - end_hashes = 0; - } - yymore(); -} -<> { return -1; } - -b\x27 { BEGIN(byte); yymore(); } -\\[nrt\\\x27\x220]\x27 { BEGIN(INITIAL); return LIT_BYTE; } -\\x[0-9a-fA-F]{2}\x27 { BEGIN(INITIAL); return LIT_BYTE; } -\\u([0-9a-fA-F]_*){4}\x27 { BEGIN(INITIAL); return LIT_BYTE; } -\\U([0-9a-fA-F]_*){8}\x27 { BEGIN(INITIAL); return LIT_BYTE; } -.\x27 { BEGIN(INITIAL); return LIT_BYTE; } -<> { BEGIN(INITIAL); return -1; } - -r\x22 { BEGIN(rawstr); yymore(); } -\x22 { BEGIN(suffix); return LIT_STR_RAW; } -(.|\n) { yymore(); } -<> { return -1; } - -r/# { - BEGIN(rawstr_esc_begin); - yymore(); - num_hashes = 0; - saw_non_hash = 0; - end_hashes = 0; -} - -# { - num_hashes++; - yymore(); -} -\x22 { - BEGIN(rawstr_esc_body); - yymore(); -} -(.|\n) { return -1; } - -\x22/# { - BEGIN(rawstr_esc_end); - yymore(); - } -(.|\n) { - yymore(); - } - -# { - end_hashes++; - if (end_hashes == num_hashes) { - BEGIN(INITIAL); - return LIT_STR_RAW; - } - yymore(); - } -[^#] { - end_hashes = 0; - BEGIN(rawstr_esc_body); - yymore(); - } - -<> { return -1; } - -\x22 { BEGIN(str); yymore(); } -\x22 { BEGIN(suffix); return LIT_STR; } - -<> { return -1; } -\\[n\nr\rt\\\x27\x220] { yymore(); } -\\x[0-9a-fA-F]{2} { yymore(); } -\\u\{([0-9a-fA-F]_*){1,6}\} { yymore(); } -\\[^n\nrt\\\x27\x220] { return -1; } -(.|\n) { yymore(); } - -\<- { return LARROW; } --\> { return RARROW; } -- { return '-'; } --= { return MINUSEQ; } -&& { return ANDAND; } -& { return '&'; } -&= { return ANDEQ; } -\|\| { return OROR; } -\| { return '|'; } -\|= { return OREQ; } -\+ { return '+'; } -\+= { return PLUSEQ; } -\* { return '*'; } -\*= { return STAREQ; } -\/ { return '/'; } -\/= { return SLASHEQ; } -\^ { return '^'; } -\^= { return CARETEQ; } -% { return '%'; } -%= { return PERCENTEQ; } - -<> { return 0; } - -%% diff --git a/src/grammar/parser-lalr-main.c b/src/grammar/parser-lalr-main.c deleted file mode 100644 index 6348190cc140b..0000000000000 --- a/src/grammar/parser-lalr-main.c +++ /dev/null @@ -1,193 +0,0 @@ -#include -#include -#include -#include - -extern int yylex(); -extern int rsparse(); - -#define PUSHBACK_LEN 4 - -static char pushback[PUSHBACK_LEN]; -static int verbose; - -void print(const char* format, ...) { - va_list args; - va_start(args, format); - if (verbose) { - vprintf(format, args); - } - va_end(args); -} - -// If there is a non-null char at the head of the pushback queue, -// dequeue it and shift the rest of the queue forwards. Otherwise, -// return the token from calling yylex. -int rslex() { - if (pushback[0] == '\0') { - return yylex(); - } else { - char c = pushback[0]; - memmove(pushback, pushback + 1, PUSHBACK_LEN - 1); - pushback[PUSHBACK_LEN - 1] = '\0'; - return c; - } -} - -// Note: this does nothing if the pushback queue is full. As long as -// there aren't more than PUSHBACK_LEN consecutive calls to push_back -// in an action, this shouldn't be a problem. -void push_back(char c) { - for (int i = 0; i < PUSHBACK_LEN; ++i) { - if (pushback[i] == '\0') { - pushback[i] = c; - break; - } - } -} - -extern int rsdebug; - -struct node { - struct node *next; - struct node *prev; - int own_string; - char const *name; - int n_elems; - struct node *elems[]; -}; - -struct node *nodes = NULL; -int n_nodes; - -struct node *mk_node(char const *name, int n, ...) { - va_list ap; - int i = 0; - unsigned sz = sizeof(struct node) + (n * sizeof(struct node *)); - struct node *nn, *nd = (struct node *)malloc(sz); - - print("# New %d-ary node: %s = %p\n", n, name, nd); - - nd->own_string = 0; - nd->prev = NULL; - nd->next = nodes; - if (nodes) { - nodes->prev = nd; - } - nodes = nd; - - nd->name = name; - nd->n_elems = n; - - va_start(ap, n); - while (i < n) { - nn = va_arg(ap, struct node *); - print("# arg[%d]: %p\n", i, nn); - print("# (%s ...)\n", nn->name); - nd->elems[i++] = nn; - } - va_end(ap); - n_nodes++; - return nd; -} - -struct node *mk_atom(char *name) { - struct node *nd = mk_node((char const *)strdup(name), 0); - nd->own_string = 1; - return nd; -} - -struct node *mk_none() { - return mk_atom(""); -} - -struct node *ext_node(struct node *nd, int n, ...) { - va_list ap; - int i = 0, c = nd->n_elems + n; - unsigned sz = sizeof(struct node) + (c * sizeof(struct node *)); - struct node *nn; - - print("# Extending %d-ary node by %d nodes: %s = %p", - nd->n_elems, c, nd->name, nd); - - if (nd->next) { - nd->next->prev = nd->prev; - } - if (nd->prev) { - nd->prev->next = nd->next; - } - nd = realloc(nd, sz); - nd->prev = NULL; - nd->next = nodes; - nodes->prev = nd; - nodes = nd; - - print(" ==> %p\n", nd); - - va_start(ap, n); - while (i < n) { - nn = va_arg(ap, struct node *); - print("# arg[%d]: %p\n", i, nn); - print("# (%s ...)\n", nn->name); - nd->elems[nd->n_elems++] = nn; - ++i; - } - va_end(ap); - return nd; -} - -int const indent_step = 4; - -void print_indent(int depth) { - while (depth) { - if (depth-- % indent_step == 0) { - print("|"); - } else { - print(" "); - } - } -} - -void print_node(struct node *n, int depth) { - int i = 0; - print_indent(depth); - if (n->n_elems == 0) { - print("%s\n", n->name); - } else { - print("(%s\n", n->name); - for (i = 0; i < n->n_elems; ++i) { - print_node(n->elems[i], depth + indent_step); - } - print_indent(depth); - print(")\n"); - } -} - -int main(int argc, char **argv) { - if (argc == 2 && strcmp(argv[1], "-v") == 0) { - verbose = 1; - } else { - verbose = 0; - } - int ret = 0; - struct node *tmp; - memset(pushback, '\0', PUSHBACK_LEN); - ret = rsparse(); - print("--- PARSE COMPLETE: ret:%d, n_nodes:%d ---\n", ret, n_nodes); - if (nodes) { - print_node(nodes, 0); - } - while (nodes) { - tmp = nodes; - nodes = tmp->next; - if (tmp->own_string) { - free((void*)tmp->name); - } - free(tmp); - } - return ret; -} - -void rserror(char const *s) { - fprintf(stderr, "%s\n", s); -} diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y deleted file mode 100644 index 5585c95a5a63a..0000000000000 --- a/src/grammar/parser-lalr.y +++ /dev/null @@ -1,1982 +0,0 @@ -%{ -#define YYERROR_VERBOSE -#define YYSTYPE struct node * -struct node; -extern int yylex(); -extern void yyerror(char const *s); -extern struct node *mk_node(char const *name, int n, ...); -extern struct node *mk_atom(char *text); -extern struct node *mk_none(); -extern struct node *ext_node(struct node *nd, int n, ...); -extern void push_back(char c); -extern char *yytext; -%} -%debug - -%token SHL -%token SHR -%token LE -%token EQEQ -%token NE -%token GE -%token ANDAND -%token OROR -%token SHLEQ -%token SHREQ -%token MINUSEQ -%token ANDEQ -%token OREQ -%token PLUSEQ -%token STAREQ -%token SLASHEQ -%token CARETEQ -%token PERCENTEQ -%token DOTDOT -%token DOTDOTDOT -%token MOD_SEP -%token RARROW -%token LARROW -%token FAT_ARROW -%token LIT_BYTE -%token LIT_CHAR -%token LIT_INTEGER -%token LIT_FLOAT -%token LIT_STR -%token LIT_STR_RAW -%token LIT_BYTE_STR -%token LIT_BYTE_STR_RAW -%token IDENT -%token UNDERSCORE -%token LIFETIME - -// keywords -%token SELF -%token STATIC -%token ABSTRACT -%token ALIGNOF -%token AS -%token BECOME -%token BREAK -%token CATCH -%token CRATE -%token DO -%token ELSE -%token ENUM -%token EXTERN -%token FALSE -%token FINAL -%token FN -%token FOR -%token IF -%token IMPL -%token IN -%token LET -%token LOOP -%token MACRO -%token MATCH -%token MOD -%token MOVE -%token MUT -%token OFFSETOF -%token OVERRIDE -%token PRIV -%token PUB -%token PURE -%token REF -%token RETURN -%token SIZEOF -%token STRUCT -%token SUPER -%token UNION -%token UNSIZED -%token TRUE -%token TRAIT -%token TYPE -%token UNSAFE -%token VIRTUAL -%token YIELD -%token DEFAULT -%token USE -%token WHILE -%token CONTINUE -%token PROC -%token BOX -%token CONST -%token WHERE -%token TYPEOF -%token INNER_DOC_COMMENT -%token OUTER_DOC_COMMENT - -%token SHEBANG -%token SHEBANG_LINE -%token STATIC_LIFETIME - - /* - Quoting from the Bison manual: - - "Finally, the resolution of conflicts works by comparing the precedence - of the rule being considered with that of the lookahead token. If the - token's precedence is higher, the choice is to shift. If the rule's - precedence is higher, the choice is to reduce. If they have equal - precedence, the choice is made based on the associativity of that - precedence level. The verbose output file made by ‘-v’ (see Invoking - Bison) says how each conflict was resolved" - */ - -// We expect no shift/reduce or reduce/reduce conflicts in this grammar; -// all potential ambiguities are scrutinized and eliminated manually. -%expect 0 - -// fake-precedence symbol to cause '|' bars in lambda context to parse -// at low precedence, permit things like |x| foo = bar, where '=' is -// otherwise lower-precedence than '|'. Also used for proc() to cause -// things like proc() a + b to parse as proc() { a + b }. -%precedence LAMBDA - -%precedence SELF - -// MUT should be lower precedence than IDENT so that in the pat rule, -// "& MUT pat" has higher precedence than "binding_mode ident [@ pat]" -%precedence MUT - -// IDENT needs to be lower than '{' so that 'foo {' is shifted when -// trying to decide if we've got a struct-construction expr (esp. in -// contexts like 'if foo { .') -// -// IDENT also needs to be lower precedence than '<' so that '<' in -// 'foo:bar . <' is shifted (in a trait reference occurring in a -// bounds list), parsing as foo:(bar) rather than (foo:bar). -%precedence IDENT - // Put the weak keywords that can be used as idents here as well -%precedence CATCH -%precedence DEFAULT -%precedence UNION - -// A couple fake-precedence symbols to use in rules associated with + -// and < in trailing type contexts. These come up when you have a type -// in the RHS of operator-AS, such as "foo as bar". The "<" there -// has to be shifted so the parser keeps trying to parse a type, even -// though it might well consider reducing the type "bar" and then -// going on to "<" as a subsequent binop. The "+" case is with -// trailing type-bounds ("foo as bar:A+B"), for the same reason. -%precedence SHIFTPLUS - -%precedence MOD_SEP -%precedence RARROW ':' - -// In where clauses, "for" should have greater precedence when used as -// a higher ranked constraint than when used as the beginning of a -// for_in_type (which is a ty) -%precedence FORTYPE -%precedence FOR - -// Binops & unops, and their precedences -%precedence '?' -%precedence BOX -%nonassoc DOTDOT - -// RETURN needs to be lower-precedence than tokens that start -// prefix_exprs -%precedence RETURN YIELD - -%right '=' SHLEQ SHREQ MINUSEQ ANDEQ OREQ PLUSEQ STAREQ SLASHEQ CARETEQ PERCENTEQ -%right LARROW -%left OROR -%left ANDAND -%left EQEQ NE -%left '<' '>' LE GE -%left '|' -%left '^' -%left '&' -%left SHL SHR -%left '+' '-' -%precedence AS -%left '*' '/' '%' -%precedence '!' - -%precedence '{' '[' '(' '.' - -%precedence RANGE - -%start crate - -%% - -//////////////////////////////////////////////////////////////////////// -// Part 1: Items and attributes -//////////////////////////////////////////////////////////////////////// - -crate -: maybe_shebang inner_attrs maybe_mod_items { mk_node("crate", 2, $2, $3); } -| maybe_shebang maybe_mod_items { mk_node("crate", 1, $2); } -; - -maybe_shebang -: SHEBANG_LINE -| %empty -; - -maybe_inner_attrs -: inner_attrs -| %empty { $$ = mk_none(); } -; - -inner_attrs -: inner_attr { $$ = mk_node("InnerAttrs", 1, $1); } -| inner_attrs inner_attr { $$ = ext_node($1, 1, $2); } -; - -inner_attr -: SHEBANG '[' meta_item ']' { $$ = mk_node("InnerAttr", 1, $3); } -| INNER_DOC_COMMENT { $$ = mk_node("InnerAttr", 1, mk_node("doc-comment", 1, mk_atom(yytext))); } -; - -maybe_outer_attrs -: outer_attrs -| %empty { $$ = mk_none(); } -; - -outer_attrs -: outer_attr { $$ = mk_node("OuterAttrs", 1, $1); } -| outer_attrs outer_attr { $$ = ext_node($1, 1, $2); } -; - -outer_attr -: '#' '[' meta_item ']' { $$ = $3; } -| OUTER_DOC_COMMENT { $$ = mk_node("doc-comment", 1, mk_atom(yytext)); } -; - -meta_item -: ident { $$ = mk_node("MetaWord", 1, $1); } -| ident '=' lit { $$ = mk_node("MetaNameValue", 2, $1, $3); } -| ident '(' meta_seq ')' { $$ = mk_node("MetaList", 2, $1, $3); } -| ident '(' meta_seq ',' ')' { $$ = mk_node("MetaList", 2, $1, $3); } -; - -meta_seq -: %empty { $$ = mk_none(); } -| meta_item { $$ = mk_node("MetaItems", 1, $1); } -| meta_seq ',' meta_item { $$ = ext_node($1, 1, $3); } -; - -maybe_mod_items -: mod_items -| %empty { $$ = mk_none(); } -; - -mod_items -: mod_item { $$ = mk_node("Items", 1, $1); } -| mod_items mod_item { $$ = ext_node($1, 1, $2); } -; - -attrs_and_vis -: maybe_outer_attrs visibility { $$ = mk_node("AttrsAndVis", 2, $1, $2); } -; - -mod_item -: attrs_and_vis item { $$ = mk_node("Item", 2, $1, $2); } -; - -// items that can appear outside of a fn block -item -: stmt_item -| item_macro -; - -// items that can appear in "stmts" -stmt_item -: item_static -| item_const -| item_type -| block_item -| view_item -; - -item_static -: STATIC ident ':' ty '=' expr ';' { $$ = mk_node("ItemStatic", 3, $2, $4, $6); } -| STATIC MUT ident ':' ty '=' expr ';' { $$ = mk_node("ItemStatic", 3, $3, $5, $7); } -; - -item_const -: CONST ident ':' ty '=' expr ';' { $$ = mk_node("ItemConst", 3, $2, $4, $6); } -; - -item_macro -: path_expr '!' maybe_ident parens_delimited_token_trees ';' { $$ = mk_node("ItemMacro", 3, $1, $3, $4); } -| path_expr '!' maybe_ident braces_delimited_token_trees { $$ = mk_node("ItemMacro", 3, $1, $3, $4); } -| path_expr '!' maybe_ident brackets_delimited_token_trees ';'{ $$ = mk_node("ItemMacro", 3, $1, $3, $4); } -; - -view_item -: use_item -| extern_fn_item -| EXTERN CRATE ident ';' { $$ = mk_node("ViewItemExternCrate", 1, $3); } -| EXTERN CRATE ident AS ident ';' { $$ = mk_node("ViewItemExternCrate", 2, $3, $5); } -; - -extern_fn_item -: EXTERN maybe_abi item_fn { $$ = mk_node("ViewItemExternFn", 2, $2, $3); } -; - -use_item -: USE view_path ';' { $$ = mk_node("ViewItemUse", 1, $2); } -; - -view_path -: path_no_types_allowed { $$ = mk_node("ViewPathSimple", 1, $1); } -| path_no_types_allowed MOD_SEP '{' '}' { $$ = mk_node("ViewPathList", 2, $1, mk_atom("ViewPathListEmpty")); } -| MOD_SEP '{' '}' { $$ = mk_node("ViewPathList", 1, mk_atom("ViewPathListEmpty")); } -| path_no_types_allowed MOD_SEP '{' idents_or_self '}' { $$ = mk_node("ViewPathList", 2, $1, $4); } -| MOD_SEP '{' idents_or_self '}' { $$ = mk_node("ViewPathList", 1, $3); } -| path_no_types_allowed MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 2, $1, $4); } -| MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 1, $3); } -| path_no_types_allowed MOD_SEP '*' { $$ = mk_node("ViewPathGlob", 1, $1); } -| MOD_SEP '*' { $$ = mk_atom("ViewPathGlob"); } -| '*' { $$ = mk_atom("ViewPathGlob"); } -| '{' '}' { $$ = mk_atom("ViewPathListEmpty"); } -| '{' idents_or_self '}' { $$ = mk_node("ViewPathList", 1, $2); } -| '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 1, $2); } -| path_no_types_allowed AS ident { $$ = mk_node("ViewPathSimple", 2, $1, $3); } -; - -block_item -: item_fn -| item_unsafe_fn -| item_mod -| item_foreign_mod { $$ = mk_node("ItemForeignMod", 1, $1); } -| item_struct -| item_enum -| item_union -| item_trait -| item_impl -; - -maybe_ty_ascription -: ':' ty_sum { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -maybe_init_expr -: '=' expr { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -// structs -item_struct -: STRUCT ident generic_params maybe_where_clause struct_decl_args -{ - $$ = mk_node("ItemStruct", 4, $2, $3, $4, $5); -} -| STRUCT ident generic_params struct_tuple_args maybe_where_clause ';' -{ - $$ = mk_node("ItemStruct", 4, $2, $3, $4, $5); -} -| STRUCT ident generic_params maybe_where_clause ';' -{ - $$ = mk_node("ItemStruct", 3, $2, $3, $4); -} -; - -struct_decl_args -: '{' struct_decl_fields '}' { $$ = $2; } -| '{' struct_decl_fields ',' '}' { $$ = $2; } -; - -struct_tuple_args -: '(' struct_tuple_fields ')' { $$ = $2; } -| '(' struct_tuple_fields ',' ')' { $$ = $2; } -; - -struct_decl_fields -: struct_decl_field { $$ = mk_node("StructFields", 1, $1); } -| struct_decl_fields ',' struct_decl_field { $$ = ext_node($1, 1, $3); } -| %empty { $$ = mk_none(); } -; - -struct_decl_field -: attrs_and_vis ident ':' ty_sum { $$ = mk_node("StructField", 3, $1, $2, $4); } -; - -struct_tuple_fields -: struct_tuple_field { $$ = mk_node("StructFields", 1, $1); } -| struct_tuple_fields ',' struct_tuple_field { $$ = ext_node($1, 1, $3); } -| %empty { $$ = mk_none(); } -; - -struct_tuple_field -: attrs_and_vis ty_sum { $$ = mk_node("StructField", 2, $1, $2); } -; - -// enums -item_enum -: ENUM ident generic_params maybe_where_clause '{' enum_defs '}' { $$ = mk_node("ItemEnum", 0); } -| ENUM ident generic_params maybe_where_clause '{' enum_defs ',' '}' { $$ = mk_node("ItemEnum", 0); } -; - -enum_defs -: enum_def { $$ = mk_node("EnumDefs", 1, $1); } -| enum_defs ',' enum_def { $$ = ext_node($1, 1, $3); } -| %empty { $$ = mk_none(); } -; - -enum_def -: attrs_and_vis ident enum_args { $$ = mk_node("EnumDef", 3, $1, $2, $3); } -; - -enum_args -: '{' struct_decl_fields '}' { $$ = mk_node("EnumArgs", 1, $2); } -| '{' struct_decl_fields ',' '}' { $$ = mk_node("EnumArgs", 1, $2); } -| '(' maybe_ty_sums ')' { $$ = mk_node("EnumArgs", 1, $2); } -| '=' expr { $$ = mk_node("EnumArgs", 1, $2); } -| %empty { $$ = mk_none(); } -; - -// unions -item_union -: UNION ident generic_params maybe_where_clause '{' struct_decl_fields '}' { $$ = mk_node("ItemUnion", 0); } -| UNION ident generic_params maybe_where_clause '{' struct_decl_fields ',' '}' { $$ = mk_node("ItemUnion", 0); } - -item_mod -: MOD ident ';' { $$ = mk_node("ItemMod", 1, $2); } -| MOD ident '{' maybe_mod_items '}' { $$ = mk_node("ItemMod", 2, $2, $4); } -| MOD ident '{' inner_attrs maybe_mod_items '}' { $$ = mk_node("ItemMod", 3, $2, $4, $5); } -; - -item_foreign_mod -: EXTERN maybe_abi '{' maybe_foreign_items '}' { $$ = mk_node("ItemForeignMod", 1, $4); } -| EXTERN maybe_abi '{' inner_attrs maybe_foreign_items '}' { $$ = mk_node("ItemForeignMod", 2, $4, $5); } -; - -maybe_abi -: str -| %empty { $$ = mk_none(); } -; - -maybe_foreign_items -: foreign_items -| %empty { $$ = mk_none(); } -; - -foreign_items -: foreign_item { $$ = mk_node("ForeignItems", 1, $1); } -| foreign_items foreign_item { $$ = ext_node($1, 1, $2); } -; - -foreign_item -: attrs_and_vis STATIC item_foreign_static { $$ = mk_node("ForeignItem", 2, $1, $3); } -| attrs_and_vis item_foreign_fn { $$ = mk_node("ForeignItem", 2, $1, $2); } -| attrs_and_vis UNSAFE item_foreign_fn { $$ = mk_node("ForeignItem", 2, $1, $3); } -; - -item_foreign_static -: maybe_mut ident ':' ty ';' { $$ = mk_node("StaticItem", 3, $1, $2, $4); } -; - -item_foreign_fn -: FN ident generic_params fn_decl_allow_variadic maybe_where_clause ';' { $$ = mk_node("ForeignFn", 4, $2, $3, $4, $5); } -; - -fn_decl_allow_variadic -: fn_params_allow_variadic ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); } -; - -fn_params_allow_variadic -: '(' ')' { $$ = mk_none(); } -| '(' params ')' { $$ = $2; } -| '(' params ',' ')' { $$ = $2; } -| '(' params ',' DOTDOTDOT ')' { $$ = $2; } -; - -visibility -: PUB { $$ = mk_atom("Public"); } -| %empty { $$ = mk_atom("Inherited"); } -; - -idents_or_self -: ident_or_self { $$ = mk_node("IdentsOrSelf", 1, $1); } -| idents_or_self AS ident { $$ = mk_node("IdentsOrSelf", 2, $1, $3); } -| idents_or_self ',' ident_or_self { $$ = ext_node($1, 1, $3); } -; - -ident_or_self -: ident -| SELF { $$ = mk_atom(yytext); } -; - -item_type -: TYPE ident generic_params maybe_where_clause '=' ty_sum ';' { $$ = mk_node("ItemTy", 4, $2, $3, $4, $6); } -; - -for_sized -: FOR '?' ident { $$ = mk_node("ForSized", 1, $3); } -| FOR ident '?' { $$ = mk_node("ForSized", 1, $2); } -| %empty { $$ = mk_none(); } -; - -item_trait -: maybe_unsafe TRAIT ident generic_params for_sized maybe_ty_param_bounds maybe_where_clause '{' maybe_trait_items '}' -{ - $$ = mk_node("ItemTrait", 7, $1, $3, $4, $5, $6, $7, $9); -} -; - -maybe_trait_items -: trait_items -| %empty { $$ = mk_none(); } -; - -trait_items -: trait_item { $$ = mk_node("TraitItems", 1, $1); } -| trait_items trait_item { $$ = ext_node($1, 1, $2); } -; - -trait_item -: trait_const -| trait_type -| trait_method -| maybe_outer_attrs item_macro { $$ = mk_node("TraitMacroItem", 2, $1, $2); } -; - -trait_const -: maybe_outer_attrs CONST ident maybe_ty_ascription maybe_const_default ';' { $$ = mk_node("ConstTraitItem", 4, $1, $3, $4, $5); } -; - -maybe_const_default -: '=' expr { $$ = mk_node("ConstDefault", 1, $2); } -| %empty { $$ = mk_none(); } -; - -trait_type -: maybe_outer_attrs TYPE ty_param ';' { $$ = mk_node("TypeTraitItem", 2, $1, $3); } -; - -maybe_unsafe -: UNSAFE { $$ = mk_atom("Unsafe"); } -| %empty { $$ = mk_none(); } -; - -maybe_default_maybe_unsafe -: DEFAULT UNSAFE { $$ = mk_atom("DefaultUnsafe"); } -| DEFAULT { $$ = mk_atom("Default"); } -| UNSAFE { $$ = mk_atom("Unsafe"); } -| %empty { $$ = mk_none(); } - -trait_method -: type_method { $$ = mk_node("Required", 1, $1); } -| method { $$ = mk_node("Provided", 1, $1); } -; - -type_method -: maybe_outer_attrs maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' -{ - $$ = mk_node("TypeMethod", 6, $1, $2, $4, $5, $6, $7); -} -| maybe_outer_attrs CONST maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' -{ - $$ = mk_node("TypeMethod", 6, $1, $3, $5, $6, $7, $8); -} -| maybe_outer_attrs maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' -{ - $$ = mk_node("TypeMethod", 7, $1, $2, $4, $6, $7, $8, $9); -} -; - -method -: maybe_outer_attrs maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 7, $1, $2, $4, $5, $6, $7, $8); -} -| maybe_outer_attrs CONST maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 7, $1, $3, $5, $6, $7, $8, $9); -} -| maybe_outer_attrs maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 8, $1, $2, $4, $6, $7, $8, $9, $10); -} -; - -impl_method -: attrs_and_vis maybe_default maybe_unsafe FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 8, $1, $2, $3, $5, $6, $7, $8, $9); -} -| attrs_and_vis maybe_default CONST maybe_unsafe FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 8, $1, $2, $4, $6, $7, $8, $9, $10); -} -| attrs_and_vis maybe_default maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 9, $1, $2, $3, $5, $7, $8, $9, $10, $11); -} -; - -// There are two forms of impl: -// -// impl (<...>)? TY { ... } -// impl (<...>)? TRAIT for TY { ... } -// -// Unfortunately since TY can begin with '<' itself -- as part of a -// TyQualifiedPath type -- there's an s/r conflict when we see '<' after IMPL: -// should we reduce one of the early rules of TY (such as maybe_once) -// or shall we continue shifting into the generic_params list for the -// impl? -// -// The production parser disambiguates a different case here by -// permitting / requiring the user to provide parens around types when -// they are ambiguous with traits. We do the same here, regrettably, -// by splitting ty into ty and ty_prim. -item_impl -: maybe_default_maybe_unsafe IMPL generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' -{ - $$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8); -} -| maybe_default_maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' -{ - $$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10); -} -| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' -{ - $$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10); -} -| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' -{ - $$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11); -} -| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}' -{ - $$ = mk_node("ItemImplDefault", 3, $1, $3, $4); -} -| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}' -{ - $$ = mk_node("ItemImplDefaultNeg", 3, $1, $3, $4); -} -; - -maybe_impl_items -: impl_items -| %empty { $$ = mk_none(); } -; - -impl_items -: impl_item { $$ = mk_node("ImplItems", 1, $1); } -| impl_item impl_items { $$ = ext_node($1, 1, $2); } -; - -impl_item -: impl_method -| attrs_and_vis item_macro { $$ = mk_node("ImplMacroItem", 2, $1, $2); } -| impl_const -| impl_type -; - -maybe_default -: DEFAULT { $$ = mk_atom("Default"); } -| %empty { $$ = mk_none(); } -; - -impl_const -: attrs_and_vis maybe_default item_const { $$ = mk_node("ImplConst", 3, $1, $2, $3); } -; - -impl_type -: attrs_and_vis maybe_default TYPE ident generic_params '=' ty_sum ';' { $$ = mk_node("ImplType", 5, $1, $2, $4, $5, $7); } -; - -item_fn -: FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("ItemFn", 5, $2, $3, $4, $5, $6); -} -| CONST FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("ItemFn", 5, $3, $4, $5, $6, $7); -} -; - -item_unsafe_fn -: UNSAFE FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("ItemUnsafeFn", 5, $3, $4, $5, $6, $7); -} -| CONST UNSAFE FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("ItemUnsafeFn", 5, $4, $5, $6, $7, $8); -} -| UNSAFE EXTERN maybe_abi FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("ItemUnsafeFn", 6, $3, $5, $6, $7, $8, $9); -} -; - -fn_decl -: fn_params ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); } -; - -fn_decl_with_self -: fn_params_with_self ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); } -; - -fn_decl_with_self_allow_anon_params -: fn_anon_params_with_self ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); } -; - -fn_params -: '(' maybe_params ')' { $$ = $2; } -; - -fn_anon_params -: '(' anon_param anon_params_allow_variadic_tail ')' { $$ = ext_node($2, 1, $3); } -| '(' ')' { $$ = mk_none(); } -; - -fn_params_with_self -: '(' maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node("SelfLower", 3, $2, $4, $5); } -| '(' '&' maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node("SelfRegion", 3, $3, $5, $6); } -| '(' '&' lifetime maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node("SelfRegion", 4, $3, $4, $6, $7); } -| '(' maybe_params ')' { $$ = mk_node("SelfStatic", 1, $2); } -; - -fn_anon_params_with_self -: '(' maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node("SelfLower", 3, $2, $4, $5); } -| '(' '&' maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node("SelfRegion", 3, $3, $5, $6); } -| '(' '&' lifetime maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node("SelfRegion", 4, $3, $4, $6, $7); } -| '(' maybe_anon_params ')' { $$ = mk_node("SelfStatic", 1, $2); } -; - -maybe_params -: params -| params ',' -| %empty { $$ = mk_none(); } -; - -params -: param { $$ = mk_node("Args", 1, $1); } -| params ',' param { $$ = ext_node($1, 1, $3); } -; - -param -: pat ':' ty_sum { $$ = mk_node("Arg", 2, $1, $3); } -; - -inferrable_params -: inferrable_param { $$ = mk_node("InferrableParams", 1, $1); } -| inferrable_params ',' inferrable_param { $$ = ext_node($1, 1, $3); } -; - -inferrable_param -: pat maybe_ty_ascription { $$ = mk_node("InferrableParam", 2, $1, $2); } -; - -maybe_comma_params -: ',' { $$ = mk_none(); } -| ',' params { $$ = $2; } -| ',' params ',' { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -maybe_comma_anon_params -: ',' { $$ = mk_none(); } -| ',' anon_params { $$ = $2; } -| ',' anon_params ',' { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -maybe_anon_params -: anon_params -| anon_params ',' -| %empty { $$ = mk_none(); } -; - -anon_params -: anon_param { $$ = mk_node("Args", 1, $1); } -| anon_params ',' anon_param { $$ = ext_node($1, 1, $3); } -; - -// anon means it's allowed to be anonymous (type-only), but it can -// still have a name -anon_param -: named_arg ':' ty { $$ = mk_node("Arg", 2, $1, $3); } -| ty -; - -anon_params_allow_variadic_tail -: ',' DOTDOTDOT { $$ = mk_none(); } -| ',' anon_param anon_params_allow_variadic_tail { $$ = mk_node("Args", 2, $2, $3); } -| %empty { $$ = mk_none(); } -; - -named_arg -: ident -| UNDERSCORE { $$ = mk_atom("PatWild"); } -| '&' ident { $$ = $2; } -| '&' UNDERSCORE { $$ = mk_atom("PatWild"); } -| ANDAND ident { $$ = $2; } -| ANDAND UNDERSCORE { $$ = mk_atom("PatWild"); } -| MUT ident { $$ = $2; } -; - -ret_ty -: RARROW '!' { $$ = mk_none(); } -| RARROW ty { $$ = mk_node("ret-ty", 1, $2); } -| %prec IDENT %empty { $$ = mk_none(); } -; - -generic_params -: '<' '>' { $$ = mk_node("Generics", 2, mk_none(), mk_none()); } -| '<' lifetimes '>' { $$ = mk_node("Generics", 2, $2, mk_none()); } -| '<' lifetimes ',' '>' { $$ = mk_node("Generics", 2, $2, mk_none()); } -| '<' lifetimes SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, mk_none()); } -| '<' lifetimes ',' SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, mk_none()); } -| '<' lifetimes ',' ty_params '>' { $$ = mk_node("Generics", 2, $2, $4); } -| '<' lifetimes ',' ty_params ',' '>' { $$ = mk_node("Generics", 2, $2, $4); } -| '<' lifetimes ',' ty_params SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, $4); } -| '<' lifetimes ',' ty_params ',' SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, $4); } -| '<' ty_params '>' { $$ = mk_node("Generics", 2, mk_none(), $2); } -| '<' ty_params ',' '>' { $$ = mk_node("Generics", 2, mk_none(), $2); } -| '<' ty_params SHR { push_back('>'); $$ = mk_node("Generics", 2, mk_none(), $2); } -| '<' ty_params ',' SHR { push_back('>'); $$ = mk_node("Generics", 2, mk_none(), $2); } -| %empty { $$ = mk_none(); } -; - -maybe_where_clause -: %empty { $$ = mk_none(); } -| where_clause -; - -where_clause -: WHERE where_predicates { $$ = mk_node("WhereClause", 1, $2); } -| WHERE where_predicates ',' { $$ = mk_node("WhereClause", 1, $2); } -; - -where_predicates -: where_predicate { $$ = mk_node("WherePredicates", 1, $1); } -| where_predicates ',' where_predicate { $$ = ext_node($1, 1, $3); } -; - -where_predicate -: maybe_for_lifetimes lifetime ':' bounds { $$ = mk_node("WherePredicate", 3, $1, $2, $4); } -| maybe_for_lifetimes ty ':' ty_param_bounds { $$ = mk_node("WherePredicate", 3, $1, $2, $4); } -; - -maybe_for_lifetimes -: FOR '<' lifetimes '>' { $$ = mk_none(); } -| %prec FORTYPE %empty { $$ = mk_none(); } - -ty_params -: ty_param { $$ = mk_node("TyParams", 1, $1); } -| ty_params ',' ty_param { $$ = ext_node($1, 1, $3); } -; - -// A path with no type parameters; e.g. `foo::bar::Baz` -// -// These show up in 'use' view-items, because these are processed -// without respect to types. -path_no_types_allowed -: ident { $$ = mk_node("ViewPath", 1, $1); } -| MOD_SEP ident { $$ = mk_node("ViewPath", 1, $2); } -| SELF { $$ = mk_node("ViewPath", 1, mk_atom("Self")); } -| MOD_SEP SELF { $$ = mk_node("ViewPath", 1, mk_atom("Self")); } -| SUPER { $$ = mk_node("ViewPath", 1, mk_atom("Super")); } -| MOD_SEP SUPER { $$ = mk_node("ViewPath", 1, mk_atom("Super")); } -| path_no_types_allowed MOD_SEP ident { $$ = ext_node($1, 1, $3); } -; - -// A path with a lifetime and type parameters, with no double colons -// before the type parameters; e.g. `foo::bar<'a>::Baz` -// -// These show up in "trait references", the components of -// type-parameter bounds lists, as well as in the prefix of the -// path_generic_args_and_bounds rule, which is the full form of a -// named typed expression. -// -// They do not have (nor need) an extra '::' before '<' because -// unlike in expr context, there are no "less-than" type exprs to -// be ambiguous with. -path_generic_args_without_colons -: %prec IDENT - ident { $$ = mk_node("components", 1, $1); } -| %prec IDENT - ident generic_args { $$ = mk_node("components", 2, $1, $2); } -| %prec IDENT - ident '(' maybe_ty_sums ')' ret_ty { $$ = mk_node("components", 2, $1, $3); } -| %prec IDENT - path_generic_args_without_colons MOD_SEP ident { $$ = ext_node($1, 1, $3); } -| %prec IDENT - path_generic_args_without_colons MOD_SEP ident generic_args { $$ = ext_node($1, 2, $3, $4); } -| %prec IDENT - path_generic_args_without_colons MOD_SEP ident '(' maybe_ty_sums ')' ret_ty { $$ = ext_node($1, 2, $3, $5); } -; - -generic_args -: '<' generic_values '>' { $$ = $2; } -| '<' generic_values SHR { push_back('>'); $$ = $2; } -| '<' generic_values GE { push_back('='); $$ = $2; } -| '<' generic_values SHREQ { push_back('>'); push_back('='); $$ = $2; } -// If generic_args starts with "<<", the first arg must be a -// TyQualifiedPath because that's the only type that can start with a -// '<'. This rule parses that as the first ty_sum and then continues -// with the rest of generic_values. -| SHL ty_qualified_path_and_generic_values '>' { $$ = $2; } -| SHL ty_qualified_path_and_generic_values SHR { push_back('>'); $$ = $2; } -| SHL ty_qualified_path_and_generic_values GE { push_back('='); $$ = $2; } -| SHL ty_qualified_path_and_generic_values SHREQ { push_back('>'); push_back('='); $$ = $2; } -; - -generic_values -: maybe_ty_sums_and_or_bindings { $$ = mk_node("GenericValues", 1, $1); } -; - -maybe_ty_sums_and_or_bindings -: ty_sums -| ty_sums ',' -| ty_sums ',' bindings { $$ = mk_node("TySumsAndBindings", 2, $1, $3); } -| bindings -| bindings ',' -| %empty { $$ = mk_none(); } -; - -maybe_bindings -: ',' bindings { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -//////////////////////////////////////////////////////////////////////// -// Part 2: Patterns -//////////////////////////////////////////////////////////////////////// - -pat -: UNDERSCORE { $$ = mk_atom("PatWild"); } -| '&' pat { $$ = mk_node("PatRegion", 1, $2); } -| '&' MUT pat { $$ = mk_node("PatRegion", 1, $3); } -| ANDAND pat { $$ = mk_node("PatRegion", 1, mk_node("PatRegion", 1, $2)); } -| '(' ')' { $$ = mk_atom("PatUnit"); } -| '(' pat_tup ')' { $$ = mk_node("PatTup", 1, $2); } -| '[' pat_vec ']' { $$ = mk_node("PatVec", 1, $2); } -| lit_or_path -| lit_or_path DOTDOTDOT lit_or_path { $$ = mk_node("PatRange", 2, $1, $3); } -| path_expr '{' pat_struct '}' { $$ = mk_node("PatStruct", 2, $1, $3); } -| path_expr '(' ')' { $$ = mk_node("PatEnum", 2, $1, mk_none()); } -| path_expr '(' pat_tup ')' { $$ = mk_node("PatEnum", 2, $1, $3); } -| path_expr '!' maybe_ident delimited_token_trees { $$ = mk_node("PatMac", 3, $1, $3, $4); } -| binding_mode ident { $$ = mk_node("PatIdent", 2, $1, $2); } -| ident '@' pat { $$ = mk_node("PatIdent", 3, mk_node("BindByValue", 1, mk_atom("MutImmutable")), $1, $3); } -| binding_mode ident '@' pat { $$ = mk_node("PatIdent", 3, $1, $2, $4); } -| BOX pat { $$ = mk_node("PatUniq", 1, $2); } -| '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node("PatQualifiedPath", 3, $2, $3, $6); } -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident -{ - $$ = mk_node("PatQualifiedPath", 3, mk_node("PatQualifiedPath", 3, $2, $3, $6), $7, $10); -} -; - -pats_or -: pat { $$ = mk_node("Pats", 1, $1); } -| pats_or '|' pat { $$ = ext_node($1, 1, $3); } -; - -binding_mode -: REF { $$ = mk_node("BindByRef", 1, mk_atom("MutImmutable")); } -| REF MUT { $$ = mk_node("BindByRef", 1, mk_atom("MutMutable")); } -| MUT { $$ = mk_node("BindByValue", 1, mk_atom("MutMutable")); } -; - -lit_or_path -: path_expr { $$ = mk_node("PatLit", 1, $1); } -| lit { $$ = mk_node("PatLit", 1, $1); } -| '-' lit { $$ = mk_node("PatLit", 1, $2); } -; - -pat_field -: ident { $$ = mk_node("PatField", 1, $1); } -| binding_mode ident { $$ = mk_node("PatField", 2, $1, $2); } -| BOX ident { $$ = mk_node("PatField", 2, mk_atom("box"), $2); } -| BOX binding_mode ident { $$ = mk_node("PatField", 3, mk_atom("box"), $2, $3); } -| ident ':' pat { $$ = mk_node("PatField", 2, $1, $3); } -| binding_mode ident ':' pat { $$ = mk_node("PatField", 3, $1, $2, $4); } -| LIT_INTEGER ':' pat { $$ = mk_node("PatField", 2, mk_atom(yytext), $3); } -; - -pat_fields -: pat_field { $$ = mk_node("PatFields", 1, $1); } -| pat_fields ',' pat_field { $$ = ext_node($1, 1, $3); } -; - -pat_struct -: pat_fields { $$ = mk_node("PatStruct", 2, $1, mk_atom("false")); } -| pat_fields ',' { $$ = mk_node("PatStruct", 2, $1, mk_atom("false")); } -| pat_fields ',' DOTDOT { $$ = mk_node("PatStruct", 2, $1, mk_atom("true")); } -| DOTDOT { $$ = mk_node("PatStruct", 1, mk_atom("true")); } -| %empty { $$ = mk_node("PatStruct", 1, mk_none()); } -; - -pat_tup -: pat_tup_elts { $$ = mk_node("PatTup", 2, $1, mk_none()); } -| pat_tup_elts ',' { $$ = mk_node("PatTup", 2, $1, mk_none()); } -| pat_tup_elts DOTDOT { $$ = mk_node("PatTup", 2, $1, mk_none()); } -| pat_tup_elts ',' DOTDOT { $$ = mk_node("PatTup", 2, $1, mk_none()); } -| pat_tup_elts DOTDOT ',' pat_tup_elts { $$ = mk_node("PatTup", 2, $1, $4); } -| pat_tup_elts DOTDOT ',' pat_tup_elts ',' { $$ = mk_node("PatTup", 2, $1, $4); } -| pat_tup_elts ',' DOTDOT ',' pat_tup_elts { $$ = mk_node("PatTup", 2, $1, $5); } -| pat_tup_elts ',' DOTDOT ',' pat_tup_elts ',' { $$ = mk_node("PatTup", 2, $1, $5); } -| DOTDOT ',' pat_tup_elts { $$ = mk_node("PatTup", 2, mk_none(), $3); } -| DOTDOT ',' pat_tup_elts ',' { $$ = mk_node("PatTup", 2, mk_none(), $3); } -| DOTDOT { $$ = mk_node("PatTup", 2, mk_none(), mk_none()); } -; - -pat_tup_elts -: pat { $$ = mk_node("PatTupElts", 1, $1); } -| pat_tup_elts ',' pat { $$ = ext_node($1, 1, $3); } -; - -pat_vec -: pat_vec_elts { $$ = mk_node("PatVec", 2, $1, mk_none()); } -| pat_vec_elts ',' { $$ = mk_node("PatVec", 2, $1, mk_none()); } -| pat_vec_elts DOTDOT { $$ = mk_node("PatVec", 2, $1, mk_none()); } -| pat_vec_elts ',' DOTDOT { $$ = mk_node("PatVec", 2, $1, mk_none()); } -| pat_vec_elts DOTDOT ',' pat_vec_elts { $$ = mk_node("PatVec", 2, $1, $4); } -| pat_vec_elts DOTDOT ',' pat_vec_elts ',' { $$ = mk_node("PatVec", 2, $1, $4); } -| pat_vec_elts ',' DOTDOT ',' pat_vec_elts { $$ = mk_node("PatVec", 2, $1, $5); } -| pat_vec_elts ',' DOTDOT ',' pat_vec_elts ',' { $$ = mk_node("PatVec", 2, $1, $5); } -| DOTDOT ',' pat_vec_elts { $$ = mk_node("PatVec", 2, mk_none(), $3); } -| DOTDOT ',' pat_vec_elts ',' { $$ = mk_node("PatVec", 2, mk_none(), $3); } -| DOTDOT { $$ = mk_node("PatVec", 2, mk_none(), mk_none()); } -| %empty { $$ = mk_node("PatVec", 2, mk_none(), mk_none()); } -; - -pat_vec_elts -: pat { $$ = mk_node("PatVecElts", 1, $1); } -| pat_vec_elts ',' pat { $$ = ext_node($1, 1, $3); } -; - -//////////////////////////////////////////////////////////////////////// -// Part 3: Types -//////////////////////////////////////////////////////////////////////// - -ty -: ty_prim -| ty_closure -| '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node("TyQualifiedPath", 3, $2, $3, $6); } -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node("TyQualifiedPath", 3, mk_node("TyQualifiedPath", 3, $2, $3, $6), $7, $10); } -| '(' ty_sums ')' { $$ = mk_node("TyTup", 1, $2); } -| '(' ty_sums ',' ')' { $$ = mk_node("TyTup", 1, $2); } -| '(' ')' { $$ = mk_atom("TyNil"); } -; - -ty_prim -: %prec IDENT path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("false")), $1); } -| %prec IDENT MOD_SEP path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("true")), $2); } -| %prec IDENT SELF MOD_SEP path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("self", 1, mk_atom("true")), $3); } -| %prec IDENT path_generic_args_without_colons '!' maybe_ident delimited_token_trees { $$ = mk_node("TyMacro", 3, $1, $3, $4); } -| %prec IDENT MOD_SEP path_generic_args_without_colons '!' maybe_ident delimited_token_trees { $$ = mk_node("TyMacro", 3, $2, $4, $5); } -| BOX ty { $$ = mk_node("TyBox", 1, $2); } -| '*' maybe_mut_or_const ty { $$ = mk_node("TyPtr", 2, $2, $3); } -| '&' ty { $$ = mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2); } -| '&' MUT ty { $$ = mk_node("TyRptr", 2, mk_atom("MutMutable"), $3); } -| ANDAND ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2)); } -| ANDAND MUT ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutMutable"), $3)); } -| '&' lifetime maybe_mut ty { $$ = mk_node("TyRptr", 3, $2, $3, $4); } -| ANDAND lifetime maybe_mut ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 3, $2, $3, $4)); } -| '[' ty ']' { $$ = mk_node("TyVec", 1, $2); } -| '[' ty ',' DOTDOT expr ']' { $$ = mk_node("TyFixedLengthVec", 2, $2, $5); } -| '[' ty ';' expr ']' { $$ = mk_node("TyFixedLengthVec", 2, $2, $4); } -| TYPEOF '(' expr ')' { $$ = mk_node("TyTypeof", 1, $3); } -| UNDERSCORE { $$ = mk_atom("TyInfer"); } -| ty_bare_fn -| for_in_type -; - -ty_bare_fn -: FN ty_fn_decl { $$ = $2; } -| UNSAFE FN ty_fn_decl { $$ = $3; } -| EXTERN maybe_abi FN ty_fn_decl { $$ = $4; } -| UNSAFE EXTERN maybe_abi FN ty_fn_decl { $$ = $5; } -; - -ty_fn_decl -: generic_params fn_anon_params ret_ty { $$ = mk_node("TyFnDecl", 3, $1, $2, $3); } -; - -ty_closure -: UNSAFE '|' anon_params '|' maybe_bounds ret_ty { $$ = mk_node("TyClosure", 3, $3, $5, $6); } -| '|' anon_params '|' maybe_bounds ret_ty { $$ = mk_node("TyClosure", 3, $2, $4, $5); } -| UNSAFE OROR maybe_bounds ret_ty { $$ = mk_node("TyClosure", 2, $3, $4); } -| OROR maybe_bounds ret_ty { $$ = mk_node("TyClosure", 2, $2, $3); } -; - -for_in_type -: FOR '<' maybe_lifetimes '>' for_in_type_suffix { $$ = mk_node("ForInType", 2, $3, $5); } -; - -for_in_type_suffix -: ty_bare_fn -| trait_ref -| ty_closure -; - -maybe_mut -: MUT { $$ = mk_atom("MutMutable"); } -| %prec MUT %empty { $$ = mk_atom("MutImmutable"); } -; - -maybe_mut_or_const -: MUT { $$ = mk_atom("MutMutable"); } -| CONST { $$ = mk_atom("MutImmutable"); } -| %empty { $$ = mk_atom("MutImmutable"); } -; - -ty_qualified_path_and_generic_values -: ty_qualified_path maybe_bindings -{ - $$ = mk_node("GenericValues", 3, mk_none(), mk_node("TySums", 1, mk_node("TySum", 1, $1)), $2); -} -| ty_qualified_path ',' ty_sums maybe_bindings -{ - $$ = mk_node("GenericValues", 3, mk_none(), mk_node("TySums", 2, $1, $3), $4); -} -; - -ty_qualified_path -: ty_sum AS trait_ref '>' MOD_SEP ident { $$ = mk_node("TyQualifiedPath", 3, $1, $3, $6); } -| ty_sum AS trait_ref '>' MOD_SEP ident '+' ty_param_bounds { $$ = mk_node("TyQualifiedPath", 3, $1, $3, $6); } -; - -maybe_ty_sums -: ty_sums -| ty_sums ',' -| %empty { $$ = mk_none(); } -; - -ty_sums -: ty_sum { $$ = mk_node("TySums", 1, $1); } -| ty_sums ',' ty_sum { $$ = ext_node($1, 1, $3); } -; - -ty_sum -: ty_sum_elt { $$ = mk_node("TySum", 1, $1); } -| ty_sum '+' ty_sum_elt { $$ = ext_node($1, 1, $3); } -; - -ty_sum_elt -: ty -| lifetime -; - -ty_prim_sum -: ty_prim_sum_elt { $$ = mk_node("TySum", 1, $1); } -| ty_prim_sum '+' ty_prim_sum_elt { $$ = ext_node($1, 1, $3); } -; - -ty_prim_sum_elt -: ty_prim -| lifetime -; - -maybe_ty_param_bounds -: ':' ty_param_bounds { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -ty_param_bounds -: boundseq -| %empty { $$ = mk_none(); } -; - -boundseq -: polybound -| boundseq '+' polybound { $$ = ext_node($1, 1, $3); } -; - -polybound -: FOR '<' maybe_lifetimes '>' bound { $$ = mk_node("PolyBound", 2, $3, $5); } -| bound -| '?' FOR '<' maybe_lifetimes '>' bound { $$ = mk_node("PolyBound", 2, $4, $6); } -| '?' bound { $$ = $2; } -; - -bindings -: binding { $$ = mk_node("Bindings", 1, $1); } -| bindings ',' binding { $$ = ext_node($1, 1, $3); } -; - -binding -: ident '=' ty { mk_node("Binding", 2, $1, $3); } -; - -ty_param -: ident maybe_ty_param_bounds maybe_ty_default { $$ = mk_node("TyParam", 3, $1, $2, $3); } -| ident '?' ident maybe_ty_param_bounds maybe_ty_default { $$ = mk_node("TyParam", 4, $1, $3, $4, $5); } -; - -maybe_bounds -: %prec SHIFTPLUS - ':' bounds { $$ = $2; } -| %prec SHIFTPLUS %empty { $$ = mk_none(); } -; - -bounds -: bound { $$ = mk_node("bounds", 1, $1); } -| bounds '+' bound { $$ = ext_node($1, 1, $3); } -; - -bound -: lifetime -| trait_ref -; - -maybe_ltbounds -: %prec SHIFTPLUS - ':' ltbounds { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -ltbounds -: lifetime { $$ = mk_node("ltbounds", 1, $1); } -| ltbounds '+' lifetime { $$ = ext_node($1, 1, $3); } -; - -maybe_ty_default -: '=' ty_sum { $$ = mk_node("TyDefault", 1, $2); } -| %empty { $$ = mk_none(); } -; - -maybe_lifetimes -: lifetimes -| lifetimes ',' -| %empty { $$ = mk_none(); } -; - -lifetimes -: lifetime_and_bounds { $$ = mk_node("Lifetimes", 1, $1); } -| lifetimes ',' lifetime_and_bounds { $$ = ext_node($1, 1, $3); } -; - -lifetime_and_bounds -: LIFETIME maybe_ltbounds { $$ = mk_node("lifetime", 2, mk_atom(yytext), $2); } -| STATIC_LIFETIME { $$ = mk_atom("static_lifetime"); } -; - -lifetime -: LIFETIME { $$ = mk_node("lifetime", 1, mk_atom(yytext)); } -| STATIC_LIFETIME { $$ = mk_atom("static_lifetime"); } -; - -trait_ref -: %prec IDENT path_generic_args_without_colons -| %prec IDENT MOD_SEP path_generic_args_without_colons { $$ = $2; } -; - -//////////////////////////////////////////////////////////////////////// -// Part 4: Blocks, statements, and expressions -//////////////////////////////////////////////////////////////////////// - -inner_attrs_and_block -: '{' maybe_inner_attrs maybe_stmts '}' { $$ = mk_node("ExprBlock", 2, $2, $3); } -; - -block -: '{' maybe_stmts '}' { $$ = mk_node("ExprBlock", 1, $2); } -; - -maybe_stmts -: stmts -| stmts nonblock_expr { $$ = ext_node($1, 1, $2); } -| nonblock_expr -| %empty { $$ = mk_none(); } -; - -// There are two sub-grammars within a "stmts: exprs" derivation -// depending on whether each stmt-expr is a block-expr form; this is to -// handle the "semicolon rule" for stmt sequencing that permits -// writing -// -// if foo { bar } 10 -// -// as a sequence of two stmts (one if-expr stmt, one lit-10-expr -// stmt). Unfortunately by permitting juxtaposition of exprs in -// sequence like that, the non-block expr grammar has to have a -// second limited sub-grammar that excludes the prefix exprs that -// are ambiguous with binops. That is to say: -// -// {10} - 1 -// -// should parse as (progn (progn 10) (- 1)) not (- (progn 10) 1), that -// is to say, two statements rather than one, at least according to -// the mainline rust parser. -// -// So we wind up with a 3-way split in exprs that occur in stmt lists: -// block, nonblock-prefix, and nonblock-nonprefix. -// -// In non-stmts contexts, expr can relax this trichotomy. - -stmts -: stmt { $$ = mk_node("stmts", 1, $1); } -| stmts stmt { $$ = ext_node($1, 1, $2); } -; - -stmt -: maybe_outer_attrs let { $$ = $2; } -| stmt_item -| PUB stmt_item { $$ = $2; } -| outer_attrs stmt_item { $$ = $2; } -| outer_attrs PUB stmt_item { $$ = $3; } -| full_block_expr -| maybe_outer_attrs block { $$ = $2; } -| nonblock_expr ';' -| outer_attrs nonblock_expr ';' { $$ = $2; } -| ';' { $$ = mk_none(); } -; - -maybe_exprs -: exprs -| exprs ',' -| %empty { $$ = mk_none(); } -; - -maybe_expr -: expr -| %empty { $$ = mk_none(); } -; - -exprs -: expr { $$ = mk_node("exprs", 1, $1); } -| exprs ',' expr { $$ = ext_node($1, 1, $3); } -; - -path_expr -: path_generic_args_with_colons -| MOD_SEP path_generic_args_with_colons { $$ = $2; } -| SELF MOD_SEP path_generic_args_with_colons { $$ = mk_node("SelfPath", 1, $3); } -; - -// A path with a lifetime and type parameters with double colons before -// the type parameters; e.g. `foo::bar::<'a>::Baz::` -// -// These show up in expr context, in order to disambiguate from "less-than" -// expressions. -path_generic_args_with_colons -: ident { $$ = mk_node("components", 1, $1); } -| SUPER { $$ = mk_atom("Super"); } -| path_generic_args_with_colons MOD_SEP ident { $$ = ext_node($1, 1, $3); } -| path_generic_args_with_colons MOD_SEP SUPER { $$ = ext_node($1, 1, mk_atom("Super")); } -| path_generic_args_with_colons MOD_SEP generic_args { $$ = ext_node($1, 1, $3); } -; - -// the braces-delimited macro is a block_expr so it doesn't appear here -macro_expr -: path_expr '!' maybe_ident parens_delimited_token_trees { $$ = mk_node("MacroExpr", 3, $1, $3, $4); } -| path_expr '!' maybe_ident brackets_delimited_token_trees { $$ = mk_node("MacroExpr", 3, $1, $3, $4); } -; - -nonblock_expr -: lit { $$ = mk_node("ExprLit", 1, $1); } -| %prec IDENT - path_expr { $$ = mk_node("ExprPath", 1, $1); } -| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } -| macro_expr { $$ = mk_node("ExprMac", 1, $1); } -| path_expr '{' struct_expr_fields '}' { $$ = mk_node("ExprStruct", 2, $1, $3); } -| nonblock_expr '?' { $$ = mk_node("ExprTry", 1, $1); } -| nonblock_expr '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } -| nonblock_expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -| nonblock_expr '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } -| nonblock_expr '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); } -| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); } -| '(' maybe_exprs ')' { $$ = mk_node("ExprParen", 1, $2); } -| CONTINUE { $$ = mk_node("ExprAgain", 0); } -| CONTINUE lifetime { $$ = mk_node("ExprAgain", 1, $2); } -| RETURN { $$ = mk_node("ExprRet", 0); } -| RETURN expr { $$ = mk_node("ExprRet", 1, $2); } -| BREAK { $$ = mk_node("ExprBreak", 0); } -| BREAK lifetime { $$ = mk_node("ExprBreak", 1, $2); } -| YIELD { $$ = mk_node("ExprYield", 0); } -| YIELD expr { $$ = mk_node("ExprYield", 1, $2); } -| nonblock_expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); } -| nonblock_expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); } -| nonblock_expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); } -| nonblock_expr MINUSEQ expr { $$ = mk_node("ExprAssignSub", 2, $1, $3); } -| nonblock_expr ANDEQ expr { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); } -| nonblock_expr OREQ expr { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); } -| nonblock_expr PLUSEQ expr { $$ = mk_node("ExprAssignAdd", 2, $1, $3); } -| nonblock_expr STAREQ expr { $$ = mk_node("ExprAssignMul", 2, $1, $3); } -| nonblock_expr SLASHEQ expr { $$ = mk_node("ExprAssignDiv", 2, $1, $3); } -| nonblock_expr CARETEQ expr { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); } -| nonblock_expr PERCENTEQ expr { $$ = mk_node("ExprAssignRem", 2, $1, $3); } -| nonblock_expr OROR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); } -| nonblock_expr ANDAND expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); } -| nonblock_expr EQEQ expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); } -| nonblock_expr NE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); } -| nonblock_expr '<' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); } -| nonblock_expr '>' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); } -| nonblock_expr LE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); } -| nonblock_expr GE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); } -| nonblock_expr '|' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); } -| nonblock_expr '^' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); } -| nonblock_expr '&' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); } -| nonblock_expr SHL expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); } -| nonblock_expr SHR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); } -| nonblock_expr '+' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); } -| nonblock_expr '-' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); } -| nonblock_expr '*' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); } -| nonblock_expr '/' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); } -| nonblock_expr '%' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); } -| nonblock_expr DOTDOT { $$ = mk_node("ExprRange", 2, $1, mk_none()); } -| nonblock_expr DOTDOT expr { $$ = mk_node("ExprRange", 2, $1, $3); } -| DOTDOT expr { $$ = mk_node("ExprRange", 2, mk_none(), $2); } -| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } -| nonblock_expr AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| nonblock_expr ':' ty { $$ = mk_node("ExprTypeAscr", 2, $1, $3); } -| BOX expr { $$ = mk_node("ExprBox", 1, $2); } -| expr_qualified_path -| nonblock_prefix_expr -; - -expr -: lit { $$ = mk_node("ExprLit", 1, $1); } -| %prec IDENT - path_expr { $$ = mk_node("ExprPath", 1, $1); } -| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } -| macro_expr { $$ = mk_node("ExprMac", 1, $1); } -| path_expr '{' struct_expr_fields '}' { $$ = mk_node("ExprStruct", 2, $1, $3); } -| expr '?' { $$ = mk_node("ExprTry", 1, $1); } -| expr '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } -| expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -| expr '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } -| expr '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); } -| '(' maybe_exprs ')' { $$ = mk_node("ExprParen", 1, $2); } -| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); } -| CONTINUE { $$ = mk_node("ExprAgain", 0); } -| CONTINUE ident { $$ = mk_node("ExprAgain", 1, $2); } -| RETURN { $$ = mk_node("ExprRet", 0); } -| RETURN expr { $$ = mk_node("ExprRet", 1, $2); } -| BREAK { $$ = mk_node("ExprBreak", 0); } -| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); } -| YIELD { $$ = mk_node("ExprYield", 0); } -| YIELD expr { $$ = mk_node("ExprYield", 1, $2); } -| expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); } -| expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); } -| expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); } -| expr MINUSEQ expr { $$ = mk_node("ExprAssignSub", 2, $1, $3); } -| expr ANDEQ expr { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); } -| expr OREQ expr { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); } -| expr PLUSEQ expr { $$ = mk_node("ExprAssignAdd", 2, $1, $3); } -| expr STAREQ expr { $$ = mk_node("ExprAssignMul", 2, $1, $3); } -| expr SLASHEQ expr { $$ = mk_node("ExprAssignDiv", 2, $1, $3); } -| expr CARETEQ expr { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); } -| expr PERCENTEQ expr { $$ = mk_node("ExprAssignRem", 2, $1, $3); } -| expr OROR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); } -| expr ANDAND expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); } -| expr EQEQ expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); } -| expr NE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); } -| expr '<' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); } -| expr '>' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); } -| expr LE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); } -| expr GE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); } -| expr '|' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); } -| expr '^' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); } -| expr '&' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); } -| expr SHL expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); } -| expr SHR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); } -| expr '+' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); } -| expr '-' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); } -| expr '*' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); } -| expr '/' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); } -| expr '%' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); } -| expr DOTDOT { $$ = mk_node("ExprRange", 2, $1, mk_none()); } -| expr DOTDOT expr { $$ = mk_node("ExprRange", 2, $1, $3); } -| DOTDOT expr { $$ = mk_node("ExprRange", 2, mk_none(), $2); } -| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } -| expr AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| expr ':' ty { $$ = mk_node("ExprTypeAscr", 2, $1, $3); } -| BOX expr { $$ = mk_node("ExprBox", 1, $2); } -| expr_qualified_path -| block_expr -| block -| nonblock_prefix_expr -; - -expr_nostruct -: lit { $$ = mk_node("ExprLit", 1, $1); } -| %prec IDENT - path_expr { $$ = mk_node("ExprPath", 1, $1); } -| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } -| macro_expr { $$ = mk_node("ExprMac", 1, $1); } -| expr_nostruct '?' { $$ = mk_node("ExprTry", 1, $1); } -| expr_nostruct '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } -| expr_nostruct '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -| expr_nostruct '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } -| expr_nostruct '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); } -| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); } -| '(' maybe_exprs ')' { $$ = mk_node("ExprParen", 1, $2); } -| CONTINUE { $$ = mk_node("ExprAgain", 0); } -| CONTINUE ident { $$ = mk_node("ExprAgain", 1, $2); } -| RETURN { $$ = mk_node("ExprRet", 0); } -| RETURN expr { $$ = mk_node("ExprRet", 1, $2); } -| BREAK { $$ = mk_node("ExprBreak", 0); } -| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); } -| YIELD { $$ = mk_node("ExprYield", 0); } -| YIELD expr { $$ = mk_node("ExprYield", 1, $2); } -| expr_nostruct '=' expr_nostruct { $$ = mk_node("ExprAssign", 2, $1, $3); } -| expr_nostruct SHLEQ expr_nostruct { $$ = mk_node("ExprAssignShl", 2, $1, $3); } -| expr_nostruct SHREQ expr_nostruct { $$ = mk_node("ExprAssignShr", 2, $1, $3); } -| expr_nostruct MINUSEQ expr_nostruct { $$ = mk_node("ExprAssignSub", 2, $1, $3); } -| expr_nostruct ANDEQ expr_nostruct { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); } -| expr_nostruct OREQ expr_nostruct { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); } -| expr_nostruct PLUSEQ expr_nostruct { $$ = mk_node("ExprAssignAdd", 2, $1, $3); } -| expr_nostruct STAREQ expr_nostruct { $$ = mk_node("ExprAssignMul", 2, $1, $3); } -| expr_nostruct SLASHEQ expr_nostruct { $$ = mk_node("ExprAssignDiv", 2, $1, $3); } -| expr_nostruct CARETEQ expr_nostruct { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); } -| expr_nostruct PERCENTEQ expr_nostruct { $$ = mk_node("ExprAssignRem", 2, $1, $3); } -| expr_nostruct OROR expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); } -| expr_nostruct ANDAND expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); } -| expr_nostruct EQEQ expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); } -| expr_nostruct NE expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); } -| expr_nostruct '<' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); } -| expr_nostruct '>' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); } -| expr_nostruct LE expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); } -| expr_nostruct GE expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); } -| expr_nostruct '|' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); } -| expr_nostruct '^' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); } -| expr_nostruct '&' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); } -| expr_nostruct SHL expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); } -| expr_nostruct SHR expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); } -| expr_nostruct '+' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); } -| expr_nostruct '-' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); } -| expr_nostruct '*' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); } -| expr_nostruct '/' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); } -| expr_nostruct '%' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); } -| expr_nostruct DOTDOT %prec RANGE { $$ = mk_node("ExprRange", 2, $1, mk_none()); } -| expr_nostruct DOTDOT expr_nostruct { $$ = mk_node("ExprRange", 2, $1, $3); } -| DOTDOT expr_nostruct { $$ = mk_node("ExprRange", 2, mk_none(), $2); } -| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } -| expr_nostruct AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| expr_nostruct ':' ty { $$ = mk_node("ExprTypeAscr", 2, $1, $3); } -| BOX expr { $$ = mk_node("ExprBox", 1, $2); } -| expr_qualified_path -| block_expr -| block -| nonblock_prefix_expr_nostruct -; - -nonblock_prefix_expr_nostruct -: '-' expr_nostruct { $$ = mk_node("ExprUnary", 2, mk_atom("UnNeg"), $2); } -| '!' expr_nostruct { $$ = mk_node("ExprUnary", 2, mk_atom("UnNot"), $2); } -| '*' expr_nostruct { $$ = mk_node("ExprUnary", 2, mk_atom("UnDeref"), $2); } -| '&' maybe_mut expr_nostruct { $$ = mk_node("ExprAddrOf", 2, $2, $3); } -| ANDAND maybe_mut expr_nostruct { $$ = mk_node("ExprAddrOf", 1, mk_node("ExprAddrOf", 2, $2, $3)); } -| lambda_expr_nostruct -| MOVE lambda_expr_nostruct { $$ = $2; } -; - -nonblock_prefix_expr -: '-' expr { $$ = mk_node("ExprUnary", 2, mk_atom("UnNeg"), $2); } -| '!' expr { $$ = mk_node("ExprUnary", 2, mk_atom("UnNot"), $2); } -| '*' expr { $$ = mk_node("ExprUnary", 2, mk_atom("UnDeref"), $2); } -| '&' maybe_mut expr { $$ = mk_node("ExprAddrOf", 2, $2, $3); } -| ANDAND maybe_mut expr { $$ = mk_node("ExprAddrOf", 1, mk_node("ExprAddrOf", 2, $2, $3)); } -| lambda_expr -| MOVE lambda_expr { $$ = $2; } -; - -expr_qualified_path -: '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_qpath_params -{ - $$ = mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7); -} -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident -{ - $$ = mk_node("ExprQualifiedPath", 3, mk_node("ExprQualifiedPath", 3, $2, $3, $6), $7, $10); -} -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident generic_args maybe_as_trait_ref '>' MOD_SEP ident -{ - $$ = mk_node("ExprQualifiedPath", 3, mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7), $8, $11); -} -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident generic_args -{ - $$ = mk_node("ExprQualifiedPath", 4, mk_node("ExprQualifiedPath", 3, $2, $3, $6), $7, $10, $11); -} -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident generic_args maybe_as_trait_ref '>' MOD_SEP ident generic_args -{ - $$ = mk_node("ExprQualifiedPath", 4, mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7), $8, $11, $12); -} - -maybe_qpath_params -: MOD_SEP generic_args { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -maybe_as_trait_ref -: AS trait_ref { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -lambda_expr -: %prec LAMBDA - OROR ret_ty expr { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); } -| %prec LAMBDA - '|' '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, mk_none(), $3, $4); } -| %prec LAMBDA - '|' inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $2, $4, $5); } -| %prec LAMBDA - '|' inferrable_params OROR lambda_expr_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $2, mk_none(), $4); } -; - -lambda_expr_no_first_bar -: %prec LAMBDA - '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); } -| %prec LAMBDA - inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $1, $3, $4); } -| %prec LAMBDA - inferrable_params OROR lambda_expr_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $1, mk_none(), $3); } -; - -lambda_expr_nostruct -: %prec LAMBDA - OROR expr_nostruct { $$ = mk_node("ExprFnBlock", 2, mk_none(), $2); } -| %prec LAMBDA - '|' '|' ret_ty expr_nostruct { $$ = mk_node("ExprFnBlock", 3, mk_none(), $3, $4); } -| %prec LAMBDA - '|' inferrable_params '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, $2, $4); } -| %prec LAMBDA - '|' inferrable_params OROR lambda_expr_nostruct_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $2, mk_none(), $4); } -; - -lambda_expr_nostruct_no_first_bar -: %prec LAMBDA - '|' ret_ty expr_nostruct { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); } -| %prec LAMBDA - inferrable_params '|' ret_ty expr_nostruct { $$ = mk_node("ExprFnBlock", 3, $1, $3, $4); } -| %prec LAMBDA - inferrable_params OROR lambda_expr_nostruct_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $1, mk_none(), $3); } -; - -vec_expr -: maybe_exprs -| exprs ';' expr { $$ = mk_node("VecRepeat", 2, $1, $3); } -; - -struct_expr_fields -: field_inits -| field_inits ',' -| maybe_field_inits default_field_init { $$ = ext_node($1, 1, $2); } -| %empty { $$ = mk_none(); } -; - -maybe_field_inits -: field_inits -| field_inits ',' -| %empty { $$ = mk_none(); } -; - -field_inits -: field_init { $$ = mk_node("FieldInits", 1, $1); } -| field_inits ',' field_init { $$ = ext_node($1, 1, $3); } -; - -field_init -: ident { $$ = mk_node("FieldInit", 1, $1); } -| ident ':' expr { $$ = mk_node("FieldInit", 2, $1, $3); } -| LIT_INTEGER ':' expr { $$ = mk_node("FieldInit", 2, mk_atom(yytext), $3); } -; - -default_field_init -: DOTDOT expr { $$ = mk_node("DefaultFieldInit", 1, $2); } -; - -block_expr -: expr_match -| expr_if -| expr_if_let -| expr_while -| expr_while_let -| expr_loop -| expr_for -| UNSAFE block { $$ = mk_node("UnsafeBlock", 1, $2); } -| path_expr '!' maybe_ident braces_delimited_token_trees { $$ = mk_node("Macro", 3, $1, $3, $4); } -; - -full_block_expr -: block_expr -| block_expr_dot -; - -block_expr_dot -: block_expr '.' path_generic_args_with_colons %prec IDENT { $$ = mk_node("ExprField", 2, $1, $3); } -| block_expr_dot '.' path_generic_args_with_colons %prec IDENT { $$ = mk_node("ExprField", 2, $1, $3); } -| block_expr '.' path_generic_args_with_colons '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 3, $1, $3, $5); } -| block_expr_dot '.' path_generic_args_with_colons '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 3, $1, $3, $5); } -| block_expr '.' path_generic_args_with_colons '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 3, $1, $3, $5); } -| block_expr_dot '.' path_generic_args_with_colons '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 3, $1, $3, $5); } -| block_expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -| block_expr_dot '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -; - -expr_match -: MATCH expr_nostruct '{' '}' { $$ = mk_node("ExprMatch", 1, $2); } -| MATCH expr_nostruct '{' match_clauses '}' { $$ = mk_node("ExprMatch", 2, $2, $4); } -| MATCH expr_nostruct '{' match_clauses nonblock_match_clause '}' { $$ = mk_node("ExprMatch", 2, $2, ext_node($4, 1, $5)); } -| MATCH expr_nostruct '{' nonblock_match_clause '}' { $$ = mk_node("ExprMatch", 2, $2, mk_node("Arms", 1, $4)); } -; - -match_clauses -: match_clause { $$ = mk_node("Arms", 1, $1); } -| match_clauses match_clause { $$ = ext_node($1, 1, $2); } -; - -match_clause -: nonblock_match_clause ',' -| block_match_clause -| block_match_clause ',' -; - -nonblock_match_clause -: maybe_outer_attrs pats_or maybe_guard FAT_ARROW nonblock_expr { $$ = mk_node("ArmNonblock", 4, $1, $2, $3, $5); } -| maybe_outer_attrs pats_or maybe_guard FAT_ARROW block_expr_dot { $$ = mk_node("ArmNonblock", 4, $1, $2, $3, $5); } -; - -block_match_clause -: maybe_outer_attrs pats_or maybe_guard FAT_ARROW block { $$ = mk_node("ArmBlock", 4, $1, $2, $3, $5); } -| maybe_outer_attrs pats_or maybe_guard FAT_ARROW block_expr { $$ = mk_node("ArmBlock", 4, $1, $2, $3, $5); } -; - -maybe_guard -: IF expr_nostruct { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -expr_if -: IF expr_nostruct block { $$ = mk_node("ExprIf", 2, $2, $3); } -| IF expr_nostruct block ELSE block_or_if { $$ = mk_node("ExprIf", 3, $2, $3, $5); } -; - -expr_if_let -: IF LET pat '=' expr_nostruct block { $$ = mk_node("ExprIfLet", 3, $3, $5, $6); } -| IF LET pat '=' expr_nostruct block ELSE block_or_if { $$ = mk_node("ExprIfLet", 4, $3, $5, $6, $8); } -; - -block_or_if -: block -| expr_if -| expr_if_let -; - -expr_while -: maybe_label WHILE expr_nostruct block { $$ = mk_node("ExprWhile", 3, $1, $3, $4); } -; - -expr_while_let -: maybe_label WHILE LET pat '=' expr_nostruct block { $$ = mk_node("ExprWhileLet", 4, $1, $4, $6, $7); } -; - -expr_loop -: maybe_label LOOP block { $$ = mk_node("ExprLoop", 2, $1, $3); } -; - -expr_for -: maybe_label FOR pat IN expr_nostruct block { $$ = mk_node("ExprForLoop", 4, $1, $3, $5, $6); } -; - -maybe_label -: lifetime ':' -| %empty { $$ = mk_none(); } -; - -let -: LET pat maybe_ty_ascription maybe_init_expr ';' { $$ = mk_node("DeclLocal", 3, $2, $3, $4); } -; - -//////////////////////////////////////////////////////////////////////// -// Part 5: Macros and misc. rules -//////////////////////////////////////////////////////////////////////// - -lit -: LIT_BYTE { $$ = mk_node("LitByte", 1, mk_atom(yytext)); } -| LIT_CHAR { $$ = mk_node("LitChar", 1, mk_atom(yytext)); } -| LIT_INTEGER { $$ = mk_node("LitInteger", 1, mk_atom(yytext)); } -| LIT_FLOAT { $$ = mk_node("LitFloat", 1, mk_atom(yytext)); } -| TRUE { $$ = mk_node("LitBool", 1, mk_atom(yytext)); } -| FALSE { $$ = mk_node("LitBool", 1, mk_atom(yytext)); } -| str -; - -str -: LIT_STR { $$ = mk_node("LitStr", 1, mk_atom(yytext), mk_atom("CookedStr")); } -| LIT_STR_RAW { $$ = mk_node("LitStr", 1, mk_atom(yytext), mk_atom("RawStr")); } -| LIT_BYTE_STR { $$ = mk_node("LitByteStr", 1, mk_atom(yytext), mk_atom("ByteStr")); } -| LIT_BYTE_STR_RAW { $$ = mk_node("LitByteStr", 1, mk_atom(yytext), mk_atom("RawByteStr")); } -; - -maybe_ident -: %empty { $$ = mk_none(); } -| ident -; - -ident -: IDENT { $$ = mk_node("ident", 1, mk_atom(yytext)); } -// Weak keywords that can be used as identifiers -| CATCH { $$ = mk_node("ident", 1, mk_atom(yytext)); } -| DEFAULT { $$ = mk_node("ident", 1, mk_atom(yytext)); } -| UNION { $$ = mk_node("ident", 1, mk_atom(yytext)); } -; - -unpaired_token -: SHL { $$ = mk_atom(yytext); } -| SHR { $$ = mk_atom(yytext); } -| LE { $$ = mk_atom(yytext); } -| EQEQ { $$ = mk_atom(yytext); } -| NE { $$ = mk_atom(yytext); } -| GE { $$ = mk_atom(yytext); } -| ANDAND { $$ = mk_atom(yytext); } -| OROR { $$ = mk_atom(yytext); } -| LARROW { $$ = mk_atom(yytext); } -| SHLEQ { $$ = mk_atom(yytext); } -| SHREQ { $$ = mk_atom(yytext); } -| MINUSEQ { $$ = mk_atom(yytext); } -| ANDEQ { $$ = mk_atom(yytext); } -| OREQ { $$ = mk_atom(yytext); } -| PLUSEQ { $$ = mk_atom(yytext); } -| STAREQ { $$ = mk_atom(yytext); } -| SLASHEQ { $$ = mk_atom(yytext); } -| CARETEQ { $$ = mk_atom(yytext); } -| PERCENTEQ { $$ = mk_atom(yytext); } -| DOTDOT { $$ = mk_atom(yytext); } -| DOTDOTDOT { $$ = mk_atom(yytext); } -| MOD_SEP { $$ = mk_atom(yytext); } -| RARROW { $$ = mk_atom(yytext); } -| FAT_ARROW { $$ = mk_atom(yytext); } -| LIT_BYTE { $$ = mk_atom(yytext); } -| LIT_CHAR { $$ = mk_atom(yytext); } -| LIT_INTEGER { $$ = mk_atom(yytext); } -| LIT_FLOAT { $$ = mk_atom(yytext); } -| LIT_STR { $$ = mk_atom(yytext); } -| LIT_STR_RAW { $$ = mk_atom(yytext); } -| LIT_BYTE_STR { $$ = mk_atom(yytext); } -| LIT_BYTE_STR_RAW { $$ = mk_atom(yytext); } -| IDENT { $$ = mk_atom(yytext); } -| UNDERSCORE { $$ = mk_atom(yytext); } -| LIFETIME { $$ = mk_atom(yytext); } -| SELF { $$ = mk_atom(yytext); } -| STATIC { $$ = mk_atom(yytext); } -| ABSTRACT { $$ = mk_atom(yytext); } -| ALIGNOF { $$ = mk_atom(yytext); } -| AS { $$ = mk_atom(yytext); } -| BECOME { $$ = mk_atom(yytext); } -| BREAK { $$ = mk_atom(yytext); } -| CATCH { $$ = mk_atom(yytext); } -| CRATE { $$ = mk_atom(yytext); } -| DEFAULT { $$ = mk_atom(yytext); } -| DO { $$ = mk_atom(yytext); } -| ELSE { $$ = mk_atom(yytext); } -| ENUM { $$ = mk_atom(yytext); } -| EXTERN { $$ = mk_atom(yytext); } -| FALSE { $$ = mk_atom(yytext); } -| FINAL { $$ = mk_atom(yytext); } -| FN { $$ = mk_atom(yytext); } -| FOR { $$ = mk_atom(yytext); } -| IF { $$ = mk_atom(yytext); } -| IMPL { $$ = mk_atom(yytext); } -| IN { $$ = mk_atom(yytext); } -| LET { $$ = mk_atom(yytext); } -| LOOP { $$ = mk_atom(yytext); } -| MACRO { $$ = mk_atom(yytext); } -| MATCH { $$ = mk_atom(yytext); } -| MOD { $$ = mk_atom(yytext); } -| MOVE { $$ = mk_atom(yytext); } -| MUT { $$ = mk_atom(yytext); } -| OFFSETOF { $$ = mk_atom(yytext); } -| OVERRIDE { $$ = mk_atom(yytext); } -| PRIV { $$ = mk_atom(yytext); } -| PUB { $$ = mk_atom(yytext); } -| PURE { $$ = mk_atom(yytext); } -| REF { $$ = mk_atom(yytext); } -| RETURN { $$ = mk_atom(yytext); } -| STRUCT { $$ = mk_atom(yytext); } -| SIZEOF { $$ = mk_atom(yytext); } -| SUPER { $$ = mk_atom(yytext); } -| TRUE { $$ = mk_atom(yytext); } -| TRAIT { $$ = mk_atom(yytext); } -| TYPE { $$ = mk_atom(yytext); } -| UNION { $$ = mk_atom(yytext); } -| UNSAFE { $$ = mk_atom(yytext); } -| UNSIZED { $$ = mk_atom(yytext); } -| USE { $$ = mk_atom(yytext); } -| VIRTUAL { $$ = mk_atom(yytext); } -| WHILE { $$ = mk_atom(yytext); } -| YIELD { $$ = mk_atom(yytext); } -| CONTINUE { $$ = mk_atom(yytext); } -| PROC { $$ = mk_atom(yytext); } -| BOX { $$ = mk_atom(yytext); } -| CONST { $$ = mk_atom(yytext); } -| WHERE { $$ = mk_atom(yytext); } -| TYPEOF { $$ = mk_atom(yytext); } -| INNER_DOC_COMMENT { $$ = mk_atom(yytext); } -| OUTER_DOC_COMMENT { $$ = mk_atom(yytext); } -| SHEBANG { $$ = mk_atom(yytext); } -| STATIC_LIFETIME { $$ = mk_atom(yytext); } -| ';' { $$ = mk_atom(yytext); } -| ',' { $$ = mk_atom(yytext); } -| '.' { $$ = mk_atom(yytext); } -| '@' { $$ = mk_atom(yytext); } -| '#' { $$ = mk_atom(yytext); } -| '~' { $$ = mk_atom(yytext); } -| ':' { $$ = mk_atom(yytext); } -| '$' { $$ = mk_atom(yytext); } -| '=' { $$ = mk_atom(yytext); } -| '?' { $$ = mk_atom(yytext); } -| '!' { $$ = mk_atom(yytext); } -| '<' { $$ = mk_atom(yytext); } -| '>' { $$ = mk_atom(yytext); } -| '-' { $$ = mk_atom(yytext); } -| '&' { $$ = mk_atom(yytext); } -| '|' { $$ = mk_atom(yytext); } -| '+' { $$ = mk_atom(yytext); } -| '*' { $$ = mk_atom(yytext); } -| '/' { $$ = mk_atom(yytext); } -| '^' { $$ = mk_atom(yytext); } -| '%' { $$ = mk_atom(yytext); } -; - -token_trees -: %empty { $$ = mk_node("TokenTrees", 0); } -| token_trees token_tree { $$ = ext_node($1, 1, $2); } -; - -token_tree -: delimited_token_trees -| unpaired_token { $$ = mk_node("TTTok", 1, $1); } -; - -delimited_token_trees -: parens_delimited_token_trees -| braces_delimited_token_trees -| brackets_delimited_token_trees -; - -parens_delimited_token_trees -: '(' token_trees ')' -{ - $$ = mk_node("TTDelim", 3, - mk_node("TTTok", 1, mk_atom("(")), - $2, - mk_node("TTTok", 1, mk_atom(")"))); -} -; - -braces_delimited_token_trees -: '{' token_trees '}' -{ - $$ = mk_node("TTDelim", 3, - mk_node("TTTok", 1, mk_atom("{")), - $2, - mk_node("TTTok", 1, mk_atom("}"))); -} -; - -brackets_delimited_token_trees -: '[' token_trees ']' -{ - $$ = mk_node("TTDelim", 3, - mk_node("TTTok", 1, mk_atom("[")), - $2, - mk_node("TTTok", 1, mk_atom("]"))); -} -; diff --git a/src/grammar/raw-string-literal-ambiguity.md b/src/grammar/raw-string-literal-ambiguity.md deleted file mode 100644 index c909f2333148a..0000000000000 --- a/src/grammar/raw-string-literal-ambiguity.md +++ /dev/null @@ -1,64 +0,0 @@ -Rust's lexical grammar is not context-free. Raw string literals are the source -of the problem. Informally, a raw string literal is an `r`, followed by `N` -hashes (where N can be zero), a quote, any characters, then a quote followed -by `N` hashes. Critically, once inside the first pair of quotes, -another quote cannot be followed by `N` consecutive hashes. e.g. -`r###""###"###` is invalid. - -This grammar describes this as best possible: - - R -> 'r' S - S -> '"' B '"' - S -> '#' S '#' - B -> . B - B -> ε - -Where `.` represents any character, and `ε` the empty string. Consider the -string `r#""#"#`. This string is not a valid raw string literal, but can be -accepted as one by the above grammar, using the derivation: - - R : #""#"# - S : ""#" - S : "# - B : # - B : ε - -(Where `T : U` means the rule `T` is applied, and `U` is the remainder of the -string.) The difficulty arises from the fact that it is fundamentally -context-sensitive. In particular, the context needed is the number of hashes. - -To prove that Rust's string literals are not context-free, we will use -the fact that context-free languages are closed under intersection with -regular languages, and the -[pumping lemma for context-free languages](https://en.wikipedia.org/wiki/Pumping_lemma_for_context-free_languages). - -Consider the regular language `R = r#+""#*"#+`. If Rust's raw string literals are -context-free, then their intersection with `R`, `R'`, should also be context-free. -Therefore, to prove that raw string literals are not context-free, -it is sufficient to prove that `R'` is not context-free. - -The language `R'` is `{r#^n""#^m"#^n | m < n}`. - -Assume `R'` *is* context-free. Then `R'` has some pumping length `p > 0` for which -the pumping lemma applies. Consider the following string `s` in `R'`: - -`r#^p""#^{p-1}"#^p` - -e.g. for `p = 2`: `s = r##""#"##` - -Then `s = uvwxy` for some choice of `uvwxy` such that `vx` is non-empty, -`|vwx| < p+1`, and `uv^iwx^iy` is in `R'` for all `i >= 0`. - -Neither `v` nor `x` can contain a `"` or `r`, as the number of these characters -in any string in `R'` is fixed. So `v` and `x` contain only hashes. -Consequently, of the three sequences of hashes, `v` and `x` combined -can only pump two of them. -If we ever choose the central sequence of hashes, then one of the outer sequences -will not grow when we pump, leading to an imbalance between the outer sequences. -Therefore, we must pump both outer sequences of hashes. However, -there are `p+2` characters between these two sequences of hashes, and `|vwx|` must -be less than `p+1`. Therefore we have a contradiction, and `R'` must not be -context-free. - -Since `R'` is not context-free, it follows that the Rust's raw string literals -must not be context-free. diff --git a/src/grammar/testparser.py b/src/grammar/testparser.py deleted file mode 100755 index 4b5a7fb9e10b5..0000000000000 --- a/src/grammar/testparser.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python - -# ignore-tidy-linelength - -import sys - -import os -import subprocess -import argparse - -# usage: testparser.py [-h] [-p PARSER [PARSER ...]] -s SOURCE_DIR - -# Parsers should read from stdin and return exit status 0 for a -# successful parse, and nonzero for an unsuccessful parse - -parser = argparse.ArgumentParser() -parser.add_argument('-p', '--parser', nargs='+') -parser.add_argument('-s', '--source-dir', nargs=1, required=True) -args = parser.parse_args(sys.argv[1:]) - -total = 0 -ok = {} -bad = {} -for parser in args.parser: - ok[parser] = 0 - bad[parser] = [] -devnull = open(os.devnull, 'w') -print("\n") - -for base, dirs, files in os.walk(args.source_dir[0]): - for f in filter(lambda p: p.endswith('.rs'), files): - p = os.path.join(base, f) - parse_fail = 'parse-fail' in p - if sys.version_info.major == 3: - lines = open(p, encoding='utf-8').readlines() - else: - lines = open(p).readlines() - if any('ignore-test' in line or 'ignore-lexer-test' in line for line in lines): - continue - total += 1 - for parser in args.parser: - if subprocess.call(parser, stdin=open(p), stderr=subprocess.STDOUT, stdout=devnull) == 0: - if parse_fail: - bad[parser].append(p) - else: - ok[parser] += 1 - else: - if parse_fail: - ok[parser] += 1 - else: - bad[parser].append(p) - parser_stats = ', '.join(['{}: {}'.format(parser, ok[parser]) for parser in args.parser]) - sys.stdout.write("\033[K\r total: {}, {}, scanned {}" - .format(total, os.path.relpath(parser_stats), os.path.relpath(p))) - -devnull.close() - -print("\n") - -for parser in args.parser: - filename = os.path.basename(parser) + '.bad' - print("writing {} files that did not yield the correct result with {} to {}".format(len(bad[parser]), parser, filename)) - with open(filename, "w") as f: - for p in bad[parser]: - f.write(p) - f.write("\n") diff --git a/src/grammar/tokens.h b/src/grammar/tokens.h deleted file mode 100644 index 297e3dc841e87..0000000000000 --- a/src/grammar/tokens.h +++ /dev/null @@ -1,99 +0,0 @@ -enum Token { - SHL = 257, // Parser generators reserve 0-256 for char literals - SHR, - LE, - EQEQ, - NE, - GE, - ANDAND, - OROR, - SHLEQ, - SHREQ, - MINUSEQ, - ANDEQ, - OREQ, - PLUSEQ, - STAREQ, - SLASHEQ, - CARETEQ, - PERCENTEQ, - DOTDOT, - DOTDOTDOT, - MOD_SEP, - LARROW, - RARROW, - FAT_ARROW, - LIT_BYTE, - LIT_CHAR, - LIT_INTEGER, - LIT_FLOAT, - LIT_STR, - LIT_STR_RAW, - LIT_BYTE_STR, - LIT_BYTE_STR_RAW, - IDENT, - UNDERSCORE, - LIFETIME, - - // keywords - SELF, - STATIC, - ABSTRACT, - ALIGNOF, - AS, - BECOME, - BREAK, - CATCH, - CRATE, - DEFAULT, - DO, - ELSE, - ENUM, - EXTERN, - FALSE, - FINAL, - FN, - FOR, - IF, - IMPL, - IN, - LET, - LOOP, - MACRO, - MATCH, - MOD, - MOVE, - MUT, - OFFSETOF, - OVERRIDE, - PRIV, - PUB, - PURE, - REF, - RETURN, - SIZEOF, - STRUCT, - SUPER, - UNION, - TRUE, - TRAIT, - TYPE, - UNSAFE, - UNSIZED, - USE, - VIRTUAL, - WHILE, - YIELD, - CONTINUE, - PROC, - BOX, - CONST, - WHERE, - TYPEOF, - INNER_DOC_COMMENT, - OUTER_DOC_COMMENT, - - SHEBANG, - SHEBANG_LINE, - STATIC_LIFETIME -}; diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index dc7fd1adc2958..9bc76f51570e1 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -240,7 +240,6 @@ pub(crate) unsafe fn box_free(ptr: Unique) { #[stable(feature = "global_alloc", since = "1.28.0")] #[rustc_allocator_nounwind] pub fn handle_alloc_error(layout: Layout) -> ! { - #[allow(improper_ctypes)] extern "Rust" { #[lang = "oom"] fn oom_impl(layout: Layout) -> !; diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index d5e15b3719c2e..a9c5bce4c25fc 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -329,8 +329,8 @@ impl<'a, B: ?Sized> PartialOrd for Cow<'a, B> #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Cow<'_, B> - where B: fmt::Debug + ToOwned, - ::Owned: fmt::Debug +where + B: fmt::Debug + ToOwned, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { @@ -342,8 +342,8 @@ impl fmt::Debug for Cow<'_, B> #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Cow<'_, B> - where B: fmt::Display + ToOwned, - ::Owned: fmt::Display +where + B: fmt::Display + ToOwned, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { @@ -355,8 +355,8 @@ impl fmt::Display for Cow<'_, B> #[stable(feature = "default", since = "1.11.0")] impl Default for Cow<'_, B> - where B: ToOwned, - ::Owned: Default +where + B: ToOwned, { /// Creates an owned Cow<'a, B> with the default value for the contained owned value. fn default() -> Self { diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index c92db517cad36..9b5d9431ae204 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -29,10 +29,8 @@ //! Nil, //! } //! -//! fn main() { -//! let list: List = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil)))); -//! println!("{:?}", list); -//! } +//! let list: List = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil)))); +//! println!("{:?}", list); //! ``` //! //! This will print `Cons(1, Cons(2, Nil))`. @@ -91,8 +89,10 @@ use core::ops::{ CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Receiver, Generator, GeneratorState }; use core::ptr::{self, NonNull, Unique}; +use core::slice; use core::task::{Context, Poll}; +use crate::alloc::{self, Global, Alloc}; use crate::vec::Vec; use crate::raw_vec::RawVec; use crate::str::from_boxed_utf8_unchecked; @@ -121,6 +121,34 @@ impl Box { box x } + /// Constructs a new box with uninitialized contents. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// let mut five = Box::::new_uninit(); + /// + /// let five = unsafe { + /// // Deferred initialization: + /// five.as_mut_ptr().write(5); + /// + /// five.assume_init() + /// }; + /// + /// assert_eq!(*five, 5) + /// ``` + #[unstable(feature = "new_uninit", issue = "63291")] + pub fn new_uninit() -> Box> { + let layout = alloc::Layout::new::>(); + let ptr = unsafe { + Global.alloc(layout) + .unwrap_or_else(|_| alloc::handle_alloc_error(layout)) + }; + Box(ptr.cast().into()) + } + /// Constructs a new `Pin>`. If `T` does not implement `Unpin`, then /// `x` will be pinned in memory and unable to be moved. #[stable(feature = "pin", since = "1.33.0")] @@ -130,6 +158,111 @@ impl Box { } } +impl Box<[T]> { + /// Constructs a new boxed slice with uninitialized contents. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// let mut values = Box::<[u32]>::new_uninit_slice(3); + /// + /// let values = unsafe { + /// // Deferred initialization: + /// values[0].as_mut_ptr().write(1); + /// values[1].as_mut_ptr().write(2); + /// values[2].as_mut_ptr().write(3); + /// + /// values.assume_init() + /// }; + /// + /// assert_eq!(*values, [1, 2, 3]) + /// ``` + #[unstable(feature = "new_uninit", issue = "63291")] + pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit]> { + let layout = alloc::Layout::array::>(len).unwrap(); + let ptr = unsafe { alloc::alloc(layout) }; + let unique = Unique::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout)); + let slice = unsafe { slice::from_raw_parts_mut(unique.cast().as_ptr(), len) }; + Box(Unique::from(slice)) + } +} + +impl Box> { + /// Converts to `Box`. + /// + /// # Safety + /// + /// As with [`MaybeUninit::assume_init`], + /// it is up to the caller to guarantee that the value + /// really is in an initialized state. + /// Calling this when the content is not yet fully initialized + /// causes immediate undefined behavior. + /// + /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// let mut five = Box::::new_uninit(); + /// + /// let five: Box = unsafe { + /// // Deferred initialization: + /// five.as_mut_ptr().write(5); + /// + /// five.assume_init() + /// }; + /// + /// assert_eq!(*five, 5) + /// ``` + #[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub unsafe fn assume_init(self) -> Box { + Box(Box::into_unique(self).cast()) + } +} + +impl Box<[mem::MaybeUninit]> { + /// Converts to `Box<[T]>`. + /// + /// # Safety + /// + /// As with [`MaybeUninit::assume_init`], + /// it is up to the caller to guarantee that the values + /// really are in an initialized state. + /// Calling this when the content is not yet fully initialized + /// causes immediate undefined behavior. + /// + /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// let mut values = Box::<[u32]>::new_uninit_slice(3); + /// + /// let values = unsafe { + /// // Deferred initialization: + /// values[0].as_mut_ptr().write(1); + /// values[1].as_mut_ptr().write(2); + /// values[2].as_mut_ptr().write(3); + /// + /// values.assume_init() + /// }; + /// + /// assert_eq!(*values, [1, 2, 3]) + /// ``` + #[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub unsafe fn assume_init(self) -> Box<[T]> { + Box(Unique::new_unchecked(Box::into_raw(self) as _)) + } +} + impl Box { /// Constructs a box from a raw pointer. /// @@ -240,14 +373,12 @@ impl Box { /// ``` /// #![feature(box_into_raw_non_null)] /// - /// fn main() { - /// let x = Box::new(5); - /// let ptr = Box::into_raw_non_null(x); + /// let x = Box::new(5); + /// let ptr = Box::into_raw_non_null(x); /// - /// // Clean up the memory by converting the NonNull pointer back - /// // into a Box and letting the Box be dropped. - /// let x = unsafe { Box::from_raw(ptr.as_ptr()) }; - /// } + /// // Clean up the memory by converting the NonNull pointer back + /// // into a Box and letting the Box be dropped. + /// let x = unsafe { Box::from_raw(ptr.as_ptr()) }; /// ``` #[unstable(feature = "box_into_raw_non_null", issue = "47336")] #[inline] @@ -293,23 +424,19 @@ impl Box { /// Simple usage: /// /// ``` - /// fn main() { - /// let x = Box::new(41); - /// let static_ref: &'static mut usize = Box::leak(x); - /// *static_ref += 1; - /// assert_eq!(*static_ref, 42); - /// } + /// let x = Box::new(41); + /// let static_ref: &'static mut usize = Box::leak(x); + /// *static_ref += 1; + /// assert_eq!(*static_ref, 42); /// ``` /// /// Unsized data: /// /// ``` - /// fn main() { - /// let x = vec![1, 2, 3].into_boxed_slice(); - /// let static_ref = Box::leak(x); - /// static_ref[0] = 4; - /// assert_eq!(*static_ref, [4, 2, 3]); - /// } + /// let x = vec![1, 2, 3].into_boxed_slice(); + /// let static_ref = Box::leak(x); + /// static_ref[0] = 4; + /// assert_eq!(*static_ref, [4, 2, 3]); /// ``` #[stable(feature = "box_leak", since = "1.26.0")] #[inline] @@ -645,11 +772,9 @@ impl Box { /// } /// } /// - /// fn main() { - /// let my_string = "Hello World".to_string(); - /// print_if_string(Box::new(my_string)); - /// print_if_string(Box::new(0i8)); - /// } + /// let my_string = "Hello World".to_string(); + /// print_if_string(Box::new(my_string)); + /// print_if_string(Box::new(0i8)); /// ``` pub fn downcast(self) -> Result, Box> { if self.is::() { @@ -679,11 +804,9 @@ impl Box { /// } /// } /// - /// fn main() { - /// let my_string = "Hello World".to_string(); - /// print_if_string(Box::new(my_string)); - /// print_if_string(Box::new(0i8)); - /// } + /// let my_string = "Hello World".to_string(); + /// print_if_string(Box::new(my_string)); + /// print_if_string(Box::new(0i8)); /// ``` pub fn downcast(self) -> Result, Box> { >::downcast(self).map_err(|s| unsafe { @@ -748,11 +871,33 @@ impl Iterator for Box { fn nth(&mut self, n: usize) -> Option { (**self).nth(n) } + fn last(self) -> Option { + BoxIter::last(self) + } +} + +trait BoxIter { + type Item; + fn last(self) -> Option; +} + +impl BoxIter for Box { + type Item = I::Item; + default fn last(self) -> Option { + #[inline] + fn some(_: Option, x: T) -> Option { + Some(x) + } + + self.fold(None, some) + } } +/// Specialization for sized `I`s that uses `I`s implementation of `last()` +/// instead of the default. #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Box { - fn last(self) -> Option where I: Sized { +impl BoxIter for Box { + fn last(self) -> Option { (*self).last() } } diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs index 9f531f5b83c75..3d04f30e7bde5 100644 --- a/src/liballoc/collections/binary_heap.rs +++ b/src/liballoc/collections/binary_heap.rs @@ -1163,6 +1163,9 @@ impl FusedIterator for Drain<'_, T> {} #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] impl From> for BinaryHeap { + /// Converts a `Vec` into a `BinaryHeap`. + /// + /// This conversion happens in-place, and has `O(n)` time complexity. fn from(vec: Vec) -> BinaryHeap { let mut heap = BinaryHeap { data: vec }; heap.rebuild(); diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 1683b8105567f..83fd4485f7321 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -580,7 +580,6 @@ impl BTreeMap { /// # Examples /// /// ``` - /// #![feature(map_get_key_value)] /// use std::collections::BTreeMap; /// /// let mut map = BTreeMap::new(); @@ -588,7 +587,7 @@ impl BTreeMap { /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); /// assert_eq!(map.get_key_value(&2), None); /// ``` - #[unstable(feature = "map_get_key_value", issue = "49347")] + #[stable(feature = "map_get_key_value", since = "1.40.0")] pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> where K: Borrow, Q: Ord @@ -2227,14 +2226,12 @@ impl<'a, K: Ord, V: Default> Entry<'a, K, V> { /// # Examples /// /// ``` - /// # fn main() { /// use std::collections::BTreeMap; /// /// let mut map: BTreeMap<&str, Option> = BTreeMap::new(); /// map.entry("poneyland").or_default(); /// /// assert_eq!(map["poneyland"], None); - /// # } /// ``` pub fn or_default(self) -> &'a mut V { match self { diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index e067096f0c780..0b5a271dbea95 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -106,8 +106,8 @@ impl LeafNode { LeafNode { // As a general policy, we leave fields uninitialized if they can be, as this should // be both slightly faster and easier to track in Valgrind. - keys: uninit_array![_; CAPACITY], - vals: uninit_array![_; CAPACITY], + keys: [MaybeUninit::UNINIT; CAPACITY], + vals: [MaybeUninit::UNINIT; CAPACITY], parent: ptr::null(), parent_idx: MaybeUninit::uninit(), len: 0 @@ -159,7 +159,7 @@ impl InternalNode { unsafe fn new() -> Self { InternalNode { data: LeafNode::new(), - edges: uninit_array![_; 2*B], + edges: [MaybeUninit::UNINIT; 2*B] } } } diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs index d3af910a82c27..8250fc38ccd1c 100644 --- a/src/liballoc/collections/btree/set.rs +++ b/src/liballoc/collections/btree/set.rs @@ -3,7 +3,7 @@ use core::borrow::Borrow; use core::cmp::Ordering::{self, Less, Greater, Equal}; -use core::cmp::max; +use core::cmp::{max, min}; use core::fmt::{self, Debug}; use core::iter::{Peekable, FromIterator, FusedIterator}; use core::ops::{BitOr, BitAnd, BitXor, Sub, RangeBounds}; @@ -122,13 +122,16 @@ pub struct Difference<'a, T: 'a> { } enum DifferenceInner<'a, T: 'a> { Stitch { + // iterate all of self and some of other, spotting matches along the way self_iter: Iter<'a, T>, other_iter: Peekable>, }, Search { + // iterate a small set, look up in the large set self_iter: Iter<'a, T>, other_set: &'a BTreeSet, }, + Iterate(Iter<'a, T>), // simply stream self's elements } #[stable(feature = "collection_debug", since = "1.17.0")] @@ -147,6 +150,7 @@ impl fmt::Debug for Difference<'_, T> { self_iter, other_set: _, } => f.debug_tuple("Difference").field(&self_iter).finish(), + DifferenceInner::Iterate(iter) => f.debug_tuple("Difference").field(&iter).finish(), } } } @@ -187,13 +191,16 @@ pub struct Intersection<'a, T: 'a> { } enum IntersectionInner<'a, T: 'a> { Stitch { - small_iter: Iter<'a, T>, // for size_hint, should be the smaller of the sets - other_iter: Iter<'a, T>, + // iterate similarly sized sets jointly, spotting matches along the way + a: Iter<'a, T>, + b: Iter<'a, T>, }, Search { + // iterate a small set, look up in the large set small_iter: Iter<'a, T>, large_set: &'a BTreeSet, }, + Answer(Option<&'a T>), // return a specific value or emptiness } #[stable(feature = "collection_debug", since = "1.17.0")] @@ -201,17 +208,20 @@ impl fmt::Debug for Intersection<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.inner { IntersectionInner::Stitch { - small_iter, - other_iter, + a, + b, } => f .debug_tuple("Intersection") - .field(&small_iter) - .field(&other_iter) + .field(&a) + .field(&b) .finish(), IntersectionInner::Search { small_iter, large_set: _, } => f.debug_tuple("Intersection").field(&small_iter).finish(), + IntersectionInner::Answer(answer) => { + f.debug_tuple("Intersection").field(&answer).finish() + } } } } @@ -314,24 +324,51 @@ impl BTreeSet { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn difference<'a>(&'a self, other: &'a BTreeSet) -> Difference<'a, T> { - if self.len() > other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { - // Self is bigger than or not much smaller than other set. - // Iterate both sets jointly, spotting matches along the way. - Difference { - inner: DifferenceInner::Stitch { - self_iter: self.iter(), - other_iter: other.iter().peekable(), - }, - } + let (self_min, self_max) = if let (Some(self_min), Some(self_max)) = + (self.iter().next(), self.iter().next_back()) + { + (self_min, self_max) } else { - // Self is much smaller than other set, or both sets are empty. - // Iterate the small set, searching for matches in the large set. - Difference { - inner: DifferenceInner::Search { - self_iter: self.iter(), - other_set: other, - }, - } + return Difference { + inner: DifferenceInner::Iterate(self.iter()), + }; + }; + let (other_min, other_max) = if let (Some(other_min), Some(other_max)) = + (other.iter().next(), other.iter().next_back()) + { + (other_min, other_max) + } else { + return Difference { + inner: DifferenceInner::Iterate(self.iter()), + }; + }; + Difference { + inner: match (self_min.cmp(other_max), self_max.cmp(other_min)) { + (Greater, _) | (_, Less) => DifferenceInner::Iterate(self.iter()), + (Equal, _) => { + let mut self_iter = self.iter(); + self_iter.next(); + DifferenceInner::Iterate(self_iter) + } + (_, Equal) => { + let mut self_iter = self.iter(); + self_iter.next_back(); + DifferenceInner::Iterate(self_iter) + } + _ => { + if self.len() <= other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { + DifferenceInner::Search { + self_iter: self.iter(), + other_set: other, + } + } else { + DifferenceInner::Stitch { + self_iter: self.iter(), + other_iter: other.iter().peekable(), + } + } + } + }, } } @@ -387,29 +424,48 @@ impl BTreeSet { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn intersection<'a>(&'a self, other: &'a BTreeSet) -> Intersection<'a, T> { - let (small, other) = if self.len() <= other.len() { - (self, other) + let (self_min, self_max) = if let (Some(self_min), Some(self_max)) = + (self.iter().next(), self.iter().next_back()) + { + (self_min, self_max) } else { - (other, self) + return Intersection { + inner: IntersectionInner::Answer(None), + }; }; - if small.len() > other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { - // Small set is not much smaller than other set. - // Iterate both sets jointly, spotting matches along the way. - Intersection { - inner: IntersectionInner::Stitch { - small_iter: small.iter(), - other_iter: other.iter(), - }, - } + let (other_min, other_max) = if let (Some(other_min), Some(other_max)) = + (other.iter().next(), other.iter().next_back()) + { + (other_min, other_max) } else { - // Big difference in number of elements, or both sets are empty. - // Iterate the small set, searching for matches in the large set. - Intersection { - inner: IntersectionInner::Search { - small_iter: small.iter(), - large_set: other, - }, - } + return Intersection { + inner: IntersectionInner::Answer(None), + }; + }; + Intersection { + inner: match (self_min.cmp(other_max), self_max.cmp(other_min)) { + (Greater, _) | (_, Less) => IntersectionInner::Answer(None), + (Equal, _) => IntersectionInner::Answer(Some(self_min)), + (_, Equal) => IntersectionInner::Answer(Some(self_max)), + _ => { + if self.len() <= other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { + IntersectionInner::Search { + small_iter: self.iter(), + large_set: other, + } + } else if other.len() <= self.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { + IntersectionInner::Search { + small_iter: other.iter(), + large_set: self, + } + } else { + IntersectionInner::Stitch { + a: self.iter(), + b: other.iter(), + } + } + } + }, } } @@ -544,43 +600,61 @@ impl BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] pub fn is_subset(&self, other: &BTreeSet) -> bool { // Same result as self.difference(other).next().is_none() - // but the 3 paths below are faster (in order: hugely, 20%, 5%). + // but the code below is faster (hugely in some cases). if self.len() > other.len() { - false - } else if self.len() > other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { - // Self is not much smaller than other set. - // Stolen from TreeMap - let mut x = self.iter(); - let mut y = other.iter(); - let mut a = x.next(); - let mut b = y.next(); - while a.is_some() { - if b.is_none() { + return false; + } + let (self_min, self_max) = if let (Some(self_min), Some(self_max)) = + (self.iter().next(), self.iter().next_back()) + { + (self_min, self_max) + } else { + return true; // self is empty + }; + let (other_min, other_max) = if let (Some(other_min), Some(other_max)) = + (other.iter().next(), other.iter().next_back()) + { + (other_min, other_max) + } else { + return false; // other is empty + }; + let mut self_iter = self.iter(); + match self_min.cmp(other_min) { + Less => return false, + Equal => { + self_iter.next(); + } + Greater => (), + } + match self_max.cmp(other_max) { + Greater => return false, + Equal => { + self_iter.next_back(); + } + Less => (), + } + if self_iter.len() <= other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { + // Big difference in number of elements. + for next in self_iter { + if !other.contains(next) { return false; } - - let a1 = a.unwrap(); - let b1 = b.unwrap(); - - match b1.cmp(a1) { - Less => (), - Greater => return false, - Equal => a = x.next(), - } - - b = y.next(); } - true } else { - // Big difference in number of elements, or both sets are empty. - // Iterate the small set, searching for matches in the large set. - for next in self { - if !other.contains(next) { - return false; + // Self is not much smaller than other set. + let mut other_iter = other.iter(); + other_iter.next(); + other_iter.next_back(); + let mut self_next = self_iter.next(); + while let Some(self1) = self_next { + match other_iter.next().map_or(Less, |other1| self1.cmp(other1)) { + Less => return false, + Equal => self_next = self_iter.next(), + Greater => (), } } - true } + true } /// Returns `true` if the set is a superset of another, @@ -1120,6 +1194,7 @@ impl Clone for Difference<'_, T> { self_iter: self_iter.clone(), other_set, }, + DifferenceInner::Iterate(iter) => DifferenceInner::Iterate(iter.clone()), }, } } @@ -1138,7 +1213,7 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { loop { match other_iter .peek() - .map_or(Less, |other_next| Ord::cmp(self_next, other_next)) + .map_or(Less, |other_next| self_next.cmp(other_next)) { Less => return Some(self_next), Equal => { @@ -1160,6 +1235,7 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { return Some(self_next); } }, + DifferenceInner::Iterate(iter) => iter.next(), } } @@ -1167,12 +1243,13 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { let (self_len, other_len) = match &self.inner { DifferenceInner::Stitch { self_iter, - other_iter + other_iter, } => (self_iter.len(), other_iter.len()), DifferenceInner::Search { self_iter, - other_set + other_set, } => (self_iter.len(), other_set.len()), + DifferenceInner::Iterate(iter) => (iter.len(), 0), }; (self_len.saturating_sub(other_len), Some(self_len)) } @@ -1221,11 +1298,11 @@ impl Clone for Intersection<'_, T> { Intersection { inner: match &self.inner { IntersectionInner::Stitch { - small_iter, - other_iter, + a, + b, } => IntersectionInner::Stitch { - small_iter: small_iter.clone(), - other_iter: other_iter.clone(), + a: a.clone(), + b: b.clone(), }, IntersectionInner::Search { small_iter, @@ -1234,6 +1311,7 @@ impl Clone for Intersection<'_, T> { small_iter: small_iter.clone(), large_set, }, + IntersectionInner::Answer(answer) => IntersectionInner::Answer(answer.clone()), }, } } @@ -1245,16 +1323,16 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> { fn next(&mut self) -> Option<&'a T> { match &mut self.inner { IntersectionInner::Stitch { - small_iter, - other_iter, + a, + b, } => { - let mut small_next = small_iter.next()?; - let mut other_next = other_iter.next()?; + let mut a_next = a.next()?; + let mut b_next = b.next()?; loop { - match Ord::cmp(small_next, other_next) { - Less => small_next = small_iter.next()?, - Greater => other_next = other_iter.next()?, - Equal => return Some(small_next), + match a_next.cmp(b_next) { + Less => a_next = a.next()?, + Greater => b_next = b.next()?, + Equal => return Some(a_next), } } } @@ -1267,15 +1345,17 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> { return Some(small_next); } }, + IntersectionInner::Answer(answer) => answer.take(), } } fn size_hint(&self) -> (usize, Option) { - let min_len = match &self.inner { - IntersectionInner::Stitch { small_iter, .. } => small_iter.len(), - IntersectionInner::Search { small_iter, .. } => small_iter.len(), - }; - (0, Some(min_len)) + match &self.inner { + IntersectionInner::Stitch { a, b } => (0, Some(min(a.len(), b.len()))), + IntersectionInner::Search { small_iter, .. } => (0, Some(small_iter.len())), + IntersectionInner::Answer(None) => (0, Some(0)), + IntersectionInner::Answer(Some(_)) => (1, Some(1)), + } } } diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index a14a3fe9994ab..702df250999fb 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -276,7 +276,7 @@ impl LinkedList { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> Self { + pub const fn new() -> Self { LinkedList { head: None, tail: None, @@ -1197,6 +1197,19 @@ impl Clone for LinkedList { fn clone(&self) -> Self { self.iter().cloned().collect() } + + fn clone_from(&mut self, other: &Self) { + let mut iter_other = other.iter(); + if self.len() > other.len() { + self.split_off(other.len()); + } + for (elem, elem_other) in self.iter_mut().zip(&mut iter_other) { + elem.clone_from(elem_other); + } + if !iter_other.is_empty() { + self.extend(iter_other.cloned()); + } + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/collections/linked_list/tests.rs b/src/liballoc/collections/linked_list/tests.rs index 9a6c57d286970..1001f6bba3b82 100644 --- a/src/liballoc/collections/linked_list/tests.rs +++ b/src/liballoc/collections/linked_list/tests.rs @@ -102,14 +102,57 @@ fn test_append() { assert_eq!(m.pop_front(), Some(elt)) } assert_eq!(n.len(), 0); - // let's make sure it's working properly, since we - // did some direct changes to private members + // Let's make sure it's working properly, since we + // did some direct changes to private members. n.push_back(3); assert_eq!(n.len(), 1); assert_eq!(n.pop_front(), Some(3)); check_links(&n); } +#[test] +fn test_clone_from() { + // Short cloned from long + { + let v = vec![1, 2, 3, 4, 5]; + let u = vec![8, 7, 6, 2, 3, 4, 5]; + let mut m = list_from(&v); + let n = list_from(&u); + m.clone_from(&n); + check_links(&m); + assert_eq!(m, n); + for elt in u { + assert_eq!(m.pop_front(), Some(elt)) + } + } + // Long cloned from short + { + let v = vec![1, 2, 3, 4, 5]; + let u = vec![6, 7, 8]; + let mut m = list_from(&v); + let n = list_from(&u); + m.clone_from(&n); + check_links(&m); + assert_eq!(m, n); + for elt in u { + assert_eq!(m.pop_front(), Some(elt)) + } + } + // Two equal length lists + { + let v = vec![1, 2, 3, 4, 5]; + let u = vec![9, 8, 1, 2, 3]; + let mut m = list_from(&v); + let n = list_from(&u); + m.clone_from(&n); + check_links(&m); + assert_eq!(m, n); + for elt in u { + assert_eq!(m.pop_front(), Some(elt)) + } + } +} + #[test] fn test_insert_prev() { let mut m = list_from(&[0, 2, 4, 6, 8]); diff --git a/src/liballoc/collections/mod.rs b/src/liballoc/collections/mod.rs index 5a33ddc14f004..f1f22fe48c58a 100644 --- a/src/liballoc/collections/mod.rs +++ b/src/liballoc/collections/mod.rs @@ -41,32 +41,35 @@ pub use linked_list::LinkedList; #[doc(no_inline)] pub use vec_deque::VecDeque; -use crate::alloc::{AllocErr, LayoutErr}; +use crate::alloc::{Layout, LayoutErr}; -/// Augments `AllocErr` with a CapacityOverflow variant. +/// The error type for `try_reserve` methods. #[derive(Clone, PartialEq, Eq, Debug)] #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -pub enum CollectionAllocErr { +pub enum TryReserveError { /// Error due to the computed capacity exceeding the collection's maximum /// (usually `isize::MAX` bytes). CapacityOverflow, - /// Error due to the allocator (see the `AllocErr` type's docs). - AllocErr, -} -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -impl From for CollectionAllocErr { - #[inline] - fn from(AllocErr: AllocErr) -> Self { - CollectionAllocErr::AllocErr - } + /// The memory allocator returned an error + AllocError { + /// The layout of allocation request that failed + layout: Layout, + + #[doc(hidden)] + #[unstable(feature = "container_error_extra", issue = "0", reason = "\ + Enable exposing the allocator’s custom error value \ + if an associated type is added in the future: \ + https://github.com/rust-lang/wg-allocators/issues/23")] + non_exhaustive: (), + }, } #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -impl From for CollectionAllocErr { +impl From for TryReserveError { #[inline] fn from(_: LayoutErr) -> Self { - CollectionAllocErr::CapacityOverflow + TryReserveError::CapacityOverflow } } diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 9240346ace931..a4a0fbb194dd4 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -18,7 +18,7 @@ use core::ptr::{self, NonNull}; use core::slice; use core::hash::{Hash, Hasher}; -use crate::collections::CollectionAllocErr; +use crate::collections::TryReserveError; use crate::raw_vec::RawVec; use crate::vec::Vec; @@ -576,10 +576,10 @@ impl VecDeque { /// /// ``` /// #![feature(try_reserve)] - /// use std::collections::CollectionAllocErr; + /// use std::collections::TryReserveError; /// use std::collections::VecDeque; /// - /// fn process_data(data: &[u32]) -> Result, CollectionAllocErr> { + /// fn process_data(data: &[u32]) -> Result, TryReserveError> { /// let mut output = VecDeque::new(); /// /// // Pre-reserve the memory, exiting if we can't @@ -595,7 +595,7 @@ impl VecDeque { /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] - pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { self.try_reserve(additional) } @@ -614,10 +614,10 @@ impl VecDeque { /// /// ``` /// #![feature(try_reserve)] - /// use std::collections::CollectionAllocErr; + /// use std::collections::TryReserveError; /// use std::collections::VecDeque; /// - /// fn process_data(data: &[u32]) -> Result, CollectionAllocErr> { + /// fn process_data(data: &[u32]) -> Result, TryReserveError> { /// let mut output = VecDeque::new(); /// /// // Pre-reserve the memory, exiting if we can't @@ -633,12 +633,12 @@ impl VecDeque { /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { let old_cap = self.cap(); let used_cap = self.len() + 1; let new_cap = used_cap.checked_add(additional) .and_then(|needed_cap| needed_cap.checked_next_power_of_two()) - .ok_or(CollectionAllocErr::CapacityOverflow)?; + .ok_or(TryReserveError::CapacityOverflow)?; if new_cap > old_cap { self.buf.try_reserve_exact(used_cap, new_cap - used_cap)?; @@ -1199,6 +1199,31 @@ impl VecDeque { } } + /// Removes the last element from the `VecDeque` and returns it, or `None` if + /// it is empty. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// assert_eq!(buf.pop_back(), None); + /// buf.push_back(1); + /// buf.push_back(3); + /// assert_eq!(buf.pop_back(), Some(3)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn pop_back(&mut self) -> Option { + if self.is_empty() { + None + } else { + self.head = self.wrap_sub(self.head, 1); + let head = self.head; + unsafe { Some(self.buffer_read(head)) } + } + } + /// Prepends an element to the `VecDeque`. /// /// # Examples @@ -1243,38 +1268,13 @@ impl VecDeque { unsafe { self.buffer_write(head, value) } } - /// Removes the last element from the `VecDeque` and returns it, or `None` if - /// it is empty. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// assert_eq!(buf.pop_back(), None); - /// buf.push_back(1); - /// buf.push_back(3); - /// assert_eq!(buf.pop_back(), Some(3)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn pop_back(&mut self) -> Option { - if self.is_empty() { - None - } else { - self.head = self.wrap_sub(self.head, 1); - let head = self.head; - unsafe { Some(self.buffer_read(head)) } - } - } - #[inline] fn is_contiguous(&self) -> bool { self.tail <= self.head } - /// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the - /// last element. + /// Removes an element from anywhere in the `VecDeque` and returns it, + /// replacing it with the first element. /// /// This does not preserve ordering, but is O(1). /// @@ -1288,28 +1288,28 @@ impl VecDeque { /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); - /// assert_eq!(buf.swap_remove_back(0), None); + /// assert_eq!(buf.swap_remove_front(0), None); /// buf.push_back(1); /// buf.push_back(2); /// buf.push_back(3); /// assert_eq!(buf, [1, 2, 3]); /// - /// assert_eq!(buf.swap_remove_back(0), Some(1)); - /// assert_eq!(buf, [3, 2]); + /// assert_eq!(buf.swap_remove_front(2), Some(3)); + /// assert_eq!(buf, [2, 1]); /// ``` #[stable(feature = "deque_extras_15", since = "1.5.0")] - pub fn swap_remove_back(&mut self, index: usize) -> Option { + pub fn swap_remove_front(&mut self, index: usize) -> Option { let length = self.len(); - if length > 0 && index < length - 1 { - self.swap(index, length - 1); + if length > 0 && index < length && index != 0 { + self.swap(index, 0); } else if index >= length { return None; } - self.pop_back() + self.pop_front() } - /// Removes an element from anywhere in the `VecDeque` and returns it, - /// replacing it with the first element. + /// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the + /// last element. /// /// This does not preserve ordering, but is O(1). /// @@ -1323,24 +1323,24 @@ impl VecDeque { /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); - /// assert_eq!(buf.swap_remove_front(0), None); + /// assert_eq!(buf.swap_remove_back(0), None); /// buf.push_back(1); /// buf.push_back(2); /// buf.push_back(3); /// assert_eq!(buf, [1, 2, 3]); /// - /// assert_eq!(buf.swap_remove_front(2), Some(3)); - /// assert_eq!(buf, [2, 1]); + /// assert_eq!(buf.swap_remove_back(0), Some(1)); + /// assert_eq!(buf, [3, 2]); /// ``` #[stable(feature = "deque_extras_15", since = "1.5.0")] - pub fn swap_remove_front(&mut self, index: usize) -> Option { + pub fn swap_remove_back(&mut self, index: usize) -> Option { let length = self.len(); - if length > 0 && index < length && index != 0 { - self.swap(index, 0); + if length > 0 && index < length - 1 { + self.swap(index, length - 1); } else if index >= length { return None; } - self.pop_front() + self.pop_back() } /// Inserts an element at `index` within the `VecDeque`, shifting all elements with indices @@ -1810,7 +1810,7 @@ impl VecDeque { other } - /// Moves all the elements of `other` into `Self`, leaving `other` empty. + /// Moves all the elements of `other` into `self`, leaving `other` empty. /// /// # Panics /// @@ -1847,7 +1847,7 @@ impl VecDeque { /// /// let mut buf = VecDeque::new(); /// buf.extend(1..5); - /// buf.retain(|&x| x%2 == 0); + /// buf.retain(|&x| x % 2 == 0); /// assert_eq!(buf, [2, 4]); /// ``` /// diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index deea74daa52d5..e6b174beaae6d 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -69,7 +69,7 @@ #![warn(missing_debug_implementations)] #![deny(intra_doc_link_resolution_failure)] // rustdoc is run without -D warnings #![allow(explicit_outlives_requirements)] -#![cfg_attr(not(bootstrap), allow(incomplete_features))] +#![allow(incomplete_features)] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(test))] @@ -84,9 +84,10 @@ #![feature(coerce_unsized)] #![feature(const_generic_impls_guard)] #![feature(const_generics)] -#![cfg_attr(not(bootstrap), feature(const_in_array_repeat_expressions))] +#![feature(const_in_array_repeat_expressions)] #![feature(dispatch_from_dyn)] #![feature(core_intrinsics)] +#![feature(container_error_extra)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] #![feature(fmt_internals)] @@ -116,12 +117,11 @@ #![feature(allocator_internals)] #![feature(on_unimplemented)] #![feature(rustc_const_unstable)] -#![feature(const_vec_new)] #![feature(slice_partition_dedup)] -#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_array)] +#![feature(maybe_uninit_extra, maybe_uninit_slice)] #![feature(alloc_layout_extra)] #![feature(try_trait)] -#![feature(mem_take)] +#![feature(associated_type_bounds)] // Allow testing this library @@ -169,3 +169,9 @@ pub mod vec; mod std { pub use core::ops; // RangeFull } + +#[doc(hidden)] +#[unstable(feature = "liballoc_internals", issue = "0", reason = "implementation detail")] +pub mod __export { + pub use core::format_args; +} diff --git a/src/liballoc/macros.rs b/src/liballoc/macros.rs index 250c419c531f8..2f2cdc39c633d 100644 --- a/src/liballoc/macros.rs +++ b/src/liballoc/macros.rs @@ -98,5 +98,5 @@ macro_rules! vec { #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] macro_rules! format { - ($($arg:tt)*) => ($crate::fmt::format(format_args!($($arg)*))) + ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*))) } diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 0abab45e920cc..ee75fc288fee5 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -7,8 +7,8 @@ use core::ops::Drop; use core::ptr::{self, NonNull, Unique}; use core::slice; -use crate::alloc::{Alloc, Layout, Global, handle_alloc_error}; -use crate::collections::CollectionAllocErr::{self, *}; +use crate::alloc::{Alloc, Layout, Global, AllocErr, handle_alloc_error}; +use crate::collections::TryReserveError::{self, *}; use crate::boxed::Box; #[cfg(test)] @@ -19,26 +19,26 @@ mod tests; /// involved. This type is excellent for building your own data structures like Vec and VecDeque. /// In particular: /// -/// * Produces Unique::empty() on zero-sized types -/// * Produces Unique::empty() on zero-length allocations -/// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics) -/// * Guards against 32-bit systems allocating more than isize::MAX bytes -/// * Guards against overflowing your length -/// * Aborts on OOM or calls handle_alloc_error as applicable -/// * Avoids freeing Unique::empty() -/// * Contains a ptr::Unique and thus endows the user with all related benefits +/// * Produces `Unique::empty()` on zero-sized types. +/// * Produces `Unique::empty()` on zero-length allocations. +/// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics). +/// * Guards against 32-bit systems allocating more than isize::MAX bytes. +/// * Guards against overflowing your length. +/// * Aborts on OOM or calls `handle_alloc_error` as applicable. +/// * Avoids freeing `Unique::empty()`. +/// * Contains a `ptr::Unique` and thus endows the user with all related benefits. /// /// This type does not in anyway inspect the memory that it manages. When dropped it *will* -/// free its memory, but it *won't* try to Drop its contents. It is up to the user of RawVec -/// to handle the actual things *stored* inside of a RawVec. +/// free its memory, but it *won't* try to drop its contents. It is up to the user of `RawVec` +/// to handle the actual things *stored* inside of a `RawVec`. /// -/// Note that a RawVec always forces its capacity to be usize::MAX for zero-sized types. -/// This enables you to use capacity growing logic catch the overflows in your length +/// Note that a `RawVec` always forces its capacity to be `usize::MAX` for zero-sized types. +/// This enables you to use capacity-growing logic catch the overflows in your length /// that might occur with zero-sized types. /// -/// However this means that you need to be careful when round-tripping this type -/// with a `Box<[T]>`: `capacity()` won't yield the len. However `with_capacity`, -/// `shrink_to_fit`, and `from_box` will actually set RawVec's private capacity +/// The above means that you need to be careful when round-tripping this type with a +/// `Box<[T]>`, since `capacity()` won't yield the length. However, `with_capacity`, +/// `shrink_to_fit`, and `from_box` will actually set `RawVec`'s private capacity /// field. This allows zero-sized types to not be special-cased by consumers of /// this type. #[allow(missing_debug_implementations)] @@ -49,14 +49,14 @@ pub struct RawVec { } impl RawVec { - /// Like `new` but parameterized over the choice of allocator for - /// the returned RawVec. + /// Like `new`, but parameterized over the choice of allocator for + /// the returned `RawVec`. pub const fn new_in(a: A) -> Self { - // !0 is usize::MAX. This branch should be stripped at compile time. - // FIXME(mark-i-m): use this line when `if`s are allowed in `const` + // `!0` is `usize::MAX`. This branch should be stripped at compile time. + // FIXME(mark-i-m): use this line when `if`s are allowed in `const`: //let cap = if mem::size_of::() == 0 { !0 } else { 0 }; - // Unique::empty() doubles as "unallocated" and "zero-sized allocation" + // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation". RawVec { ptr: Unique::empty(), // FIXME(mark-i-m): use `cap` when ifs are allowed in const @@ -65,15 +65,15 @@ impl RawVec { } } - /// Like `with_capacity` but parameterized over the choice of - /// allocator for the returned RawVec. + /// Like `with_capacity`, but parameterized over the choice of + /// allocator for the returned `RawVec`. #[inline] pub fn with_capacity_in(capacity: usize, a: A) -> Self { RawVec::allocate_in(capacity, false, a) } - /// Like `with_capacity_zeroed` but parameterized over the choice - /// of allocator for the returned RawVec. + /// Like `with_capacity_zeroed`, but parameterized over the choice + /// of allocator for the returned `RawVec`. #[inline] pub fn with_capacity_zeroed_in(capacity: usize, a: A) -> Self { RawVec::allocate_in(capacity, true, a) @@ -86,7 +86,7 @@ impl RawVec { let alloc_size = capacity.checked_mul(elem_size).unwrap_or_else(|| capacity_overflow()); alloc_guard(alloc_size).unwrap_or_else(|_| capacity_overflow()); - // handles ZSTs and `capacity = 0` alike + // Handles ZSTs and `capacity == 0` alike. let ptr = if alloc_size == 0 { NonNull::::dangling() } else { @@ -113,20 +113,45 @@ impl RawVec { } impl RawVec { - /// Creates the biggest possible RawVec (on the system heap) - /// without allocating. If T has positive size, then this makes a - /// RawVec with capacity 0. If T has 0 size, then it makes a - /// RawVec with capacity `usize::MAX`. Useful for implementing + /// HACK(Centril): This exists because `#[unstable]` `const fn`s needn't conform + /// to `min_const_fn` and so they cannot be called in `min_const_fn`s either. + /// + /// If you change `RawVec::new` or dependencies, please take care to not + /// introduce anything that would truly violate `min_const_fn`. + /// + /// NOTE: We could avoid this hack and check conformance with some + /// `#[rustc_force_min_const_fn]` attribute which requires conformance + /// with `min_const_fn` but does not necessarily allow calling it in + /// `stable(...) const fn` / user code not enabling `foo` when + /// `#[rustc_const_unstable(feature = "foo", ..)]` is present. + pub const NEW: Self = Self::new(); + + /// Creates the biggest possible `RawVec` (on the system heap) + /// without allocating. If `T` has positive size, then this makes a + /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a + /// `RawVec` with capacity `usize::MAX`. Useful for implementing /// delayed allocation. pub const fn new() -> Self { - Self::new_in(Global) + // FIXME(Centril): Reintegrate this with `fn new_in` when we can. + + // `!0` is `usize::MAX`. This branch should be stripped at compile time. + // FIXME(mark-i-m): use this line when `if`s are allowed in `const`: + //let cap = if mem::size_of::() == 0 { !0 } else { 0 }; + + // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation". + RawVec { + ptr: Unique::empty(), + // FIXME(mark-i-m): use `cap` when ifs are allowed in const + cap: [0, !0][(mem::size_of::() == 0) as usize], + a: Global, + } } - /// Creates a RawVec (on the system heap) with exactly the + /// Creates a `RawVec` (on the system heap) with exactly the /// capacity and alignment requirements for a `[T; capacity]`. This is - /// equivalent to calling RawVec::new when `capacity` is 0 or T is + /// equivalent to calling `RawVec::new` when `capacity` is `0` or `T` is /// zero-sized. Note that if `T` is zero-sized this means you will - /// *not* get a RawVec with the requested capacity! + /// *not* get a `RawVec` with the requested capacity. /// /// # Panics /// @@ -136,13 +161,13 @@ impl RawVec { /// /// # Aborts /// - /// Aborts on OOM + /// Aborts on OOM. #[inline] pub fn with_capacity(capacity: usize) -> Self { RawVec::allocate_in(capacity, false, Global) } - /// Like `with_capacity` but guarantees the buffer is zeroed. + /// Like `with_capacity`, but guarantees the buffer is zeroed. #[inline] pub fn with_capacity_zeroed(capacity: usize) -> Self { RawVec::allocate_in(capacity, true, Global) @@ -150,13 +175,13 @@ impl RawVec { } impl RawVec { - /// Reconstitutes a RawVec from a pointer, capacity, and allocator. + /// Reconstitutes a `RawVec` from a pointer, capacity, and allocator. /// /// # Undefined Behavior /// - /// The ptr must be allocated (via the given allocator `a`), and with the given capacity. The - /// capacity cannot exceed `isize::MAX` (only a concern on 32-bit systems). - /// If the ptr and capacity come from a RawVec created via `a`, then this is guaranteed. + /// The `ptr` must be allocated (via the given allocator `a`), and with the given `capacity`. + /// The `capacity` cannot exceed `isize::MAX` (only a concern on 32-bit systems). + /// If the `ptr` and `capacity` come from a `RawVec` created via `a`, then this is guaranteed. pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, a: A) -> Self { RawVec { ptr: Unique::new_unchecked(ptr), @@ -167,13 +192,13 @@ impl RawVec { } impl RawVec { - /// Reconstitutes a RawVec from a pointer, capacity. + /// Reconstitutes a `RawVec` from a pointer and capacity. /// /// # Undefined Behavior /// - /// The ptr must be allocated (on the system heap), and with the given capacity. The - /// capacity cannot exceed `isize::MAX` (only a concern on 32-bit systems). - /// If the ptr and capacity come from a RawVec, then this is guaranteed. + /// The `ptr` must be allocated (on the system heap), and with the given `capacity`. + /// The `capacity` cannot exceed `isize::MAX` (only a concern on 32-bit systems). + /// If the `ptr` and `capacity` come from a `RawVec`, then this is guaranteed. pub unsafe fn from_raw_parts(ptr: *mut T, capacity: usize) -> Self { RawVec { ptr: Unique::new_unchecked(ptr), @@ -194,7 +219,7 @@ impl RawVec { impl RawVec { /// Gets a raw pointer to the start of the allocation. Note that this is - /// Unique::empty() if `capacity = 0` or T is zero-sized. In the former case, you must + /// `Unique::empty()` if `capacity == 0` or `T` is zero-sized. In the former case, you must /// be careful. pub fn ptr(&self) -> *mut T { self.ptr.as_ptr() @@ -212,12 +237,12 @@ impl RawVec { } } - /// Returns a shared reference to the allocator backing this RawVec. + /// Returns a shared reference to the allocator backing this `RawVec`. pub fn alloc(&self) -> &A { &self.a } - /// Returns a mutable reference to the allocator backing this RawVec. + /// Returns a mutable reference to the allocator backing this `RawVec`. pub fn alloc_mut(&mut self) -> &mut A { &mut self.a } @@ -247,7 +272,7 @@ impl RawVec { /// /// # Panics /// - /// * Panics if T is zero-sized on the assumption that you managed to exhaust + /// * Panics if `T` is zero-sized on the assumption that you managed to exhaust /// all `usize::MAX` slots in your imaginary buffer. /// * Panics on 32-bit platforms if the requested capacity exceeds /// `isize::MAX` bytes. @@ -290,20 +315,20 @@ impl RawVec { unsafe { let elem_size = mem::size_of::(); - // since we set the capacity to usize::MAX when elem_size is - // 0, getting to here necessarily means the RawVec is overfull. + // Since we set the capacity to `usize::MAX` when `elem_size` is + // 0, getting to here necessarily means the `RawVec` is overfull. assert!(elem_size != 0, "capacity overflow"); let (new_cap, uniq) = match self.current_layout() { Some(cur) => { // Since we guarantee that we never allocate more than - // isize::MAX bytes, `elem_size * self.cap <= isize::MAX` as + // `isize::MAX` bytes, `elem_size * self.cap <= isize::MAX` as // a precondition, so this can't overflow. Additionally the // alignment will never be too large as to "not be // satisfiable", so `Layout::from_size_align` will always // return `Some`. // - // tl;dr; we bypass runtime checks due to dynamic assertions + // TL;DR, we bypass runtime checks due to dynamic assertions // in this module, allowing us to use // `from_size_align_unchecked`. let new_cap = 2 * self.cap; @@ -320,8 +345,8 @@ impl RawVec { } } None => { - // skip to 4 because tiny Vec's are dumb; but not if that - // would cause overflow + // Skip to 4 because tiny `Vec`'s are dumb; but not if that + // would cause overflow. let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 }; match self.a.alloc_array::(new_cap) { Ok(ptr) => (new_cap, ptr.into()), @@ -342,7 +367,7 @@ impl RawVec { /// /// # Panics /// - /// * Panics if T is zero-sized on the assumption that you managed to exhaust + /// * Panics if `T` is zero-sized on the assumption that you managed to exhaust /// all `usize::MAX` slots in your imaginary buffer. /// * Panics on 32-bit platforms if the requested capacity exceeds /// `isize::MAX` bytes. @@ -356,15 +381,15 @@ impl RawVec { None => return false, // nothing to double }; - // since we set the capacity to usize::MAX when elem_size is - // 0, getting to here necessarily means the RawVec is overfull. + // Since we set the capacity to `usize::MAX` when `elem_size` is + // 0, getting to here necessarily means the `RawVec` is overfull. assert!(elem_size != 0, "capacity overflow"); - // Since we guarantee that we never allocate more than isize::MAX + // Since we guarantee that we never allocate more than `isize::MAX` // bytes, `elem_size * self.cap <= isize::MAX` as a precondition, so // this can't overflow. // - // Similarly like with `double` above we can go straight to + // Similarly to with `double` above, we can go straight to // `Layout::from_size_align_unchecked` as we know this won't // overflow and the alignment is sufficiently small. let new_cap = 2 * self.cap; @@ -385,7 +410,7 @@ impl RawVec { /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. pub fn try_reserve_exact(&mut self, used_capacity: usize, needed_extra_capacity: usize) - -> Result<(), CollectionAllocErr> { + -> Result<(), TryReserveError> { self.reserve_internal(used_capacity, needed_extra_capacity, Fallible, Exact) } @@ -409,11 +434,11 @@ impl RawVec { /// /// # Aborts /// - /// Aborts on OOM + /// Aborts on OOM. pub fn reserve_exact(&mut self, used_capacity: usize, needed_extra_capacity: usize) { match self.reserve_internal(used_capacity, needed_extra_capacity, Infallible, Exact) { Err(CapacityOverflow) => capacity_overflow(), - Err(AllocErr) => unreachable!(), + Err(AllocError { .. }) => unreachable!(), Ok(()) => { /* yay */ } } } @@ -422,9 +447,9 @@ impl RawVec { /// needed_extra_capacity` elements. This logic is used in amortized reserve methods. /// Returns `(new_capacity, new_alloc_size)`. fn amortized_new_size(&self, used_capacity: usize, needed_extra_capacity: usize) - -> Result { + -> Result { - // Nothing we can really do about these checks :( + // Nothing we can really do about these checks, sadly. let required_cap = used_capacity.checked_add(needed_extra_capacity) .ok_or(CapacityOverflow)?; // Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`. @@ -435,7 +460,7 @@ impl RawVec { /// The same as `reserve`, but returns on errors instead of panicking or aborting. pub fn try_reserve(&mut self, used_capacity: usize, needed_extra_capacity: usize) - -> Result<(), CollectionAllocErr> { + -> Result<(), TryReserveError> { self.reserve_internal(used_capacity, needed_extra_capacity, Fallible, Amortized) } @@ -459,7 +484,7 @@ impl RawVec { /// /// # Aborts /// - /// Aborts on OOM + /// Aborts on OOM. /// /// # Examples /// @@ -494,7 +519,7 @@ impl RawVec { pub fn reserve(&mut self, used_capacity: usize, needed_extra_capacity: usize) { match self.reserve_internal(used_capacity, needed_extra_capacity, Infallible, Amortized) { Err(CapacityOverflow) => capacity_overflow(), - Err(AllocErr) => unreachable!(), + Err(AllocError { .. }) => unreachable!(), Ok(()) => { /* yay */ } } } @@ -538,7 +563,7 @@ impl RawVec { // Here, `cap < used_capacity + needed_extra_capacity <= new_cap` // (regardless of whether `self.cap - used_capacity` wrapped). - // Therefore we can safely call grow_in_place. + // Therefore, we can safely call `grow_in_place`. let new_layout = Layout::new::().repeat(new_cap).unwrap().0; // FIXME: may crash and burn on over-reserve @@ -576,14 +601,14 @@ impl RawVec { return; } - // This check is my waterloo; it's the only thing Vec wouldn't have to do. + // This check is my waterloo; it's the only thing `Vec` wouldn't have to do. assert!(self.cap >= amount, "Tried to shrink to a larger capacity"); if amount == 0 { // We want to create a new zero-length vector within the - // same allocator. We use ptr::write to avoid an + // same allocator. We use `ptr::write` to avoid an // erroneous attempt to drop the contents, and we use - // ptr::read to sidestep condition against destructuring + // `ptr::read` to sidestep condition against destructuring // types that implement Drop. unsafe { @@ -600,7 +625,7 @@ impl RawVec { // // We also know that `self.cap` is greater than `amount`, and // consequently we don't need runtime checks for creating either - // layout + // layout. let old_size = elem_size * self.cap; let new_size = elem_size * amount; let align = mem::align_of::(); @@ -640,10 +665,8 @@ impl RawVec { needed_extra_capacity: usize, fallibility: Fallibility, strategy: ReserveStrategy, - ) -> Result<(), CollectionAllocErr> { + ) -> Result<(), TryReserveError> { unsafe { - use crate::alloc::AllocErr; - // 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 @@ -655,7 +678,7 @@ impl RawVec { return Ok(()); } - // Nothing we can really do about these checks :( + // Nothing we can really do about these checks, sadly. let new_cap = match strategy { Exact => used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?, Amortized => self.amortized_new_size(used_capacity, needed_extra_capacity)?, @@ -672,12 +695,16 @@ impl RawVec { None => self.a.alloc(new_layout), }; - match (&res, fallibility) { + let ptr = match (res, fallibility) { (Err(AllocErr), Infallible) => handle_alloc_error(new_layout), - _ => {} - } + (Err(AllocErr), Fallible) => return Err(TryReserveError::AllocError { + layout: new_layout, + non_exhaustive: (), + }), + (Ok(ptr), _) => ptr, + }; - self.ptr = res?.cast().into(); + self.ptr = ptr.cast().into(); self.cap = new_cap; Ok(()) @@ -690,7 +717,7 @@ impl RawVec { /// Converts the entire buffer into `Box<[T]>`. /// /// Note that this will correctly reconstitute any `cap` changes - /// that may have been performed. (see description of type for details) + /// that may have been performed. (See description of type for details.) /// /// # Undefined Behavior /// @@ -698,7 +725,7 @@ impl RawVec { /// the rules around uninitialized boxed values are not finalized yet, /// but until they are, it is advisable to avoid them. pub unsafe fn into_box(self) -> Box<[T]> { - // NOTE: not calling `capacity()` here, actually using the real `cap` field! + // NOTE: not calling `capacity()` here; actually using the real `cap` field! let slice = slice::from_raw_parts_mut(self.ptr(), self.cap); let output: Box<[T]> = Box::from_raw(slice); mem::forget(self); @@ -707,7 +734,7 @@ impl RawVec { } impl RawVec { - /// Frees the memory owned by the RawVec *without* trying to Drop its contents. + /// Frees the memory owned by the `RawVec` *without* trying to drop its contents. pub unsafe fn dealloc_buffer(&mut self) { let elem_size = mem::size_of::(); if elem_size != 0 { @@ -719,25 +746,23 @@ impl RawVec { } unsafe impl<#[may_dangle] T, A: Alloc> Drop for RawVec { - /// Frees the memory owned by the RawVec *without* trying to Drop its contents. + /// Frees the memory owned by the `RawVec` *without* trying to drop its contents. fn drop(&mut self) { unsafe { self.dealloc_buffer(); } } } - - // We need to guarantee the following: -// * We don't ever allocate `> isize::MAX` byte-size objects -// * We don't overflow `usize::MAX` and actually allocate too little +// * We don't ever allocate `> isize::MAX` byte-size objects. +// * We don't overflow `usize::MAX` and actually allocate too little. // // On 64-bit we just need to check for overflow since trying to allocate // `> isize::MAX` bytes will surely fail. On 32-bit and 16-bit we need to add // an extra guard for this in case we're running on a platform which can use -// all 4GB in user-space. e.g., PAE or x32 +// all 4GB in user-space, e.g., PAE or x32. #[inline] -fn alloc_guard(alloc_size: usize) -> Result<(), CollectionAllocErr> { +fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { if mem::size_of::() < 8 && alloc_size > core::isize::MAX as usize { Err(CapacityOverflow) } else { @@ -749,5 +774,5 @@ fn alloc_guard(alloc_size: usize) -> Result<(), CollectionAllocErr> { // ensure that the code generation related to these panics is minimal as there's // only one location which panics rather than a bunch throughout the module. fn capacity_overflow() -> ! { - panic!("capacity overflow") + panic!("capacity overflow"); } diff --git a/src/liballoc/raw_vec/tests.rs b/src/liballoc/raw_vec/tests.rs index c389898d1ef04..d35b62fc1ef15 100644 --- a/src/liballoc/raw_vec/tests.rs +++ b/src/liballoc/raw_vec/tests.rs @@ -5,12 +5,12 @@ fn allocator_param() { use crate::alloc::AllocErr; // Writing a test of integration between third-party - // allocators and RawVec is a little tricky because the RawVec + // allocators and `RawVec` is a little tricky because the `RawVec` // API does not expose fallible allocation methods, so we // cannot check what happens when allocator is exhausted // (beyond detecting a panic). // - // Instead, this just checks that the RawVec methods do at + // Instead, this just checks that the `RawVec` methods do at // least go through the Allocator API when it reserves // storage. @@ -44,7 +44,7 @@ fn allocator_param() { fn reserve_does_not_overallocate() { { let mut v: RawVec = RawVec::new(); - // First `reserve` allocates like `reserve_exact` + // First, `reserve` allocates like `reserve_exact`. v.reserve(0, 9); assert_eq!(9, v.capacity()); } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 0c406a92029a7..a28c6d22abb95 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -327,6 +327,37 @@ impl Rc { })) } + /// Constructs a new `Rc` with uninitialized contents. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut five = Rc::::new_uninit(); + /// + /// let five = unsafe { + /// // Deferred initialization: + /// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); + /// + /// five.assume_init() + /// }; + /// + /// assert_eq!(*five, 5) + /// ``` + #[unstable(feature = "new_uninit", issue = "63291")] + pub fn new_uninit() -> Rc> { + unsafe { + Rc::from_ptr(Rc::allocate_for_layout( + Layout::new::(), + |mem| mem as *mut RcBox>, + )) + } + } + /// Constructs a new `Pin>`. If `T` does not implement `Unpin`, then /// `value` will be pinned in memory and unable to be moved. #[stable(feature = "pin", since = "1.33.0")] @@ -377,6 +408,118 @@ impl Rc { } } +impl Rc<[T]> { + /// Constructs a new reference-counted slice with uninitialized contents. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut values = Rc::<[u32]>::new_uninit_slice(3); + /// + /// let values = unsafe { + /// // Deferred initialization: + /// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1); + /// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2); + /// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3); + /// + /// values.assume_init() + /// }; + /// + /// assert_eq!(*values, [1, 2, 3]) + /// ``` + #[unstable(feature = "new_uninit", issue = "63291")] + pub fn new_uninit_slice(len: usize) -> Rc<[mem::MaybeUninit]> { + unsafe { + Rc::from_ptr(Rc::allocate_for_slice(len)) + } + } +} + +impl Rc> { + /// Converts to `Rc`. + /// + /// # Safety + /// + /// As with [`MaybeUninit::assume_init`], + /// it is up to the caller to guarantee that the value + /// really is in an initialized state. + /// Calling this when the content is not yet fully initialized + /// causes immediate undefined behavior. + /// + /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut five = Rc::::new_uninit(); + /// + /// let five = unsafe { + /// // Deferred initialization: + /// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); + /// + /// five.assume_init() + /// }; + /// + /// assert_eq!(*five, 5) + /// ``` + #[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub unsafe fn assume_init(self) -> Rc { + Rc::from_inner(mem::ManuallyDrop::new(self).ptr.cast()) + } +} + +impl Rc<[mem::MaybeUninit]> { + /// Converts to `Rc<[T]>`. + /// + /// # Safety + /// + /// As with [`MaybeUninit::assume_init`], + /// it is up to the caller to guarantee that the value + /// really is in an initialized state. + /// Calling this when the content is not yet fully initialized + /// causes immediate undefined behavior. + /// + /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut values = Rc::<[u32]>::new_uninit_slice(3); + /// + /// let values = unsafe { + /// // Deferred initialization: + /// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1); + /// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2); + /// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3); + /// + /// values.assume_init() + /// }; + /// + /// assert_eq!(*values, [1, 2, 3]) + /// ``` + #[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub unsafe fn assume_init(self) -> Rc<[T]> { + Rc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _) + } +} + impl Rc { /// Consumes the `Rc`, returning the wrapped pointer. /// @@ -424,7 +567,7 @@ impl Rc { /// let x = Rc::from_raw(x_ptr); /// assert_eq!(&*x, "hello"); /// - /// // Further calls to `Rc::from_raw(x_ptr)` would be memory unsafe. + /// // Further calls to `Rc::from_raw(x_ptr)` would be memory-unsafe. /// } /// /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! @@ -560,13 +703,46 @@ impl Rc { pub fn get_mut(this: &mut Self) -> Option<&mut T> { if Rc::is_unique(this) { unsafe { - Some(&mut this.ptr.as_mut().value) + Some(Rc::get_mut_unchecked(this)) } } else { None } } + /// Returns a mutable reference to the inner value, + /// without any check. + /// + /// See also [`get_mut`], which is safe and does appropriate checks. + /// + /// [`get_mut`]: struct.Rc.html#method.get_mut + /// + /// # Safety + /// + /// Any other `Rc` or [`Weak`] pointers to the same value must not be dereferenced + /// for the duration of the returned borrow. + /// This is trivially the case if no such pointers exist, + /// for example immediately after `Rc::new`. + /// + /// # Examples + /// + /// ``` + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut x = Rc::new(String::new()); + /// unsafe { + /// Rc::get_mut_unchecked(&mut x).push_str("foo") + /// } + /// assert_eq!(*x, "foo"); + /// ``` + #[inline] + #[unstable(feature = "get_mut_unchecked", issue = "63292")] + pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { + &mut this.ptr.as_mut().value + } + #[inline] #[stable(feature = "ptr_eq", since = "1.17.0")] /// Returns `true` if the two `Rc`s point to the same value (not @@ -685,11 +861,9 @@ impl Rc { /// } /// } /// - /// fn main() { - /// let my_string = "Hello World".to_string(); - /// print_if_string(Rc::new(my_string)); - /// print_if_string(Rc::new(0i8)); - /// } + /// let my_string = "Hello World".to_string(); + /// print_if_string(Rc::new(my_string)); + /// print_if_string(Rc::new(0i8)); /// ``` pub fn downcast(self) -> Result, Rc> { if (*self).is::() { @@ -704,11 +878,11 @@ impl Rc { impl Rc { /// Allocates an `RcBox` with sufficient space for - /// an unsized value where the value has the layout provided. + /// a possibly-unsized value where the value has the layout provided. /// /// The function `mem_to_rcbox` is called with the data pointer /// and must return back a (potentially fat)-pointer for the `RcBox`. - unsafe fn allocate_for_unsized( + unsafe fn allocate_for_layout( value_layout: Layout, mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcBox ) -> *mut RcBox { @@ -737,7 +911,7 @@ impl Rc { /// Allocates an `RcBox` with sufficient space for an unsized value unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox { // Allocate for the `RcBox` using the given value. - Self::allocate_for_unsized( + Self::allocate_for_layout( Layout::for_value(&*ptr), |mem| set_data_ptr(ptr as *mut T, mem) as *mut RcBox, ) @@ -768,7 +942,7 @@ impl Rc { impl Rc<[T]> { /// Allocates an `RcBox<[T]>` with the given length. unsafe fn allocate_for_slice(len: usize) -> *mut RcBox<[T]> { - Self::allocate_for_unsized( + Self::allocate_for_layout( Layout::array::(len).unwrap(), |mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]>, ) @@ -1656,8 +1830,9 @@ impl Weak { } } - /// Returns `true` if the two `Weak`s point to the same value (not just values - /// that compare as equal). + /// Returns `true` if the two `Weak`s point to the same value (not just + /// values that compare as equal), or if both don't point to any value + /// (because they were created with `Weak::new()`). /// /// # Notes /// @@ -1667,7 +1842,6 @@ impl Weak { /// # Examples /// /// ``` - /// #![feature(weak_ptr_eq)] /// use std::rc::Rc; /// /// let first_rc = Rc::new(5); @@ -1685,7 +1859,6 @@ impl Weak { /// Comparing `Weak::new`. /// /// ``` - /// #![feature(weak_ptr_eq)] /// use std::rc::{Rc, Weak}; /// /// let first = Weak::new(); @@ -1697,7 +1870,7 @@ impl Weak { /// assert!(!first.ptr_eq(&third)); /// ``` #[inline] - #[unstable(feature = "weak_ptr_eq", issue = "55981")] + #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { self.ptr.as_ptr() == other.ptr.as_ptr() } diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 881d499c0745b..08243ef7c519f 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -411,25 +411,16 @@ impl [T] { /// Basic usage: /// /// ``` - /// #![feature(repeat_generic_slice)] - /// - /// fn main() { - /// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]); - /// } + /// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]); /// ``` /// /// A panic upon overflow: /// /// ```should_panic - /// #![feature(repeat_generic_slice)] - /// fn main() { - /// // this will panic at runtime - /// b"0123456789abcdef".repeat(usize::max_value()); - /// } + /// // this will panic at runtime + /// b"0123456789abcdef".repeat(usize::max_value()); /// ``` - #[unstable(feature = "repeat_generic_slice", - reason = "it's on str, why not on slice?", - issue = "48784")] + #[stable(feature = "repeat_generic_slice", since = "1.40.0")] pub fn repeat(&self, n: usize) -> Vec where T: Copy { if n == 0 { return Vec::new(); diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 9a1342c30d502..9231c2d3f1d56 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -500,10 +500,8 @@ impl str { /// A panic upon overflow: /// /// ```should_panic - /// fn main() { - /// // this will panic at runtime - /// "0123456789abcdef".repeat(usize::max_value()); - /// } + /// // this will panic at runtime + /// "0123456789abcdef".repeat(usize::max_value()); /// ``` #[stable(feature = "repeat_str", since = "1.16.0")] pub fn repeat(&self, n: usize) -> String { diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index eca726cd41032..639124e26cc20 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -56,7 +56,7 @@ use core::ptr; use core::str::{pattern::Pattern, lossy}; use crate::borrow::{Cow, ToOwned}; -use crate::collections::CollectionAllocErr; +use crate::collections::TryReserveError; use crate::boxed::Box; use crate::str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; use crate::vec::Vec; @@ -164,10 +164,8 @@ use crate::vec::Vec; /// /// fn example_func(example_arg: A) {} /// -/// fn main() { -/// let example_string = String::from("example_string"); -/// example_func(&example_string); -/// } +/// let example_string = String::from("example_string"); +/// example_func(&example_string); /// ``` /// /// There are two options that would work instead. The first would be to @@ -369,7 +367,6 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_string_new")] pub const fn new() -> String { String { vec: Vec::new() } } @@ -429,7 +426,7 @@ impl String { /// Converts a vector of bytes to a `String`. /// - /// A string slice ([`&str`]) is made of bytes ([`u8`]), and a vector of bytes + /// A string ([`String`]) is made of bytes ([`u8`]), and a vector of bytes /// ([`Vec`]) is made of bytes, so this function converts between the /// two. Not all byte slices are valid `String`s, however: `String` /// requires that it is valid UTF-8. `from_utf8()` checks to ensure that @@ -446,7 +443,7 @@ impl String { /// If you need a [`&str`] instead of a `String`, consider /// [`str::from_utf8`]. /// - /// The inverse of this method is [`as_bytes`]. + /// The inverse of this method is [`into_bytes`]. /// /// # Errors /// @@ -480,11 +477,11 @@ impl String { /// with this error. /// /// [`from_utf8_unchecked`]: struct.String.html#method.from_utf8_unchecked - /// [`&str`]: ../../std/primitive.str.html + /// [`String`]: struct.String.html /// [`u8`]: ../../std/primitive.u8.html /// [`Vec`]: ../../std/vec/struct.Vec.html /// [`str::from_utf8`]: ../../std/str/fn.from_utf8.html - /// [`as_bytes`]: struct.String.html#method.as_bytes + /// [`into_bytes`]: struct.String.html#method.into_bytes /// [`FromUtf8Error`]: struct.FromUtf8Error.html /// [`Err`]: ../../std/result/enum.Result.html#variant.Err #[inline] @@ -937,9 +934,9 @@ impl String { /// /// ``` /// #![feature(try_reserve)] - /// use std::collections::CollectionAllocErr; + /// use std::collections::TryReserveError; /// - /// fn process_data(data: &str) -> Result { + /// fn process_data(data: &str) -> Result { /// let mut output = String::new(); /// /// // Pre-reserve the memory, exiting if we can't @@ -953,7 +950,7 @@ impl String { /// # process_data("rust").expect("why is the test harness OOMing on 4 bytes?"); /// ``` #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.vec.try_reserve(additional) } @@ -975,9 +972,9 @@ impl String { /// /// ``` /// #![feature(try_reserve)] - /// use std::collections::CollectionAllocErr; + /// use std::collections::TryReserveError; /// - /// fn process_data(data: &str) -> Result { + /// fn process_data(data: &str) -> Result { /// let mut output = String::new(); /// /// // Pre-reserve the memory, exiting if we can't @@ -991,7 +988,7 @@ impl String { /// # process_data("rust").expect("why is the test harness OOMing on 4 bytes?"); /// ``` #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] - pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { self.vec.try_reserve_exact(additional) } diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 7d3b2656a7b90..5977e69b7fa0f 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -107,10 +107,6 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; /// // a, b, and foo are all Arcs that point to the same memory location /// ``` /// -/// The [`Arc::clone(&from)`] syntax is the most idiomatic because it conveys more explicitly -/// the meaning of the code. In the example above, this syntax makes it easier to see that -/// this code is creating a new reference rather than copying the whole content of foo. -/// /// ## `Deref` behavior /// /// `Arc` automatically dereferences to `T` (via the [`Deref`][deref] trait), @@ -311,6 +307,37 @@ impl Arc { Self::from_inner(Box::into_raw_non_null(x)) } + /// Constructs a new `Arc` with uninitialized contents. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// #![feature(get_mut_unchecked)] + /// + /// use std::sync::Arc; + /// + /// let mut five = Arc::::new_uninit(); + /// + /// let five = unsafe { + /// // Deferred initialization: + /// Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); + /// + /// five.assume_init() + /// }; + /// + /// assert_eq!(*five, 5) + /// ``` + #[unstable(feature = "new_uninit", issue = "63291")] + pub fn new_uninit() -> Arc> { + unsafe { + Arc::from_ptr(Arc::allocate_for_layout( + Layout::new::(), + |mem| mem as *mut ArcInner>, + )) + } + } + /// Constructs a new `Pin>`. If `T` does not implement `Unpin`, then /// `data` will be pinned in memory and unable to be moved. #[stable(feature = "pin", since = "1.33.0")] @@ -361,6 +388,118 @@ impl Arc { } } +impl Arc<[T]> { + /// Constructs a new reference-counted slice with uninitialized contents. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// #![feature(get_mut_unchecked)] + /// + /// use std::sync::Arc; + /// + /// let mut values = Arc::<[u32]>::new_uninit_slice(3); + /// + /// let values = unsafe { + /// // Deferred initialization: + /// Arc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1); + /// Arc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2); + /// Arc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3); + /// + /// values.assume_init() + /// }; + /// + /// assert_eq!(*values, [1, 2, 3]) + /// ``` + #[unstable(feature = "new_uninit", issue = "63291")] + pub fn new_uninit_slice(len: usize) -> Arc<[mem::MaybeUninit]> { + unsafe { + Arc::from_ptr(Arc::allocate_for_slice(len)) + } + } +} + +impl Arc> { + /// Converts to `Arc`. + /// + /// # Safety + /// + /// As with [`MaybeUninit::assume_init`], + /// it is up to the caller to guarantee that the value + /// really is in an initialized state. + /// Calling this when the content is not yet fully initialized + /// causes immediate undefined behavior. + /// + /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// #![feature(get_mut_unchecked)] + /// + /// use std::sync::Arc; + /// + /// let mut five = Arc::::new_uninit(); + /// + /// let five = unsafe { + /// // Deferred initialization: + /// Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); + /// + /// five.assume_init() + /// }; + /// + /// assert_eq!(*five, 5) + /// ``` + #[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub unsafe fn assume_init(self) -> Arc { + Arc::from_inner(mem::ManuallyDrop::new(self).ptr.cast()) + } +} + +impl Arc<[mem::MaybeUninit]> { + /// Converts to `Arc<[T]>`. + /// + /// # Safety + /// + /// As with [`MaybeUninit::assume_init`], + /// it is up to the caller to guarantee that the value + /// really is in an initialized state. + /// Calling this when the content is not yet fully initialized + /// causes immediate undefined behavior. + /// + /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// #![feature(get_mut_unchecked)] + /// + /// use std::sync::Arc; + /// + /// let mut values = Arc::<[u32]>::new_uninit_slice(3); + /// + /// let values = unsafe { + /// // Deferred initialization: + /// Arc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1); + /// Arc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2); + /// Arc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3); + /// + /// values.assume_init() + /// }; + /// + /// assert_eq!(*values, [1, 2, 3]) + /// ``` + #[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub unsafe fn assume_init(self) -> Arc<[T]> { + Arc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _) + } +} + impl Arc { /// Consumes the `Arc`, returning the wrapped pointer. /// @@ -408,7 +547,7 @@ impl Arc { /// let x = Arc::from_raw(x_ptr); /// assert_eq!(&*x, "hello"); /// - /// // Further calls to `Arc::from_raw(x_ptr)` would be memory unsafe. + /// // Further calls to `Arc::from_raw(x_ptr)` would be memory-unsafe. /// } /// /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! @@ -593,11 +732,11 @@ impl Arc { impl Arc { /// Allocates an `ArcInner` with sufficient space for - /// an unsized value where the value has the layout provided. + /// a possibly-unsized value where the value has the layout provided. /// /// The function `mem_to_arcinner` is called with the data pointer /// and must return back a (potentially fat)-pointer for the `ArcInner`. - unsafe fn allocate_for_unsized( + unsafe fn allocate_for_layout( value_layout: Layout, mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner ) -> *mut ArcInner { @@ -625,7 +764,7 @@ impl Arc { /// Allocates an `ArcInner` with sufficient space for an unsized value. unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner { // Allocate for the `ArcInner` using the given value. - Self::allocate_for_unsized( + Self::allocate_for_layout( Layout::for_value(&*ptr), |mem| set_data_ptr(ptr as *mut T, mem) as *mut ArcInner, ) @@ -656,7 +795,7 @@ impl Arc { impl Arc<[T]> { /// Allocates an `ArcInner<[T]>` with the given length. unsafe fn allocate_for_slice(len: usize) -> *mut ArcInner<[T]> { - Self::allocate_for_unsized( + Self::allocate_for_layout( Layout::array::(len).unwrap(), |mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>, ) @@ -945,13 +1084,46 @@ impl Arc { // the Arc itself to be `mut`, so we're returning the only possible // reference to the inner data. unsafe { - Some(&mut this.ptr.as_mut().data) + Some(Arc::get_mut_unchecked(this)) } } else { None } } + /// Returns a mutable reference to the inner value, + /// without any check. + /// + /// See also [`get_mut`], which is safe and does appropriate checks. + /// + /// [`get_mut`]: struct.Arc.html#method.get_mut + /// + /// # Safety + /// + /// Any other `Arc` or [`Weak`] pointers to the same value must not be dereferenced + /// for the duration of the returned borrow. + /// This is trivially the case if no such pointers exist, + /// for example immediately after `Arc::new`. + /// + /// # Examples + /// + /// ``` + /// #![feature(get_mut_unchecked)] + /// + /// use std::sync::Arc; + /// + /// let mut x = Arc::new(String::new()); + /// unsafe { + /// Arc::get_mut_unchecked(&mut x).push_str("foo") + /// } + /// assert_eq!(*x, "foo"); + /// ``` + #[inline] + #[unstable(feature = "get_mut_unchecked", issue = "63292")] + pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { + &mut this.ptr.as_mut().data + } + /// Determine whether this is the unique reference (including weak refs) to /// the underlying data. /// @@ -1072,11 +1244,9 @@ impl Arc { /// } /// } /// - /// fn main() { - /// let my_string = "Hello World".to_string(); - /// print_if_string(Arc::new(my_string)); - /// print_if_string(Arc::new(0i8)); - /// } + /// let my_string = "Hello World".to_string(); + /// print_if_string(Arc::new(my_string)); + /// print_if_string(Arc::new(0i8)); /// ``` pub fn downcast(self) -> Result, Self> where @@ -1378,19 +1548,18 @@ impl Weak { } } - /// Returns `true` if the two `Weak`s point to the same value (not just values - /// that compare as equal). + /// Returns `true` if the two `Weak`s point to the same value (not just + /// values that compare as equal), or if both don't point to any value + /// (because they were created with `Weak::new()`). /// /// # Notes /// /// Since this compares pointers it means that `Weak::new()` will equal each /// other, even though they don't point to any value. /// - /// /// # Examples /// /// ``` - /// #![feature(weak_ptr_eq)] /// use std::sync::Arc; /// /// let first_rc = Arc::new(5); @@ -1408,7 +1577,6 @@ impl Weak { /// Comparing `Weak::new`. /// /// ``` - /// #![feature(weak_ptr_eq)] /// use std::sync::{Arc, Weak}; /// /// let first = Weak::new(); @@ -1420,7 +1588,7 @@ impl Weak { /// assert!(!first.ptr_eq(&third)); /// ``` #[inline] - #[unstable(feature = "weak_ptr_eq", issue = "55981")] + #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { self.ptr.as_ptr() == other.ptr.as_ptr() } diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index 844afe870766b..266a0d055d5bc 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -689,7 +689,10 @@ fn test_split_off_empty_left() { #[test] fn test_split_off_large_random_sorted() { + #[cfg(not(miri))] // Miri is too slow let mut data = rand_data(1529); + #[cfg(miri)] + let mut data = rand_data(529); // special case with maximum height. data.sort(); diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index 8c3dacd914f39..5c611fd21d21b 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -48,7 +48,9 @@ fn check(a: &[i32], b: &[i32], expected: &[i32], f: F) f(&set_a, &set_b, &mut |&x| { - assert_eq!(x, expected[i]); + if i < expected.len() { + assert_eq!(x, expected[i]); + } i += 1; true }); @@ -69,20 +71,41 @@ fn test_intersection() { check_intersection(&[11, 1, 3, 77, 103, 5, -5], &[2, 11, 77, -9, -42, 5, 3], &[3, 5, 11, 77]); - let large = (0..1000).collect::>(); + + if cfg!(miri) { // Miri is too slow + return; + } + + let large = (0..100).collect::>(); check_intersection(&[], &large, &[]); check_intersection(&large, &[], &[]); check_intersection(&[-1], &large, &[]); check_intersection(&large, &[-1], &[]); check_intersection(&[0], &large, &[0]); check_intersection(&large, &[0], &[0]); - check_intersection(&[999], &large, &[999]); - check_intersection(&large, &[999], &[999]); - check_intersection(&[1000], &large, &[]); - check_intersection(&large, &[1000], &[]); - check_intersection(&[11, 5000, 1, 3, 77, 8924, 103], + check_intersection(&[99], &large, &[99]); + check_intersection(&large, &[99], &[99]); + check_intersection(&[100], &large, &[]); + check_intersection(&large, &[100], &[]); + check_intersection(&[11, 5000, 1, 3, 77, 8924], &large, - &[1, 3, 11, 77, 103]); + &[1, 3, 11, 77]); +} + +#[test] +fn test_intersection_size_hint() { + let x: BTreeSet = [3, 4].iter().copied().collect(); + let y: BTreeSet = [1, 2, 3].iter().copied().collect(); + let mut iter = x.intersection(&y); + assert_eq!(iter.size_hint(), (1, Some(1))); + assert_eq!(iter.next(), Some(&3)); + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next(), None); + + iter = y.intersection(&y); + assert_eq!(iter.size_hint(), (0, Some(3))); + assert_eq!(iter.next(), Some(&1)); + assert_eq!(iter.size_hint(), (0, Some(2))); } #[test] @@ -95,21 +118,93 @@ fn test_difference() { check_difference(&[1, 12], &[], &[1, 12]); check_difference(&[], &[1, 2, 3, 9], &[]); check_difference(&[1, 3, 5, 9, 11], &[3, 9], &[1, 5, 11]); + check_difference(&[1, 3, 5, 9, 11], &[3, 6, 9], &[1, 5, 11]); + check_difference(&[1, 3, 5, 9, 11], &[0, 1], &[3, 5, 9, 11]); + check_difference(&[1, 3, 5, 9, 11], &[11, 12], &[1, 3, 5, 9]); check_difference(&[-5, 11, 22, 33, 40, 42], &[-12, -5, 14, 23, 34, 38, 39, 50], &[11, 22, 33, 40, 42]); - let large = (0..1000).collect::>(); + + if cfg!(miri) { // Miri is too slow + return; + } + + let large = (0..100).collect::>(); check_difference(&[], &large, &[]); check_difference(&[-1], &large, &[-1]); check_difference(&[0], &large, &[]); - check_difference(&[999], &large, &[]); - check_difference(&[1000], &large, &[1000]); - check_difference(&[11, 5000, 1, 3, 77, 8924, 103], + check_difference(&[99], &large, &[]); + check_difference(&[100], &large, &[100]); + check_difference(&[11, 5000, 1, 3, 77, 8924], &large, &[5000, 8924]); check_difference(&large, &[], &large); check_difference(&large, &[-1], &large); - check_difference(&large, &[1000], &large); + check_difference(&large, &[100], &large); +} + +#[test] +fn test_difference_size_hint() { + let s246: BTreeSet = [2, 4, 6].iter().copied().collect(); + let s23456: BTreeSet = (2..=6).collect(); + let mut iter = s246.difference(&s23456); + assert_eq!(iter.size_hint(), (0, Some(3))); + assert_eq!(iter.next(), None); + + let s12345: BTreeSet = (1..=5).collect(); + iter = s246.difference(&s12345); + assert_eq!(iter.size_hint(), (0, Some(3))); + assert_eq!(iter.next(), Some(&6)); + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next(), None); + + let s34567: BTreeSet = (3..=7).collect(); + iter = s246.difference(&s34567); + assert_eq!(iter.size_hint(), (0, Some(3))); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.size_hint(), (0, Some(2))); + assert_eq!(iter.next(), None); + + let s1: BTreeSet = (-9..=1).collect(); + iter = s246.difference(&s1); + assert_eq!(iter.size_hint(), (3, Some(3))); + + let s2: BTreeSet = (-9..=2).collect(); + iter = s246.difference(&s2); + assert_eq!(iter.size_hint(), (2, Some(2))); + assert_eq!(iter.next(), Some(&4)); + assert_eq!(iter.size_hint(), (1, Some(1))); + + let s23: BTreeSet = (2..=3).collect(); + iter = s246.difference(&s23); + assert_eq!(iter.size_hint(), (1, Some(3))); + assert_eq!(iter.next(), Some(&4)); + assert_eq!(iter.size_hint(), (1, Some(1))); + + let s4: BTreeSet = (4..=4).collect(); + iter = s246.difference(&s4); + assert_eq!(iter.size_hint(), (2, Some(3))); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.size_hint(), (1, Some(2))); + assert_eq!(iter.next(), Some(&6)); + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next(), None); + + let s56: BTreeSet = (5..=6).collect(); + iter = s246.difference(&s56); + assert_eq!(iter.size_hint(), (1, Some(3))); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.size_hint(), (0, Some(2))); + + let s6: BTreeSet = (6..=19).collect(); + iter = s246.difference(&s6); + assert_eq!(iter.size_hint(), (2, Some(2))); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.size_hint(), (1, Some(1))); + + let s7: BTreeSet = (7..=19).collect(); + iter = s246.difference(&s7); + assert_eq!(iter.size_hint(), (3, Some(3))); } #[test] @@ -166,13 +261,24 @@ fn test_is_subset() { assert_eq!(is_subset(&[1, 2], &[1]), false); assert_eq!(is_subset(&[1, 2], &[1, 2]), true); assert_eq!(is_subset(&[1, 2], &[2, 3]), false); - let large = (0..1000).collect::>(); + assert_eq!(is_subset(&[-5, 11, 22, 33, 40, 42], + &[-12, -5, 11, 14, 22, 23, 33, 34, 38, 39, 40, 42]), + true); + assert_eq!(is_subset(&[-5, 11, 22, 33, 40, 42], + &[-12, -5, 11, 14, 22, 23, 34, 38]), + false); + + if cfg!(miri) { // Miri is too slow + return; + } + + let large = (0..100).collect::>(); assert_eq!(is_subset(&[], &large), true); assert_eq!(is_subset(&large, &[]), false); assert_eq!(is_subset(&[-1], &large), false); assert_eq!(is_subset(&[0], &large), true); assert_eq!(is_subset(&[1, 2], &large), true); - assert_eq!(is_subset(&[999, 1000], &large), false); + assert_eq!(is_subset(&[99, 100], &large), false); } #[test] @@ -371,7 +477,10 @@ fn test_split_off_empty_left() { #[test] fn test_split_off_large_random_sorted() { + #[cfg(not(miri))] // Miri is too slow let mut data = rand_data(1529); + #[cfg(miri)] + let mut data = rand_data(529); // special case with maximum height. data.sort(); diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 6d774f3fecd92..f2a2c80f2f7ee 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -4,10 +4,10 @@ #![feature(exact_size_is_empty)] #![feature(option_flattening)] #![feature(pattern)] -#![feature(repeat_generic_slice)] #![feature(trusted_len)] #![feature(try_reserve)] #![feature(unboxed_closures)] +#![feature(associated_type_bounds)] use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index c5198ca39fedf..4332b2e90fdaf 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -1638,10 +1638,12 @@ mod pattern { } } - fn cmp_search_to_vec<'a, P: Pattern<'a>>(rev: bool, pat: P, haystack: &'a str, - right: Vec) - where P::Searcher: ReverseSearcher<'a> - { + fn cmp_search_to_vec<'a>( + rev: bool, + pat: impl Pattern<'a, Searcher: ReverseSearcher<'a>>, + haystack: &'a str, + right: Vec + ) { let mut searcher = pat.into_searcher(haystack); let mut v = vec![]; loop { diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index 765210e5aa6b3..55edf56345b59 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -1,5 +1,5 @@ use std::borrow::Cow; -use std::collections::CollectionAllocErr::*; +use std::collections::TryReserveError::*; use std::mem::size_of; use std::{usize, isize}; @@ -566,11 +566,11 @@ fn test_try_reserve() { } else { panic!("usize::MAX should trigger an overflow!") } } else { // Check isize::MAX + 1 is an OOM - if let Err(AllocErr) = empty_string.try_reserve(MAX_CAP + 1) { + if let Err(AllocError { .. }) = empty_string.try_reserve(MAX_CAP + 1) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } // Check usize::MAX is an OOM - if let Err(AllocErr) = empty_string.try_reserve(MAX_USIZE) { + if let Err(AllocError { .. }) = empty_string.try_reserve(MAX_USIZE) { } else { panic!("usize::MAX should trigger an OOM!") } } } @@ -590,7 +590,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should always overflow in the add-to-len @@ -629,10 +629,10 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_USIZE) { } else { panic!("usize::MAX should trigger an overflow!") } } else { - if let Err(AllocErr) = empty_string.try_reserve_exact(MAX_CAP + 1) { + if let Err(AllocError { .. }) = empty_string.try_reserve_exact(MAX_CAP + 1) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } - if let Err(AllocErr) = empty_string.try_reserve_exact(MAX_USIZE) { + if let Err(AllocError { .. }) = empty_string.try_reserve_exact(MAX_USIZE) { } else { panic!("usize::MAX should trigger an OOM!") } } } @@ -651,7 +651,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 6e8ffe18522a0..98d013dfa2b57 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use std::mem::size_of; use std::{usize, isize}; use std::vec::{Drain, IntoIter}; -use std::collections::CollectionAllocErr::*; +use std::collections::TryReserveError::*; struct DropCounter<'a> { count: &'a mut u32, @@ -1121,11 +1121,11 @@ fn test_try_reserve() { } else { panic!("usize::MAX should trigger an overflow!") } } else { // Check isize::MAX + 1 is an OOM - if let Err(AllocErr) = empty_bytes.try_reserve(MAX_CAP + 1) { + if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_CAP + 1) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } // Check usize::MAX is an OOM - if let Err(AllocErr) = empty_bytes.try_reserve(MAX_USIZE) { + if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE) { } else { panic!("usize::MAX should trigger an OOM!") } } } @@ -1145,7 +1145,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should always overflow in the add-to-len @@ -1168,7 +1168,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { + if let Err(AllocError { .. }) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should fail in the mul-by-size @@ -1209,10 +1209,10 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_USIZE) { } else { panic!("usize::MAX should trigger an overflow!") } } else { - if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { + if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } - if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_USIZE) { + if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_USIZE) { } else { panic!("usize::MAX should trigger an OOM!") } } } @@ -1231,7 +1231,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { @@ -1252,7 +1252,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { + if let Err(AllocError { .. }) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) { @@ -1281,3 +1281,51 @@ fn test_stable_push_pop() { v.pop().unwrap(); assert_eq!(*v0, 13); } + +// https://github.com/rust-lang/rust/pull/49496 introduced specialization based on: +// +// ``` +// unsafe impl IsZero for *mut T { +// fn is_zero(&self) -> bool { +// (*self).is_null() +// } +// } +// ``` +// +// … to call `RawVec::with_capacity_zeroed` for creating `Vec<*mut T>`, +// which is incorrect for fat pointers since `<*mut T>::is_null` only looks at the data component. +// That is, a fat pointer can be “null” without being made entirely of zero bits. +#[test] +fn vec_macro_repeating_null_raw_fat_pointer() { + let raw_dyn = &mut (|| ()) as &mut dyn Fn() as *mut dyn Fn(); + let vtable = dbg!(ptr_metadata(raw_dyn)); + let null_raw_dyn = ptr_from_raw_parts(std::ptr::null_mut(), vtable); + assert!(null_raw_dyn.is_null()); + + let vec = vec![null_raw_dyn; 1]; + dbg!(ptr_metadata(vec[0])); + assert!(vec[0] == null_raw_dyn); + + // Polyfill for https://github.com/rust-lang/rfcs/pull/2580 + + fn ptr_metadata(ptr: *mut dyn Fn()) -> *mut () { + unsafe { + std::mem::transmute::<*mut dyn Fn(), DynRepr>(ptr).vtable + } + } + + fn ptr_from_raw_parts(data: *mut (), vtable: *mut()) -> *mut dyn Fn() { + unsafe { + std::mem::transmute::(DynRepr { + data, + vtable + }) + } + } + + #[repr(C)] + struct DynRepr { + data: *mut (), + vtable: *mut (), + } +} diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index 1bbcca97b3c78..d49b553fc0217 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -1,6 +1,6 @@ use std::fmt::Debug; use std::collections::{VecDeque, vec_deque::Drain}; -use std::collections::CollectionAllocErr::*; +use std::collections::TryReserveError::*; use std::mem::size_of; use std::{usize, isize}; @@ -1168,7 +1168,7 @@ fn test_try_reserve() { // VecDeque starts with capacity 7, always adds 1 to the capacity // and also rounds the number to next power of 2 so this is the // furthest we can go without triggering CapacityOverflow - if let Err(AllocErr) = empty_bytes.try_reserve(MAX_CAP) { + if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_CAP) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } } @@ -1188,7 +1188,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should always overflow in the add-to-len @@ -1211,7 +1211,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { + if let Err(AllocError { .. }) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should fail in the mul-by-size @@ -1256,7 +1256,7 @@ fn test_try_reserve_exact() { // VecDeque starts with capacity 7, always adds 1 to the capacity // and also rounds the number to next power of 2 so this is the // furthest we can go without triggering CapacityOverflow - if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_CAP) { + if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_CAP) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } } @@ -1275,7 +1275,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { @@ -1296,7 +1296,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { + if let Err(AllocError { .. }) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) { diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index dac04e4e62403..6350b189c5faa 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -70,7 +70,7 @@ use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; use crate::borrow::{ToOwned, Cow}; -use crate::collections::CollectionAllocErr; +use crate::collections::TryReserveError; use crate::boxed::Box; use crate::raw_vec::RawVec; @@ -291,6 +291,7 @@ use crate::raw_vec::RawVec; /// [`reserve`]: ../../std/vec/struct.Vec.html#method.reserve /// [owned slice]: ../../std/boxed/struct.Box.html #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")] pub struct Vec { buf: RawVec, len: usize, @@ -313,10 +314,9 @@ impl Vec { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_vec_new")] pub const fn new() -> Vec { Vec { - buf: RawVec::new(), + buf: RawVec::NEW, len: 0, } } @@ -389,28 +389,26 @@ impl Vec { /// use std::ptr; /// use std::mem; /// - /// fn main() { - /// let mut v = vec![1, 2, 3]; - /// - /// // Pull out the various important pieces of information about `v` - /// let p = v.as_mut_ptr(); - /// let len = v.len(); - /// let cap = v.capacity(); + /// let mut v = vec![1, 2, 3]; /// - /// unsafe { - /// // Cast `v` into the void: no destructor run, so we are in - /// // complete control of the allocation to which `p` points. - /// mem::forget(v); + /// // Pull out the various important pieces of information about `v` + /// let p = v.as_mut_ptr(); + /// let len = v.len(); + /// let cap = v.capacity(); /// - /// // Overwrite memory with 4, 5, 6 - /// for i in 0..len as isize { - /// ptr::write(p.offset(i), 4 + i); - /// } + /// unsafe { + /// // Cast `v` into the void: no destructor run, so we are in + /// // complete control of the allocation to which `p` points. + /// mem::forget(v); /// - /// // Put everything back together into a Vec - /// let rebuilt = Vec::from_raw_parts(p, len, cap); - /// assert_eq!(rebuilt, [4, 5, 6]); + /// // Overwrite memory with 4, 5, 6 + /// for i in 0..len as isize { + /// ptr::write(p.offset(i), 4 + i); /// } + /// + /// // Put everything back together into a Vec + /// let rebuilt = Vec::from_raw_parts(p, len, cap); + /// assert_eq!(rebuilt, [4, 5, 6]); /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -498,9 +496,9 @@ impl Vec { /// /// ``` /// #![feature(try_reserve)] - /// use std::collections::CollectionAllocErr; + /// use std::collections::TryReserveError; /// - /// fn process_data(data: &[u32]) -> Result, CollectionAllocErr> { + /// fn process_data(data: &[u32]) -> Result, TryReserveError> { /// let mut output = Vec::new(); /// /// // Pre-reserve the memory, exiting if we can't @@ -516,7 +514,7 @@ impl Vec { /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.buf.try_reserve(self.len, additional) } @@ -538,9 +536,9 @@ impl Vec { /// /// ``` /// #![feature(try_reserve)] - /// use std::collections::CollectionAllocErr; + /// use std::collections::TryReserveError; /// - /// fn process_data(data: &[u32]) -> Result, CollectionAllocErr> { + /// fn process_data(data: &[u32]) -> Result, TryReserveError> { /// let mut output = Vec::new(); /// /// // Pre-reserve the memory, exiting if we can't @@ -556,7 +554,7 @@ impl Vec { /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] - pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { self.buf.try_reserve_exact(self.len, additional) } @@ -684,21 +682,25 @@ impl Vec { /// [`drain`]: #method.drain #[stable(feature = "rust1", since = "1.0.0")] pub fn truncate(&mut self, len: usize) { - let current_len = self.len; - unsafe { - let mut ptr = self.as_mut_ptr().add(self.len); - // Set the final length at the end, keeping in mind that - // dropping an element might panic. Works around a missed - // optimization, as seen in the following issue: - // https://github.com/rust-lang/rust/issues/51802 - let mut local_len = SetLenOnDrop::new(&mut self.len); + if mem::needs_drop::() { + let current_len = self.len; + unsafe { + let mut ptr = self.as_mut_ptr().add(self.len); + // Set the final length at the end, keeping in mind that + // dropping an element might panic. Works around a missed + // optimization, as seen in the following issue: + // https://github.com/rust-lang/rust/issues/51802 + let mut local_len = SetLenOnDrop::new(&mut self.len); - // drop any extra elements - for _ in len..current_len { - local_len.decrement_len(1); - ptr = ptr.offset(-1); - ptr::drop_in_place(ptr); + // drop any extra elements + for _ in len..current_len { + local_len.decrement_len(1); + ptr = ptr.offset(-1); + ptr::drop_in_place(ptr); + } } + } else if len <= self.len { + self.len = len; } } @@ -1387,12 +1389,10 @@ impl Vec { /// ``` /// #![feature(vec_leak)] /// - /// fn main() { - /// let x = vec![1, 2, 3]; - /// let static_ref: &'static mut [usize] = Vec::leak(x); - /// static_ref[0] += 1; - /// assert_eq!(static_ref, &[2, 2, 3]); - /// } + /// let x = vec![1, 2, 3]; + /// let static_ref: &'static mut [usize] = Vec::leak(x); + /// static_ref[0] += 1; + /// assert_eq!(static_ref, &[2, 2, 3]); /// ``` #[unstable(feature = "vec_leak", issue = "62195")] #[inline] @@ -1730,20 +1730,45 @@ impl_is_zero!(char, |x| x == '\0'); impl_is_zero!(f32, |x: f32| x.to_bits() == 0); impl_is_zero!(f64, |x: f64| x.to_bits() == 0); -unsafe impl IsZero for *const T { +unsafe impl IsZero for *const T { #[inline] fn is_zero(&self) -> bool { (*self).is_null() } } -unsafe impl IsZero for *mut T { +unsafe impl IsZero for *mut T { #[inline] fn is_zero(&self) -> bool { (*self).is_null() } } +// `Option<&T>`, `Option<&mut T>` and `Option>` are guaranteed to represent `None` as null. +// For fat pointers, the bytes that would be the pointer metadata in the `Some` variant +// are padding in the `None` variant, so ignoring them and zero-initializing instead is ok. + +unsafe impl IsZero for Option<&T> { + #[inline] + fn is_zero(&self) -> bool { + self.is_none() + } +} + +unsafe impl IsZero for Option<&mut T> { + #[inline] + fn is_zero(&self) -> bool { + self.is_none() + } +} + +unsafe impl IsZero for Option> { + #[inline] + fn is_zero(&self) -> bool { + self.is_none() + } +} + //////////////////////////////////////////////////////////////////////////////// // Common trait implementations for Vec diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 690d8344acff9..66d27a275192e 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -500,7 +500,7 @@ impl DroplessArena { // though it was supposed to give us `len` return slice::from_raw_parts_mut(mem, i); } - ptr::write(mem.offset(i as isize), value.unwrap()); + ptr::write(mem.add(i), value.unwrap()); i += 1; } } diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 078091a9b5475..85b59162620fa 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -87,10 +87,8 @@ pub trait Any: 'static { /// TypeId::of::() == s.type_id() /// } /// - /// fn main() { - /// assert_eq!(is_string(&0), false); - /// assert_eq!(is_string(&"cookie monster".to_string()), true); - /// } + /// assert_eq!(is_string(&0), false); + /// assert_eq!(is_string(&"cookie monster".to_string()), true); /// ``` #[stable(feature = "get_type_id", since = "1.34.0")] fn type_id(&self) -> TypeId; @@ -145,21 +143,19 @@ impl dyn Any { /// } /// } /// - /// fn main() { - /// is_string(&0); - /// is_string(&"cookie monster".to_string()); - /// } + /// is_string(&0); + /// is_string(&"cookie monster".to_string()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is(&self) -> bool { - // Get TypeId of the type this function is instantiated with + // Get `TypeId` of the type this function is instantiated with. let t = TypeId::of::(); - // Get TypeId of the type in the trait object + // Get `TypeId` of the type in the trait object. let concrete = self.type_id(); - // Compare both TypeIds on equality + // Compare both `TypeId`s on equality. t == concrete } @@ -179,10 +175,8 @@ impl dyn Any { /// } /// } /// - /// fn main() { - /// print_if_string(&0); - /// print_if_string(&"cookie monster".to_string()); - /// } + /// print_if_string(&0); + /// print_if_string(&"cookie monster".to_string()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -210,16 +204,14 @@ impl dyn Any { /// } /// } /// - /// fn main() { - /// let mut x = 10u32; - /// let mut s = "starlord".to_string(); + /// let mut x = 10u32; + /// let mut s = "starlord".to_string(); /// - /// modify_if_u32(&mut x); - /// modify_if_u32(&mut s); + /// modify_if_u32(&mut x); + /// modify_if_u32(&mut s); /// - /// assert_eq!(x, 42); - /// assert_eq!(&s, "starlord"); - /// } + /// assert_eq!(x, 42); + /// assert_eq!(&s, "starlord"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -250,10 +242,8 @@ impl dyn Any+Send { /// } /// } /// - /// fn main() { - /// is_string(&0); - /// is_string(&"cookie monster".to_string()); - /// } + /// is_string(&0); + /// is_string(&"cookie monster".to_string()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -276,10 +266,8 @@ impl dyn Any+Send { /// } /// } /// - /// fn main() { - /// print_if_string(&0); - /// print_if_string(&"cookie monster".to_string()); - /// } + /// print_if_string(&0); + /// print_if_string(&"cookie monster".to_string()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -300,16 +288,14 @@ impl dyn Any+Send { /// } /// } /// - /// fn main() { - /// let mut x = 10u32; - /// let mut s = "starlord".to_string(); + /// let mut x = 10u32; + /// let mut s = "starlord".to_string(); /// - /// modify_if_u32(&mut x); - /// modify_if_u32(&mut s); + /// modify_if_u32(&mut x); + /// modify_if_u32(&mut s); /// - /// assert_eq!(x, 42); - /// assert_eq!(&s, "starlord"); - /// } + /// assert_eq!(x, 42); + /// assert_eq!(&s, "starlord"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -334,10 +320,8 @@ impl dyn Any+Send+Sync { /// } /// } /// - /// fn main() { - /// is_string(&0); - /// is_string(&"cookie monster".to_string()); - /// } + /// is_string(&0); + /// is_string(&"cookie monster".to_string()); /// ``` #[stable(feature = "any_send_sync_methods", since = "1.28.0")] #[inline] @@ -360,10 +344,8 @@ impl dyn Any+Send+Sync { /// } /// } /// - /// fn main() { - /// print_if_string(&0); - /// print_if_string(&"cookie monster".to_string()); - /// } + /// print_if_string(&0); + /// print_if_string(&"cookie monster".to_string()); /// ``` #[stable(feature = "any_send_sync_methods", since = "1.28.0")] #[inline] @@ -384,16 +366,14 @@ impl dyn Any+Send+Sync { /// } /// } /// - /// fn main() { - /// let mut x = 10u32; - /// let mut s = "starlord".to_string(); + /// let mut x = 10u32; + /// let mut s = "starlord".to_string(); /// - /// modify_if_u32(&mut x); - /// modify_if_u32(&mut s); + /// modify_if_u32(&mut x); + /// modify_if_u32(&mut s); /// - /// assert_eq!(x, 42); - /// assert_eq!(&s, "starlord"); - /// } + /// assert_eq!(x, 42); + /// assert_eq!(&s, "starlord"); /// ``` #[stable(feature = "any_send_sync_methods", since = "1.28.0")] #[inline] @@ -437,10 +417,8 @@ impl TypeId { /// TypeId::of::() == TypeId::of::() /// } /// - /// fn main() { - /// assert_eq!(is_string(&0), false); - /// assert_eq!(is_string(&"cookie monster".to_string()), true); - /// } + /// assert_eq!(is_string(&0), false); + /// assert_eq!(is_string(&"cookie monster".to_string()), true); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature="const_type_id")] @@ -470,10 +448,5 @@ impl TypeId { #[stable(feature = "type_name", since = "1.38.0")] #[rustc_const_unstable(feature = "const_type_name")] pub const fn type_name() -> &'static str { - #[cfg(bootstrap)] - unsafe { - intrinsics::type_name::() - } - #[cfg(not(bootstrap))] intrinsics::type_name::() } diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index e6a6fdde54042..4087333e2cf6d 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -14,6 +14,7 @@ use crate::fmt; use crate::ops::Range; use crate::iter::FusedIterator; +use crate::str::from_utf8_unchecked; /// An iterator over the escaped version of a byte. /// @@ -22,6 +23,7 @@ use crate::iter::FusedIterator; /// /// [`escape_default`]: fn.escape_default.html #[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] pub struct EscapeDefault { range: Range, data: [u8; 4], @@ -130,6 +132,13 @@ impl ExactSizeIterator for EscapeDefault {} #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for EscapeDefault {} +#[stable(feature = "ascii_escape_display", since = "1.39.0")] +impl fmt::Display for EscapeDefault { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(unsafe { from_utf8_unchecked(&self.data[self.range.clone()]) }) + } +} + #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for EscapeDefault { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/src/libcore/benches/slice.rs b/src/libcore/benches/slice.rs index 484753c1a045e..711a8dff2c0b5 100644 --- a/src/libcore/benches/slice.rs +++ b/src/libcore/benches/slice.rs @@ -55,3 +55,29 @@ fn binary_search_l2_with_dups(b: &mut Bencher) { fn binary_search_l3_with_dups(b: &mut Bencher) { binary_search(b, Cache::L3, |i| i / 16 * 16); } + +macro_rules! rotate { + ($fn:ident, $n:expr, $mapper:expr) => { + #[bench] + fn $fn(b: &mut Bencher) { + let mut x = (0usize..$n).map(&$mapper).collect::>(); + b.iter(|| { + for s in 0..x.len() { + x[..].rotate_right(s); + } + black_box(x[0].clone()) + }) + } + }; +} + +#[derive(Clone)] +struct Rgb(u8, u8, u8); + +rotate!(rotate_u8, 32, |i| i as u8); +rotate!(rotate_rgb, 32, |i| Rgb(i as u8, (i as u8).wrapping_add(7), (i as u8).wrapping_add(42))); +rotate!(rotate_usize, 32, |i| i); +rotate!(rotate_16_usize_4, 16, |i| [i; 4]); +rotate!(rotate_16_usize_5, 16, |i| [i; 5]); +rotate!(rotate_64_usize_4, 64, |i| [i; 4]); +rotate!(rotate_64_usize_5, 64, |i| [i; 5]); diff --git a/src/libcore/bool.rs b/src/libcore/bool.rs new file mode 100644 index 0000000000000..617bdd238f4c6 --- /dev/null +++ b/src/libcore/bool.rs @@ -0,0 +1,44 @@ +//! impl bool {} + +#[lang = "bool"] +impl bool { + /// Returns `Some(t)` if the `bool` is `true`, or `None` otherwise. + /// + /// # Examples + /// + /// ``` + /// #![feature(bool_to_option)] + /// + /// assert_eq!(false.then(0), None); + /// assert_eq!(true.then(0), Some(0)); + /// ``` + #[unstable(feature = "bool_to_option", issue = "64260")] + #[inline] + pub fn then(self, t: T) -> Option { + if self { + Some(t) + } else { + None + } + } + + /// Returns `Some(f())` if the `bool` is `true`, or `None` otherwise. + /// + /// # Examples + /// + /// ``` + /// #![feature(bool_to_option)] + /// + /// assert_eq!(false.then_with(|| 0), None); + /// assert_eq!(true.then_with(|| 0), Some(0)); + /// ``` + #[unstable(feature = "bool_to_option", issue = "64260")] + #[inline] + pub fn then_with T>(self, f: F) -> Option { + if self { + Some(f()) + } else { + None + } + } +} diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 8579dbf353e80..fda103a52d8bc 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -229,52 +229,6 @@ pub struct Cell { value: UnsafeCell, } -impl Cell { - /// Returns a copy of the contained value. - /// - /// # Examples - /// - /// ``` - /// use std::cell::Cell; - /// - /// let c = Cell::new(5); - /// - /// let five = c.get(); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get(&self) -> T { - unsafe{ *self.value.get() } - } - - /// Updates the contained value using a function and returns the new value. - /// - /// # Examples - /// - /// ``` - /// #![feature(cell_update)] - /// - /// use std::cell::Cell; - /// - /// let c = Cell::new(5); - /// let new = c.update(|x| x + 1); - /// - /// assert_eq!(new, 6); - /// assert_eq!(c.get(), 6); - /// ``` - #[inline] - #[unstable(feature = "cell_update", issue = "50186")] - pub fn update(&self, f: F) -> T - where - F: FnOnce(T) -> T, - { - let old = self.get(); - let new = f(old); - self.set(new); - new - } -} - #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Send for Cell where T: Send {} @@ -448,6 +402,52 @@ impl Cell { } } +impl Cell { + /// Returns a copy of the contained value. + /// + /// # Examples + /// + /// ``` + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// + /// let five = c.get(); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get(&self) -> T { + unsafe{ *self.value.get() } + } + + /// Updates the contained value using a function and returns the new value. + /// + /// # Examples + /// + /// ``` + /// #![feature(cell_update)] + /// + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// let new = c.update(|x| x + 1); + /// + /// assert_eq!(new, 6); + /// assert_eq!(c.get(), 6); + /// ``` + #[inline] + #[unstable(feature = "cell_update", issue = "50186")] + pub fn update(&self, f: F) -> T + where + F: FnOnce(T) -> T, + { + let old = self.get(); + let new = f(old); + self.set(new); + new + } +} + impl Cell { /// Returns a raw pointer to the underlying data in this cell. /// diff --git a/src/libcore/char/convert.rs b/src/libcore/char/convert.rs index 0a870c67518c7..c456e14db12d4 100644 --- a/src/libcore/char/convert.rs +++ b/src/libcore/char/convert.rs @@ -111,11 +111,9 @@ impl From for u32 { /// ``` /// use std::mem; /// - /// fn main() { - /// let c = 'c'; - /// let u = u32::from(c); - /// assert!(4 == mem::size_of_val(&u)) - /// } + /// let c = 'c'; + /// let u = u32::from(c); + /// assert!(4 == mem::size_of_val(&u)) /// ``` #[inline] fn from(c: char) -> Self { @@ -150,11 +148,9 @@ impl From for char { /// ``` /// use std::mem; /// - /// fn main() { - /// let u = 32 as u8; - /// let c = char::from(u); - /// assert!(4 == mem::size_of_val(&c)) - /// } + /// let u = 32 as u8; + /// let c = char::from(u); + /// assert!(4 == mem::size_of_val(&c)) /// ``` #[inline] fn from(i: u8) -> Self { diff --git a/src/libcore/char/decode.rs b/src/libcore/char/decode.rs index 23059243c61d7..b71c9c2c40b37 100644 --- a/src/libcore/char/decode.rs +++ b/src/libcore/char/decode.rs @@ -31,21 +31,23 @@ pub struct DecodeUtf16Error { /// ``` /// use std::char::decode_utf16; /// -/// fn main() { -/// // 𝄞music -/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075, -/// 0x0073, 0xDD1E, 0x0069, 0x0063, -/// 0xD834]; +/// // 𝄞music +/// let v = [ +/// 0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834, +/// ]; /// -/// assert_eq!(decode_utf16(v.iter().cloned()) -/// .map(|r| r.map_err(|e| e.unpaired_surrogate())) -/// .collect::>(), -/// vec![Ok('𝄞'), -/// Ok('m'), Ok('u'), Ok('s'), -/// Err(0xDD1E), -/// Ok('i'), Ok('c'), -/// Err(0xD834)]); -/// } +/// assert_eq!( +/// decode_utf16(v.iter().cloned()) +/// .map(|r| r.map_err(|e| e.unpaired_surrogate())) +/// .collect::>(), +/// vec![ +/// Ok('𝄞'), +/// Ok('m'), Ok('u'), Ok('s'), +/// Err(0xDD1E), +/// Ok('i'), Ok('c'), +/// Err(0xD834) +/// ] +/// ); /// ``` /// /// A lossy decoder can be obtained by replacing `Err` results with the replacement character: @@ -53,17 +55,17 @@ pub struct DecodeUtf16Error { /// ``` /// use std::char::{decode_utf16, REPLACEMENT_CHARACTER}; /// -/// fn main() { -/// // 𝄞music -/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075, -/// 0x0073, 0xDD1E, 0x0069, 0x0063, -/// 0xD834]; +/// // 𝄞music +/// let v = [ +/// 0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834, +/// ]; /// -/// assert_eq!(decode_utf16(v.iter().cloned()) -/// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) -/// .collect::(), -/// "𝄞mus�ic�"); -/// } +/// assert_eq!( +/// decode_utf16(v.iter().cloned()) +/// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) +/// .collect::(), +/// "𝄞mus�ic�" +/// ); /// ``` #[stable(feature = "decode_utf16", since = "1.9.0")] #[inline] diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index aa834db2b9b3e..a69eb0f6d4b20 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -547,39 +547,6 @@ impl char { } } - /// Returns `true` if this `char` satisfies the `XID_Start` Unicode property, and false - /// otherwise. - /// - /// `XID_Start` is a Unicode Derived Property specified in - /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), - /// mostly similar to `ID_Start` but modified for closure under `NFKx`. - #[cfg_attr(bootstrap, - unstable(feature = "rustc_private", - reason = "mainly needed for compiler internals", - issue = "27812"))] - #[cfg_attr(not(bootstrap), - unstable(feature = "unicode_internals", issue = "0"))] - pub fn is_xid_start(self) -> bool { - derived_property::XID_Start(self) - } - - /// Returns `true` if this `char` satisfies the `XID_Continue` Unicode property, and false - /// otherwise. - /// - /// `XID_Continue` is a Unicode Derived Property specified in - /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), - /// mostly similar to `ID_Continue` but modified for closure under NFKx. - #[cfg_attr(bootstrap, - unstable(feature = "rustc_private", - reason = "mainly needed for compiler internals", - issue = "27812"))] - #[cfg_attr(not(bootstrap), - unstable(feature = "unicode_internals", issue = "0"))] - #[inline] - pub fn is_xid_continue(self) -> bool { - derived_property::XID_Continue(self) - } - /// Returns `true` if this `char` is lowercase. /// /// 'Lowercase' is defined according to the terms of the Unicode Derived Core diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 9e32acb97d360..14d947ccf2402 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -133,6 +133,12 @@ pub trait Clone : Sized { } } +/// Derive macro generating an impl of the trait `Clone`. +#[rustc_builtin_macro] +#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[allow_internal_unstable(core_intrinsics, derive_clone_copy)] +pub macro Clone($item:item) { /* compiler built-in */ } + // FIXME(aburka): these structs are used solely by #[derive] to // assert that every component of a type implements Clone or Copy. // diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index f9613556a1ebc..d0ea75c7623f4 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -9,14 +9,22 @@ //! * [`Ord`] and [`PartialOrd`] are traits that allow you to define total and //! partial orderings between values, respectively. Implementing them overloads //! the `<`, `<=`, `>`, and `>=` operators. -//! * [`Ordering`][cmp::Ordering] is an enum returned by the -//! main functions of [`Ord`] and [`PartialOrd`], and describes an ordering. -//! * [`Reverse`][cmp::Reverse] is a struct that allows you to easily reverse -//! an ordering. -//! * [`max`][cmp::max] and [`min`][cmp::min] are functions that build off of -//! [`Ord`] and allow you to find the maximum or minimum of two values. +//! * [`Ordering`] is an enum returned by the main functions of [`Ord`] and +//! [`PartialOrd`], and describes an ordering. +//! * [`Reverse`] is a struct that allows you to easily reverse an ordering. +//! * [`max`] and [`min`] are functions that build off of [`Ord`] and allow you +//! to find the maximum or minimum of two values. //! //! For more details, see the respective documentation of each item in the list. +//! +//! [`Eq`]: trait.Eq.html +//! [`PartialEq`]: trait.PartialEq.html +//! [`Ord`]: trait.Ord.html +//! [`PartialOrd`]: trait.PartialOrd.html +//! [`Ordering`]: enum.Ordering.html +//! [`Reverse`]: struct.Reverse.html +//! [`max`]: fn.max.html +//! [`min`]: fn.min.html #![stable(feature = "rust1", since = "1.0.0")] @@ -200,6 +208,12 @@ pub trait PartialEq { fn ne(&self, other: &Rhs) -> bool { !self.eq(other) } } +/// Derive macro generating an impl of the trait `PartialEq`. +#[rustc_builtin_macro] +#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[allow_internal_unstable(core_intrinsics)] +pub macro PartialEq($item:item) { /* compiler built-in */ } + /// Trait for equality comparisons which are [equivalence relations]( /// https://en.wikipedia.org/wiki/Equivalence_relation). /// @@ -256,6 +270,12 @@ pub trait Eq: PartialEq { fn assert_receiver_is_total_eq(&self) {} } +/// Derive macro generating an impl of the trait `Eq`. +#[rustc_builtin_macro] +#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[allow_internal_unstable(core_intrinsics, derive_eq)] +pub macro Eq($item:item) { /* compiler built-in */ } + // FIXME: this struct is used solely by #[derive] to // assert that every component of a type implements Eq. // @@ -548,7 +568,7 @@ pub trait Ord: Eq + PartialOrd { #[inline] fn max(self, other: Self) -> Self where Self: Sized { - if other >= self { other } else { self } + max_by(self, other, Ord::cmp) } /// Compares and returns the minimum of two values. @@ -565,7 +585,7 @@ pub trait Ord: Eq + PartialOrd { #[inline] fn min(self, other: Self) -> Self where Self: Sized { - if self <= other { self } else { other } + min_by(self, other, Ord::cmp) } /// Restrict a value to a certain interval. @@ -600,6 +620,12 @@ pub trait Ord: Eq + PartialOrd { } } +/// Derive macro generating an impl of the trait `Ord`. +#[rustc_builtin_macro] +#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[allow_internal_unstable(core_intrinsics)] +pub macro Ord($item:item) { /* compiler built-in */ } + #[stable(feature = "rust1", since = "1.0.0")] impl Eq for Ordering {} @@ -842,6 +868,12 @@ pub trait PartialOrd: PartialEq { } } +/// Derive macro generating an impl of the trait `PartialOrd`. +#[rustc_builtin_macro] +#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[allow_internal_unstable(core_intrinsics)] +pub macro PartialOrd($item:item) { /* compiler built-in */ } + /// Compares and returns the minimum of two values. /// /// Returns the first argument if the comparison determines them to be equal. @@ -862,6 +894,49 @@ pub fn min(v1: T, v2: T) -> T { v1.min(v2) } +/// Returns the minimum of two values with respect to the specified comparison function. +/// +/// Returns the first argument if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// #![feature(cmp_min_max_by)] +/// +/// use std::cmp; +/// +/// assert_eq!(cmp::min_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), 1); +/// assert_eq!(cmp::min_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), -2); +/// ``` +#[inline] +#[unstable(feature = "cmp_min_max_by", issue = "64460")] +pub fn min_by Ordering>(v1: T, v2: T, compare: F) -> T { + match compare(&v1, &v2) { + Ordering::Less | Ordering::Equal => v1, + Ordering::Greater => v2, + } +} + +/// Returns the element that gives the minimum value from the specified function. +/// +/// Returns the first argument if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// #![feature(cmp_min_max_by)] +/// +/// use std::cmp; +/// +/// assert_eq!(cmp::min_by_key(-2, 1, |x: &i32| x.abs()), 1); +/// assert_eq!(cmp::min_by_key(-2, 2, |x: &i32| x.abs()), -2); +/// ``` +#[inline] +#[unstable(feature = "cmp_min_max_by", issue = "64460")] +pub fn min_by_key K, K: Ord>(v1: T, v2: T, mut f: F) -> T { + min_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) +} + /// Compares and returns the maximum of two values. /// /// Returns the second argument if the comparison determines them to be equal. @@ -882,6 +957,49 @@ pub fn max(v1: T, v2: T) -> T { v1.max(v2) } +/// Returns the maximum of two values with respect to the specified comparison function. +/// +/// Returns the second argument if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// #![feature(cmp_min_max_by)] +/// +/// use std::cmp; +/// +/// assert_eq!(cmp::max_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), -2); +/// assert_eq!(cmp::max_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), 2); +/// ``` +#[inline] +#[unstable(feature = "cmp_min_max_by", issue = "64460")] +pub fn max_by Ordering>(v1: T, v2: T, compare: F) -> T { + match compare(&v1, &v2) { + Ordering::Less | Ordering::Equal => v2, + Ordering::Greater => v1, + } +} + +/// Returns the element that gives the maximum value from the specified function. +/// +/// Returns the second argument if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// #![feature(cmp_min_max_by)] +/// +/// use std::cmp; +/// +/// assert_eq!(cmp::max_by_key(-2, 1, |x: &i32| x.abs()), -2); +/// assert_eq!(cmp::max_by_key(-2, 2, |x: &i32| x.abs()), 2); +/// ``` +#[inline] +#[unstable(feature = "cmp_min_max_by", issue = "64460")] +pub fn max_by_key K, K: Ord>(v1: T, v2: T, mut f: F) -> T { + max_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) +} + // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types mod impls { use crate::cmp::Ordering::{self, Less, Greater, Equal}; @@ -984,8 +1102,10 @@ mod impls { impl Ord for $t { #[inline] fn cmp(&self, other: &$t) -> Ordering { - if *self == *other { Equal } - else if *self < *other { Less } + // The order here is important to generate more optimal assembly. + // See for more info. + if *self < *other { Less } + else if *self == *other { Equal } else { Greater } } } diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 624b13d96472c..3cd2337ee59a5 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -42,11 +42,11 @@ use crate::fmt; -/// An identity function. +/// The identity function. /// /// Two things are important to note about this function: /// -/// - It is not always equivalent to a closure like `|x| x` since the +/// - It is not always equivalent to a closure like `|x| x`, since the /// closure may coerce `x` into a different type. /// /// - It moves the input `x` passed to the function. @@ -56,31 +56,32 @@ use crate::fmt; /// /// # Examples /// -/// Using `identity` to do nothing among other interesting functions: +/// Using `identity` to do nothing in a sequence of other, interesting, +/// functions: /// /// ```rust /// use std::convert::identity; /// /// fn manipulation(x: u32) -> u32 { -/// // Let's assume that this function does something interesting. +/// // Let's pretend that adding one is an interesting function. /// x + 1 /// } /// /// let _arr = &[identity, manipulation]; /// ``` /// -/// Using `identity` to get a function that changes nothing in a conditional: +/// Using `identity` as a "do nothing" base case in a conditional: /// /// ```rust /// use std::convert::identity; /// /// # let condition = true; -/// +/// # /// # fn manipulation(x: u32) -> u32 { x + 1 } -/// +/// # /// let do_stuff = if condition { manipulation } else { identity }; /// -/// // do more interesting stuff.. +/// // Do more interesting stuff... /// /// let _results = do_stuff(42); /// ``` @@ -104,22 +105,17 @@ pub const fn identity(x: T) -> T { x } /// If you need to do a costly conversion it is better to implement [`From`] with type /// `&T` or write a custom function. /// -/// `AsRef` has the same signature as [`Borrow`], but `Borrow` is different in few aspects: +/// `AsRef` has the same signature as [`Borrow`], but [`Borrow`] is different in few aspects: /// -/// - Unlike `AsRef`, `Borrow` has a blanket impl for any `T`, and can be used to accept either +/// - Unlike `AsRef`, [`Borrow`] has a blanket impl for any `T`, and can be used to accept either /// a reference or a value. -/// - `Borrow` also requires that `Hash`, `Eq` and `Ord` for borrowed value are +/// - [`Borrow`] also requires that [`Hash`], [`Eq`] and [`Ord`] for borrowed value are /// equivalent to those of the owned value. For this reason, if you want to -/// borrow only a single field of a struct you can implement `AsRef`, but not `Borrow`. -/// -/// [`Borrow`]: ../../std/borrow/trait.Borrow.html +/// borrow only a single field of a struct you can implement `AsRef`, but not [`Borrow`]. /// /// **Note: This trait must not fail**. If the conversion can fail, use a /// dedicated method which returns an [`Option`] or a [`Result`]. /// -/// [`Option`]: ../../std/option/enum.Option.html -/// [`Result`]: ../../std/result/enum.Result.html -/// /// # Generic Implementations /// /// - `AsRef` auto-dereferences if the inner type is a reference or a mutable @@ -132,9 +128,16 @@ pub const fn identity(x: T) -> T { x } /// converted to the specified type `T`. /// /// For example: By creating a generic function that takes an `AsRef` we express that we -/// want to accept all references that can be converted to `&str` as an argument. -/// Since both [`String`] and `&str` implement `AsRef` we can accept both as input argument. +/// want to accept all references that can be converted to [`&str`] as an argument. +/// Since both [`String`] and [`&str`] implement `AsRef` we can accept both as input argument. /// +/// [`Option`]: ../../std/option/enum.Option.html +/// [`Result`]: ../../std/result/enum.Result.html +/// [`Borrow`]: ../../std/borrow/trait.Borrow.html +/// [`Hash`]: ../../std/hash/trait.Hash.html +/// [`Eq`]: ../../std/cmp/trait.Eq.html +/// [`Ord`]: ../../std/cmp/trait.Ord.html +/// [`&str`]: ../../std/primitive.str.html /// [`String`]: ../../std/string/struct.String.html /// /// ``` @@ -513,7 +516,7 @@ impl AsRef for &mut T where T: AsRef // FIXME (#45742): replace the above impls for &/&mut with the following more general one: // // As lifts over Deref -// impl AsRef for D where D::Target: AsRef { +// impl>, U: ?Sized> AsRef for D { // fn as_ref(&self) -> &U { // self.deref().as_ref() // } @@ -530,7 +533,7 @@ impl AsMut for &mut T where T: AsMut // FIXME (#45742): replace the above impl for &mut with the following more general one: // // AsMut lifts over DerefMut -// impl AsMut for D where D::Target: AsMut { +// impl>, U: ?Sized> AsMut for D { // fn as_mut(&mut self) -> &mut U { // self.deref_mut().as_mut() // } @@ -551,6 +554,18 @@ impl From for T { fn from(t: T) -> T { t } } +/// **Stability note:** This impl does not yet exist, but we are +/// "reserving space" to add it in the future. See +/// [rust-lang/rust#64715][#64715] for details. +/// +/// [#64715]: https://github.com/rust-lang/rust/issues/64715 +#[stable(feature = "convert_infallible", since = "1.34.0")] +#[cfg(not(bootstrap))] +#[rustc_reservation_impl="permitting this impl would forbid us from adding \ +`impl From for T` later; see rust-lang/rust#64715 for details"] +impl From for T { + fn from(t: !) -> T { t } +} // TryFrom implies TryInto #[stable(feature = "try_from", since = "1.34.0")] diff --git a/src/libcore/default.rs b/src/libcore/default.rs index 5ad05b3824764..1aadc77cfb8da 100644 --- a/src/libcore/default.rs +++ b/src/libcore/default.rs @@ -115,6 +115,12 @@ pub trait Default: Sized { fn default() -> Self; } +/// Derive macro generating an impl of the trait `Default`. +#[rustc_builtin_macro] +#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[allow_internal_unstable(core_intrinsics)] +pub macro Default($item:item) { /* compiler built-in */ } + macro_rules! default_impl { ($t:ty, $v:expr, $doc:tt) => { #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index cb4e32622ff1f..15ce2277fa00d 100644 --- a/src/libcore/fmt/builders.rs +++ b/src/libcore/fmt/builders.rs @@ -98,7 +98,7 @@ pub struct DebugStruct<'a, 'b: 'a> { has_fields: bool, } -pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, +pub(super) fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugStruct<'a, 'b> { let result = fmt.write_str(name); @@ -251,7 +251,10 @@ pub struct DebugTuple<'a, 'b: 'a> { empty_name: bool, } -pub fn debug_tuple_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugTuple<'a, 'b> { +pub(super) fn debug_tuple_new<'a, 'b>( + fmt: &'a mut fmt::Formatter<'b>, + name: &str, +) -> DebugTuple<'a, 'b> { let result = fmt.write_str(name); DebugTuple { fmt, @@ -418,7 +421,7 @@ pub struct DebugSet<'a, 'b: 'a> { inner: DebugInner<'a, 'b>, } -pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugSet<'a, 'b> { +pub(super) fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugSet<'a, 'b> { let result = fmt.write_str("{"); DebugSet { inner: DebugInner { @@ -555,7 +558,7 @@ pub struct DebugList<'a, 'b: 'a> { inner: DebugInner<'a, 'b>, } -pub fn debug_list_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugList<'a, 'b> { +pub(super) fn debug_list_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugList<'a, 'b> { let result = fmt.write_str("["); DebugList { inner: DebugInner { @@ -697,7 +700,7 @@ pub struct DebugMap<'a, 'b: 'a> { state: PadAdapterState, } -pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugMap<'a, 'b> { +pub(super) fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugMap<'a, 'b> { let result = fmt.write_str("{"); DebugMap { fmt, diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 4a7c6af7adab7..5dfdd1623061e 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -518,7 +518,7 @@ impl Display for Arguments<'_> { label="`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{Debug}`", )] #[doc(alias = "{:?}")] -#[lang = "debug_trait"] +#[rustc_diagnostic_item = "debug_trait"] pub trait Debug { /// Formats the value using the given formatter. /// @@ -545,6 +545,18 @@ pub trait Debug { fn fmt(&self, f: &mut Formatter<'_>) -> Result; } +// Separate module to reexport the macro `Debug` from prelude without the trait `Debug`. +pub(crate) mod macros { + /// Derive macro generating an impl of the trait `Debug`. + #[rustc_builtin_macro] + #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] + #[allow_internal_unstable(core_intrinsics)] + pub macro Debug($item:item) { /* compiler built-in */ } +} +#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[doc(inline)] +pub use macros::Debug; + /// Format trait for an empty format, `{}`. /// /// `Display` is similar to [`Debug`][debug], but `Display` is for user-facing @@ -1520,12 +1532,10 @@ impl<'a> Formatter<'a> { /// } /// } /// - /// fn main() { - /// assert_eq!(&format!("{:<}", Foo), "left"); - /// assert_eq!(&format!("{:>}", Foo), "right"); - /// assert_eq!(&format!("{:^}", Foo), "center"); - /// assert_eq!(&format!("{}", Foo), "into the void"); - /// } + /// assert_eq!(&format!("{:<}", Foo), "left"); + /// assert_eq!(&format!("{:>}", Foo), "right"); + /// assert_eq!(&format!("{:^}", Foo), "center"); + /// assert_eq!(&format!("{}", Foo), "into the void"); /// ``` #[stable(feature = "fmt_flags_align", since = "1.28.0")] pub fn align(&self) -> Option { diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index 593c01060ca49..f14ed38b9b0f2 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -111,8 +111,7 @@ impl Future for &mut F { #[stable(feature = "futures_api", since = "1.36.0")] impl

Future for Pin

where - P: Unpin + ops::DerefMut, - P::Target: Future, + P: Unpin + ops::DerefMut, { type Output = <

::Target as Future>::Output; diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 38e3864284240..020e085abf8a8 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -198,6 +198,18 @@ pub trait Hash { } } +// Separate module to reexport the macro `Hash` from prelude without the trait `Hash`. +pub(crate) mod macros { + /// Derive macro generating an impl of the trait `Hash`. + #[rustc_builtin_macro] + #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] + #[allow_internal_unstable(core_intrinsics)] + pub macro Hash($item:item) { /* compiler built-in */ } +} +#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[doc(inline)] +pub use macros::Hash; + /// A trait for hashing an arbitrary stream of bytes. /// /// Instances of `Hasher` usually represent state that is changed while hashing @@ -538,8 +550,6 @@ impl PartialEq for BuildHasherDefault { #[stable(since = "1.29.0", feature = "build_hasher_eq")] impl Eq for BuildHasherDefault {} -////////////////////////////////////////////////////////////////////////////// - mod impls { use crate::mem; use crate::slice; diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs index 3b2b28217f9b3..ee4be6c915119 100644 --- a/src/libcore/hint.rs +++ b/src/libcore/hint.rs @@ -49,28 +49,16 @@ pub unsafe fn unreachable_unchecked() -> ! { intrinsics::unreachable() } -/// Signals the processor that it is entering a busy-wait spin-loop. +/// Emits a machine instruction hinting to the processor that it is running in busy-wait +/// spin-loop ("spin lock"). /// -/// Upon receiving spin-loop signal the processor can optimize its behavior by, for example, saving -/// power or switching hyper-threads. -/// -/// This function is different than [`std::thread::yield_now`] which directly yields to the -/// system's scheduler, whereas `spin_loop` only signals the processor that it is entering a -/// busy-wait spin-loop without yielding control to the system's scheduler. -/// -/// Using a busy-wait spin-loop with `spin_loop` is ideally used in situations where a -/// contended lock is held by another thread executed on a different CPU and where the waiting -/// times are relatively small. Because entering busy-wait spin-loop does not trigger the system's -/// scheduler, no overhead for switching threads occurs. However, if the thread holding the -/// contended lock is running on the same CPU, the spin-loop is likely to occupy an entire CPU slice -/// before switching to the thread that holds the lock. If the contending lock is held by a thread -/// on the same CPU or if the waiting times for acquiring the lock are longer, it is often better to -/// use [`std::thread::yield_now`]. +/// For a discussion of different locking strategies and their trade-offs, see +/// [`core::sync::atomic::spin_loop_hint`]. /// /// **Note**: On platforms that do not support receiving spin-loop hints this function does not /// do anything at all. /// -/// [`std::thread::yield_now`]: ../../std/thread/fn.yield_now.html +/// [`core::sync::atomic::spin_loop_hint`]: ../sync/atomic/fn.spin_loop_hint.html #[inline] #[unstable(feature = "renamed_spin_loop", issue = "55002")] pub fn spin_loop() { @@ -104,11 +92,19 @@ pub fn spin_loop() { } } -/// A function that is opaque to the optimizer, to allow benchmarks to -/// pretend to use outputs to assist in avoiding dead-code -/// elimination. +/// An identity function that *__hints__* to the compiler to be maximally pessimistic about what +/// `black_box` could do. +/// +/// [`std::convert::identity`]: https://doc.rust-lang.org/core/convert/fn.identity.html +/// +/// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can +/// use `x` in any possible valid way that Rust code is allowed to without introducing undefined +/// behavior in the calling code. This property makes `black_box` useful for writing code in which +/// certain optimizations are not desired, such as benchmarks. /// -/// This function is a no-op, and does not even read from `dummy`. +/// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The +/// extent to which it can block optimisations may vary depending upon the platform and code-gen +/// backend used. Programs cannot rely on `black_box` for *correctness* in any way. #[inline] #[unstable(feature = "test", issue = "50297")] #[allow(unreachable_code)] // this makes #[cfg] a bit easier below. diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 56e45c3695f61..b240d059114eb 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -707,11 +707,26 @@ extern "rust-intrinsic" { they should be used through stabilized interfaces \ in the rest of the standard library", issue = "0")] - #[rustc_deprecated(reason = "no longer used by rustc, will be removed - use MaybeUninit \ - instead", + #[rustc_deprecated(reason = "superseded by MaybeUninit, removal planned", since = "1.38.0")] pub fn init() -> T; + /// Creates an uninitialized value. + /// + /// `uninit` is unsafe because there is no guarantee of what its + /// contents are. In particular its drop-flag may be set to any + /// state, which means it may claim either dropped or + /// undropped. In the general case one must use `ptr::write` to + /// initialize memory previous set to the result of `uninit`. + #[unstable(feature = "core_intrinsics", + reason = "intrinsics are unlikely to ever be stabilized, instead \ + they should be used through stabilized interfaces \ + in the rest of the standard library", + issue = "0")] + #[rustc_deprecated(reason = "superseded by MaybeUninit, removal planned", + since = "1.38.0")] + pub fn uninit() -> T; + /// Moves a value out of scope without running drop glue. pub fn forget(_: T); @@ -830,21 +845,26 @@ extern "rust-intrinsic" { /// /// ``` /// let store = [0, 1, 2, 3]; - /// let mut v_orig = store.iter().collect::>(); + /// let v_orig = store.iter().collect::>(); + /// + /// // clone the vector as we will reuse them later + /// let v_clone = v_orig.clone(); /// /// // Using transmute: this is Undefined Behavior, and a bad idea. /// // However, it is no-copy. /// let v_transmuted = unsafe { - /// std::mem::transmute::, Vec>>( - /// v_orig.clone()) + /// std::mem::transmute::, Vec>>(v_clone) /// }; /// + /// let v_clone = v_orig.clone(); + /// /// // This is the suggested, safe way. /// // It does copy the entire vector, though, into a new array. - /// let v_collected = v_orig.clone() - /// .into_iter() - /// .map(|r| Some(r)) - /// .collect::>>(); + /// let v_collected = v_clone.into_iter() + /// .map(Some) + /// .collect::>>(); + /// + /// let v_clone = v_orig.clone(); /// /// // The no-copy, unsafe way, still using transmute, but not UB. /// // This is equivalent to the original, but safer, and reuses the @@ -854,11 +874,12 @@ extern "rust-intrinsic" { /// // the original inner type (`&i32`) to the converted inner type /// // (`Option<&i32>`), so read the nomicon pages linked above. /// let v_from_raw = unsafe { - /// Vec::from_raw_parts(v_orig.as_mut_ptr() as *mut Option<&i32>, - /// v_orig.len(), - /// v_orig.capacity()) + /// // Ensure the original vector is not dropped. + /// let mut v_clone = std::mem::ManuallyDrop::new(v_clone); + /// Vec::from_raw_parts(v_clone.as_mut_ptr() as *mut Option<&i32>, + /// v_clone.len(), + /// v_clone.capacity()) /// }; - /// std::mem::forget(v_orig); /// ``` /// /// Implementing `split_at_mut`: @@ -1278,17 +1299,17 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_add` method. For example, /// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add) - pub fn overflowing_add(a: T, b: T) -> T; + pub fn wrapping_add(a: T, b: T) -> T; /// Returns (a - b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_sub` method. For example, /// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub) - pub fn overflowing_sub(a: T, b: T) -> T; + pub fn wrapping_sub(a: T, b: T) -> T; /// Returns (a * b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_mul` method. For example, /// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul) - pub fn overflowing_mul(a: T, b: T) -> T; + pub fn wrapping_mul(a: T, b: T) -> T; /// Computes `a + b`, while saturating at numeric bounds. /// The stabilized versions of this intrinsic are available on the integer diff --git a/src/libcore/iter/adapters/chain.rs b/src/libcore/iter/adapters/chain.rs index 76239ebc0abaf..c9612596b1ba0 100644 --- a/src/libcore/iter/adapters/chain.rs +++ b/src/libcore/iter/adapters/chain.rs @@ -173,17 +173,23 @@ impl Iterator for Chain where #[inline] fn size_hint(&self) -> (usize, Option) { - let (a_lower, a_upper) = self.a.size_hint(); - let (b_lower, b_upper) = self.b.size_hint(); + match self.state { + ChainState::Both => { + let (a_lower, a_upper) = self.a.size_hint(); + let (b_lower, b_upper) = self.b.size_hint(); - let lower = a_lower.saturating_add(b_lower); + let lower = a_lower.saturating_add(b_lower); - let upper = match (a_upper, b_upper) { - (Some(x), Some(y)) => x.checked_add(y), - _ => None - }; + let upper = match (a_upper, b_upper) { + (Some(x), Some(y)) => x.checked_add(y), + _ => None + }; - (lower, upper) + (lower, upper) + } + ChainState::Front => self.a.size_hint(), + ChainState::Back => self.b.size_hint(), + } } } @@ -207,6 +213,29 @@ impl DoubleEndedIterator for Chain where } } + #[inline] + fn nth_back(&mut self, mut n: usize) -> Option { + match self.state { + ChainState::Both | ChainState::Back => { + for x in self.b.by_ref().rev() { + if n == 0 { + return Some(x) + } + n -= 1; + } + if let ChainState::Both = self.state { + self.state = ChainState::Front; + } + } + ChainState::Front => {} + } + if let ChainState::Front = self.state { + self.a.nth_back(n) + } else { + None + } + } + fn try_rfold(&mut self, init: Acc, mut f: F) -> R where Self: Sized, F: FnMut(Acc, Self::Item) -> R, R: Try { diff --git a/src/libcore/iter/adapters/flatten.rs b/src/libcore/iter/adapters/flatten.rs index 8c2aae477bf2a..a45173f614ded 100644 --- a/src/libcore/iter/adapters/flatten.rs +++ b/src/libcore/iter/adapters/flatten.rs @@ -24,15 +24,17 @@ impl U> FlatMap { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for FlatMap - where ::IntoIter: Clone +impl Clone for FlatMap +where + U: Clone + IntoIterator, { fn clone(&self) -> Self { FlatMap { inner: self.inner.clone() } } } #[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for FlatMap - where U::IntoIter: fmt::Debug +impl fmt::Debug for FlatMap +where + U: IntoIterator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FlatMap").field("inner", &self.inner).finish() @@ -68,9 +70,9 @@ impl Iterator for FlatMap #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for FlatMap - where F: FnMut(I::Item) -> U, - U: IntoIterator, - U::IntoIter: DoubleEndedIterator +where + F: FnMut(I::Item) -> U, + U: IntoIterator, { #[inline] fn next_back(&mut self) -> Option { self.inner.next_back() } @@ -104,12 +106,11 @@ impl FusedIterator for FlatMap /// [`Iterator`]: trait.Iterator.html #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "iterator_flatten", since = "1.29.0")] -pub struct Flatten -where I::Item: IntoIterator { +pub struct Flatten> { inner: FlattenCompat::IntoIter>, } -impl Flatten -where I::Item: IntoIterator { + +impl> Flatten { pub(in super::super) fn new(iter: I) -> Flatten { Flatten { inner: FlattenCompat::new(iter) } } @@ -117,8 +118,9 @@ where I::Item: IntoIterator { #[stable(feature = "iterator_flatten", since = "1.29.0")] impl fmt::Debug for Flatten - where I: Iterator + fmt::Debug, U: Iterator + fmt::Debug, - I::Item: IntoIterator, +where + I: fmt::Debug + Iterator>, + U: fmt::Debug + Iterator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Flatten").field("inner", &self.inner).finish() @@ -127,16 +129,18 @@ impl fmt::Debug for Flatten #[stable(feature = "iterator_flatten", since = "1.29.0")] impl Clone for Flatten - where I: Iterator + Clone, U: Iterator + Clone, - I::Item: IntoIterator, +where + I: Clone + Iterator>, + U: Clone + Iterator, { fn clone(&self) -> Self { Flatten { inner: self.inner.clone() } } } #[stable(feature = "iterator_flatten", since = "1.29.0")] impl Iterator for Flatten - where I: Iterator, U: Iterator, - I::Item: IntoIterator +where + I: Iterator>, + U: Iterator, { type Item = U::Item; @@ -163,8 +167,9 @@ impl Iterator for Flatten #[stable(feature = "iterator_flatten", since = "1.29.0")] impl DoubleEndedIterator for Flatten - where I: DoubleEndedIterator, U: DoubleEndedIterator, - I::Item: IntoIterator +where + I: DoubleEndedIterator>, + U: DoubleEndedIterator, { #[inline] fn next_back(&mut self) -> Option { self.inner.next_back() } @@ -186,8 +191,10 @@ impl DoubleEndedIterator for Flatten #[stable(feature = "iterator_flatten", since = "1.29.0")] impl FusedIterator for Flatten - where I: FusedIterator, U: Iterator, - I::Item: IntoIterator {} +where + I: FusedIterator>, + U: Iterator, +{} /// Real logic of both `Flatten` and `FlatMap` which simply delegate to /// this type. @@ -205,8 +212,9 @@ impl FlattenCompat { } impl Iterator for FlattenCompat - where I: Iterator, U: Iterator, - I::Item: IntoIterator +where + I: Iterator>, + U: Iterator, { type Item = U::Item; @@ -217,7 +225,7 @@ impl Iterator for FlattenCompat if let elt@Some(_) = inner.next() { return elt } } match self.iter.next() { - None => return self.backiter.as_mut().and_then(|it| it.next()), + None => return self.backiter.as_mut()?.next(), Some(inner) => self.frontiter = Some(inner.into_iter()), } } @@ -225,8 +233,8 @@ impl Iterator for FlattenCompat #[inline] fn size_hint(&self) -> (usize, Option) { - let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), |it| it.size_hint()); - let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), |it| it.size_hint()); + let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), U::size_hint); + let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), U::size_hint); let lo = flo.saturating_add(blo); match (self.iter.size_hint(), fhi, bhi) { ((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(b)), @@ -238,20 +246,25 @@ impl Iterator for FlattenCompat fn try_fold(&mut self, mut init: Acc, mut fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try { + #[inline] + fn flatten<'a, T: IntoIterator, Acc, R: Try>( + frontiter: &'a mut Option, + fold: &'a mut impl FnMut(Acc, T::Item) -> R, + ) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, x| { + let mut mid = x.into_iter(); + let r = mid.try_fold(acc, &mut *fold); + *frontiter = Some(mid); + r + } + } + if let Some(ref mut front) = self.frontiter { init = front.try_fold(init, &mut fold)?; } self.frontiter = None; - { - let frontiter = &mut self.frontiter; - init = self.iter.try_fold(init, |acc, x| { - let mut mid = x.into_iter(); - let r = mid.try_fold(acc, &mut fold); - *frontiter = Some(mid); - r - })?; - } + init = self.iter.try_fold(init, flatten(&mut self.frontiter, &mut fold))?; self.frontiter = None; if let Some(ref mut back) = self.backiter { @@ -263,19 +276,27 @@ impl Iterator for FlattenCompat } #[inline] - fn fold(self, init: Acc, mut fold: Fold) -> Acc + fn fold(self, init: Acc, ref mut fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { + #[inline] + fn flatten( + fold: &mut impl FnMut(Acc, U::Item) -> Acc, + ) -> impl FnMut(Acc, U) -> Acc + '_ { + move |acc, iter| iter.fold(acc, &mut *fold) + } + self.frontiter.into_iter() .chain(self.iter.map(IntoIterator::into_iter)) .chain(self.backiter) - .fold(init, |acc, iter| iter.fold(acc, &mut fold)) + .fold(init, flatten(fold)) } } impl DoubleEndedIterator for FlattenCompat - where I: DoubleEndedIterator, U: DoubleEndedIterator, - I::Item: IntoIterator +where + I: DoubleEndedIterator>, + U: DoubleEndedIterator, { #[inline] fn next_back(&mut self) -> Option { @@ -284,7 +305,7 @@ impl DoubleEndedIterator for FlattenCompat if let elt@Some(_) = inner.next_back() { return elt } } match self.iter.next_back() { - None => return self.frontiter.as_mut().and_then(|it| it.next_back()), + None => return self.frontiter.as_mut()?.next_back(), next => self.backiter = next.map(IntoIterator::into_iter), } } @@ -294,22 +315,29 @@ impl DoubleEndedIterator for FlattenCompat fn try_rfold(&mut self, mut init: Acc, mut fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try { - if let Some(ref mut back) = self.backiter { - init = back.try_rfold(init, &mut fold)?; - } - self.backiter = None; - + #[inline] + fn flatten<'a, T: IntoIterator, Acc, R: Try>( + backiter: &'a mut Option, + fold: &'a mut impl FnMut(Acc, T::Item) -> R, + ) -> impl FnMut(Acc, T) -> R + 'a where + T::IntoIter: DoubleEndedIterator, { - let backiter = &mut self.backiter; - init = self.iter.try_rfold(init, |acc, x| { + move |acc, x| { let mut mid = x.into_iter(); - let r = mid.try_rfold(acc, &mut fold); + let r = mid.try_rfold(acc, &mut *fold); *backiter = Some(mid); r - })?; + } + } + + if let Some(ref mut back) = self.backiter { + init = back.try_rfold(init, &mut fold)?; } self.backiter = None; + init = self.iter.try_rfold(init, flatten(&mut self.backiter, &mut fold))?; + self.backiter = None; + if let Some(ref mut front) = self.frontiter { init = front.try_rfold(init, &mut fold)?; } @@ -319,12 +347,19 @@ impl DoubleEndedIterator for FlattenCompat } #[inline] - fn rfold(self, init: Acc, mut fold: Fold) -> Acc + fn rfold(self, init: Acc, ref mut fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { + #[inline] + fn flatten( + fold: &mut impl FnMut(Acc, U::Item) -> Acc, + ) -> impl FnMut(Acc, U) -> Acc + '_ { + move |acc, iter| iter.rfold(acc, &mut *fold) + } + self.frontiter.into_iter() .chain(self.iter.map(IntoIterator::into_iter)) .chain(self.backiter) - .rfold(init, |acc, iter| iter.rfold(acc, &mut fold)) + .rfold(init, flatten(fold)) } } diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs index b270290295693..3b8edc2ad6177 100644 --- a/src/libcore/iter/adapters/mod.rs +++ b/src/libcore/iter/adapters/mod.rs @@ -1,11 +1,11 @@ use crate::cmp; use crate::fmt; -use crate::ops::Try; +use crate::ops::{Add, AddAssign, Try}; use crate::usize; use crate::intrinsics; use super::{Iterator, DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen}; -use super::LoopState; +use super::{LoopState, from_fn}; mod chain; mod flatten; @@ -66,13 +66,6 @@ impl Iterator for Rev where I: DoubleEndedIterator { { self.iter.rfind(predicate) } - - #[inline] - fn rposition

(&mut self, predicate: P) -> Option where - P: FnMut(Self::Item) -> bool - { - self.iter.position(predicate) - } } #[stable(feature = "rust1", since = "1.0.0")] @@ -143,6 +136,18 @@ impl Copied { } } +fn copy_fold( + mut f: impl FnMut(Acc, T) -> Acc, +) -> impl FnMut(Acc, &T) -> Acc { + move |acc, &elt| f(acc, elt) +} + +fn copy_try_fold( + mut f: impl FnMut(Acc, T) -> R, +) -> impl FnMut(Acc, &T) -> R { + move |acc, &elt| f(acc, elt) +} + #[stable(feature = "iter_copied", since = "1.36.0")] impl<'a, I, T: 'a> Iterator for Copied where I: Iterator, T: Copy @@ -157,16 +162,16 @@ impl<'a, I, T: 'a> Iterator for Copied self.it.size_hint() } - fn try_fold(&mut self, init: B, mut f: F) -> R where + fn try_fold(&mut self, init: B, f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try { - self.it.try_fold(init, move |acc, &elt| f(acc, elt)) + self.it.try_fold(init, copy_try_fold(f)) } - fn fold(self, init: Acc, mut f: F) -> Acc + fn fold(self, init: Acc, f: F) -> Acc where F: FnMut(Acc, Self::Item) -> Acc, { - self.it.fold(init, move |acc, &elt| f(acc, elt)) + self.it.fold(init, copy_fold(f)) } } @@ -178,16 +183,16 @@ impl<'a, I, T: 'a> DoubleEndedIterator for Copied self.it.next_back().copied() } - fn try_rfold(&mut self, init: B, mut f: F) -> R where + fn try_rfold(&mut self, init: B, f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try { - self.it.try_rfold(init, move |acc, &elt| f(acc, elt)) + self.it.try_rfold(init, copy_try_fold(f)) } - fn rfold(self, init: Acc, mut f: F) -> Acc + fn rfold(self, init: Acc, f: F) -> Acc where F: FnMut(Acc, Self::Item) -> Acc, { - self.it.rfold(init, move |acc, &elt| f(acc, elt)) + self.it.rfold(init, copy_fold(f)) } } @@ -248,6 +253,12 @@ impl Cloned { } } +fn clone_try_fold( + mut f: impl FnMut(Acc, T) -> R, +) -> impl FnMut(Acc, &T) -> R { + move |acc, elt| f(acc, elt.clone()) +} + #[stable(feature = "iter_cloned", since = "1.1.0")] impl<'a, I, T: 'a> Iterator for Cloned where I: Iterator, T: Clone @@ -262,16 +273,16 @@ impl<'a, I, T: 'a> Iterator for Cloned self.it.size_hint() } - fn try_fold(&mut self, init: B, mut f: F) -> R where + fn try_fold(&mut self, init: B, f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try { - self.it.try_fold(init, move |acc, elt| f(acc, elt.clone())) + self.it.try_fold(init, clone_try_fold(f)) } - fn fold(self, init: Acc, mut f: F) -> Acc + fn fold(self, init: Acc, f: F) -> Acc where F: FnMut(Acc, Self::Item) -> Acc, { - self.it.fold(init, move |acc, elt| f(acc, elt.clone())) + self.it.map(T::clone).fold(init, f) } } @@ -283,16 +294,16 @@ impl<'a, I, T: 'a> DoubleEndedIterator for Cloned self.it.next_back().cloned() } - fn try_rfold(&mut self, init: B, mut f: F) -> R where + fn try_rfold(&mut self, init: B, f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try { - self.it.try_rfold(init, move |acc, elt| f(acc, elt.clone())) + self.it.try_rfold(init, clone_try_fold(f)) } - fn rfold(self, init: Acc, mut f: F) -> Acc + fn rfold(self, init: Acc, f: F) -> Acc where F: FnMut(Acc, Self::Item) -> Acc, { - self.it.rfold(init, move |acc, elt| f(acc, elt.clone())) + self.it.map(T::clone).rfold(init, f) } } @@ -387,6 +398,36 @@ impl Iterator for Cycle where I: Clone + Iterator { _ => (usize::MAX, None) } } + + #[inline] + fn try_fold(&mut self, mut acc: Acc, mut f: F) -> R + where + F: FnMut(Acc, Self::Item) -> R, + R: Try, + { + // fully iterate the current iterator. this is necessary because + // `self.iter` may be empty even when `self.orig` isn't + acc = self.iter.try_fold(acc, &mut f)?; + self.iter = self.orig.clone(); + + // complete a full cycle, keeping track of whether the cycled + // iterator is empty or not. we need to return early in case + // of an empty iterator to prevent an infinite loop + let mut is_empty = true; + acc = self.iter.try_fold(acc, |acc, x| { + is_empty = false; + f(acc, x) + })?; + + if is_empty { + return Try::from_ok(acc); + } + + loop { + self.iter = self.orig.clone(); + acc = self.iter.try_fold(acc, &mut f)?; + } + } } #[stable(feature = "fused", since = "1.26.0")] @@ -430,14 +471,24 @@ impl Iterator for StepBy where I: Iterator { #[inline] fn size_hint(&self) -> (usize, Option) { - let inner_hint = self.iter.size_hint(); + #[inline] + fn first_size(step: usize) -> impl Fn(usize) -> usize { + move |n| if n == 0 { 0 } else { 1 + (n - 1) / (step + 1) } + } + + #[inline] + fn other_size(step: usize) -> impl Fn(usize) -> usize { + move |n| n / (step + 1) + } + + let (low, high) = self.iter.size_hint(); if self.first_take { - let f = |n| if n == 0 { 0 } else { 1 + (n-1)/(self.step+1) }; - (f(inner_hint.0), inner_hint.1.map(f)) + let f = first_size(self.step); + (f(low), high.map(f)) } else { - let f = |n| n / (self.step+1); - (f(inner_hint.0), inner_hint.1.map(f)) + let f = other_size(self.step); + (f(low), high.map(f)) } } @@ -483,6 +534,26 @@ impl Iterator for StepBy where I: Iterator { self.iter.nth(nth - 1); } } + + fn try_fold(&mut self, mut acc: Acc, mut f: F) -> R + where + F: FnMut(Acc, Self::Item) -> R, + R: Try, + { + #[inline] + fn nth(iter: &mut I, step: usize) -> impl FnMut() -> Option + '_ { + move || iter.nth(step) + } + + if self.first_take { + self.first_take = false; + match self.iter.next() { + None => return Try::from_ok(acc), + Some(x) => acc = f(acc, x)?, + } + } + from_fn(nth(&mut self.iter, self.step)).try_fold(acc, f) + } } impl StepBy where I: ExactSizeIterator { @@ -516,6 +587,28 @@ impl DoubleEndedIterator for StepBy where I: DoubleEndedIterator + ExactSi .saturating_add(self.next_back_index()); self.iter.nth_back(n) } + + fn try_rfold(&mut self, init: Acc, mut f: F) -> R + where + F: FnMut(Acc, Self::Item) -> R, + R: Try, + { + #[inline] + fn nth_back( + iter: &mut I, + step: usize, + ) -> impl FnMut() -> Option + '_ { + move || iter.nth_back(step) + } + + match self.next_back() { + None => Try::from_ok(init), + Some(x) => { + let acc = f(init, x)?; + from_fn(nth_back(&mut self.iter, self.step)).try_fold(acc, f) + } + } + } } // StepBy can only make the iterator shorter, so the len will still fit. @@ -594,6 +687,20 @@ impl fmt::Debug for Map { } } +fn map_fold( + mut f: impl FnMut(T) -> B, + mut g: impl FnMut(Acc, B) -> Acc, +) -> impl FnMut(Acc, T) -> Acc { + move |acc, elt| g(acc, f(elt)) +} + +fn map_try_fold<'a, T, B, Acc, R>( + f: &'a mut impl FnMut(T) -> B, + mut g: impl FnMut(Acc, B) -> R + 'a, +) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, elt| g(acc, f(elt)) +} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Map where F: FnMut(I::Item) -> B { type Item = B; @@ -608,18 +715,16 @@ impl Iterator for Map where F: FnMut(I::Item) -> B { self.iter.size_hint() } - fn try_fold(&mut self, init: Acc, mut g: G) -> R where + fn try_fold(&mut self, init: Acc, g: G) -> R where Self: Sized, G: FnMut(Acc, Self::Item) -> R, R: Try { - let f = &mut self.f; - self.iter.try_fold(init, move |acc, elt| g(acc, f(elt))) + self.iter.try_fold(init, map_try_fold(&mut self.f, g)) } - fn fold(self, init: Acc, mut g: G) -> Acc + fn fold(self, init: Acc, g: G) -> Acc where G: FnMut(Acc, Self::Item) -> Acc, { - let mut f = self.f; - self.iter.fold(init, move |acc, elt| g(acc, f(elt))) + self.iter.fold(init, map_fold(self.f, g)) } } @@ -632,18 +737,16 @@ impl DoubleEndedIterator for Map where self.iter.next_back().map(&mut self.f) } - fn try_rfold(&mut self, init: Acc, mut g: G) -> R where + fn try_rfold(&mut self, init: Acc, g: G) -> R where Self: Sized, G: FnMut(Acc, Self::Item) -> R, R: Try { - let f = &mut self.f; - self.iter.try_rfold(init, move |acc, elt| g(acc, f(elt))) + self.iter.try_rfold(init, map_try_fold(&mut self.f, g)) } - fn rfold(self, init: Acc, mut g: G) -> Acc + fn rfold(self, init: Acc, g: G) -> Acc where G: FnMut(Acc, Self::Item) -> Acc, { - let mut f = self.f; - self.iter.rfold(init, move |acc, elt| g(acc, f(elt))) + self.iter.rfold(init, map_fold(self.f, g)) } } @@ -710,13 +813,27 @@ impl fmt::Debug for Filter { } } +fn filter_fold( + mut predicate: impl FnMut(&T) -> bool, + mut fold: impl FnMut(Acc, T) -> Acc, +) -> impl FnMut(Acc, T) -> Acc { + move |acc, item| if predicate(&item) { fold(acc, item) } else { acc } +} + +fn filter_try_fold<'a, T, Acc, R: Try>( + predicate: &'a mut impl FnMut(&T) -> bool, + mut fold: impl FnMut(Acc, T) -> R + 'a, +) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, item| if predicate(&item) { fold(acc, item) } else { R::from_ok(acc) } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Filter where P: FnMut(&I::Item) -> bool { type Item = I::Item; #[inline] fn next(&mut self) -> Option { - self.try_for_each(Err).err() + self.iter.find(&mut self.predicate) } #[inline] @@ -738,32 +855,26 @@ impl Iterator for Filter where P: FnMut(&I::Item) -> bool // leaving more budget for LLVM optimizations. #[inline] fn count(self) -> usize { - let mut predicate = self.predicate; - self.iter.map(|x| predicate(&x) as usize).sum() + #[inline] + fn to_usize(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut(T) -> usize { + move |x| predicate(&x) as usize + } + + self.iter.map(to_usize(self.predicate)).sum() } #[inline] - fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where + fn try_fold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try { - let predicate = &mut self.predicate; - self.iter.try_fold(init, move |acc, item| if predicate(&item) { - fold(acc, item) - } else { - Try::from_ok(acc) - }) + self.iter.try_fold(init, filter_try_fold(&mut self.predicate, fold)) } #[inline] - fn fold(self, init: Acc, mut fold: Fold) -> Acc + fn fold(self, init: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - let mut predicate = self.predicate; - self.iter.fold(init, move |acc, item| if predicate(&item) { - fold(acc, item) - } else { - acc - }) + self.iter.fold(init, filter_fold(self.predicate, fold)) } } @@ -773,31 +884,21 @@ impl DoubleEndedIterator for Filter { #[inline] fn next_back(&mut self) -> Option { - self.try_rfold((), |_, x| Err(x)).err() + self.iter.rfind(&mut self.predicate) } #[inline] - fn try_rfold(&mut self, init: Acc, mut fold: Fold) -> R where + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try { - let predicate = &mut self.predicate; - self.iter.try_rfold(init, move |acc, item| if predicate(&item) { - fold(acc, item) - } else { - Try::from_ok(acc) - }) + self.iter.try_rfold(init, filter_try_fold(&mut self.predicate, fold)) } #[inline] - fn rfold(self, init: Acc, mut fold: Fold) -> Acc + fn rfold(self, init: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - let mut predicate = self.predicate; - self.iter.rfold(init, move |acc, item| if predicate(&item) { - fold(acc, item) - } else { - acc - }) + self.iter.rfold(init, filter_fold(self.predicate, fold)) } } @@ -834,6 +935,26 @@ impl fmt::Debug for FilterMap { } } +fn filter_map_fold( + mut f: impl FnMut(T) -> Option, + mut fold: impl FnMut(Acc, B) -> Acc, +) -> impl FnMut(Acc, T) -> Acc { + move |acc, item| match f(item) { + Some(x) => fold(acc, x), + None => acc, + } +} + +fn filter_map_try_fold<'a, T, B, Acc, R: Try>( + f: &'a mut impl FnMut(T) -> Option, + mut fold: impl FnMut(Acc, B) -> R + 'a, +) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, item| match f(item) { + Some(x) => fold(acc, x), + None => R::from_ok(acc), + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for FilterMap where F: FnMut(I::Item) -> Option, @@ -842,7 +963,7 @@ impl Iterator for FilterMap #[inline] fn next(&mut self) -> Option { - self.try_for_each(Err).err() + self.iter.find_map(&mut self.f) } #[inline] @@ -852,25 +973,17 @@ impl Iterator for FilterMap } #[inline] - fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where + fn try_fold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try { - let f = &mut self.f; - self.iter.try_fold(init, move |acc, item| match f(item) { - Some(x) => fold(acc, x), - None => Try::from_ok(acc), - }) + self.iter.try_fold(init, filter_map_try_fold(&mut self.f, fold)) } #[inline] - fn fold(self, init: Acc, mut fold: Fold) -> Acc + fn fold(self, init: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - let mut f = self.f; - self.iter.fold(init, move |acc, item| match f(item) { - Some(x) => fold(acc, x), - None => acc, - }) + self.iter.fold(init, filter_map_fold(self.f, fold)) } } @@ -880,29 +993,31 @@ impl DoubleEndedIterator for FilterMap { #[inline] fn next_back(&mut self) -> Option { - self.try_rfold((), |_, x| Err(x)).err() + #[inline] + fn find( + f: &mut impl FnMut(T) -> Option + ) -> impl FnMut((), T) -> LoopState<(), B> + '_ { + move |(), x| match f(x) { + Some(x) => LoopState::Break(x), + None => LoopState::Continue(()), + } + } + + self.iter.try_rfold((), find(&mut self.f)).break_value() } #[inline] - fn try_rfold(&mut self, init: Acc, mut fold: Fold) -> R where + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try { - let f = &mut self.f; - self.iter.try_rfold(init, move |acc, item| match f(item) { - Some(x) => fold(acc, x), - None => Try::from_ok(acc), - }) + self.iter.try_rfold(init, filter_map_try_fold(&mut self.f, fold)) } #[inline] - fn rfold(self, init: Acc, mut fold: Fold) -> Acc + fn rfold(self, init: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - let mut f = self.f; - self.iter.rfold(init, move |acc, item| match f(item) { - Some(x) => fold(acc, x), - None => acc, - }) + self.iter.rfold(init, filter_map_fold(self.f, fold)) } } @@ -944,14 +1059,12 @@ impl Iterator for Enumerate where I: Iterator { /// /// Might panic if the index of the element overflows a `usize`. #[inline] - #[rustc_inherit_overflow_checks] fn next(&mut self) -> Option<(usize, ::Item)> { - self.iter.next().map(|a| { - let ret = (self.count, a); - // Possible undefined overflow. - self.count += 1; - ret - }) + let a = self.iter.next()?; + let i = self.count; + // Possible undefined overflow. + AddAssign::add_assign(&mut self.count, 1); + Some((i, a)) } #[inline] @@ -960,13 +1073,12 @@ impl Iterator for Enumerate where I: Iterator { } #[inline] - #[rustc_inherit_overflow_checks] fn nth(&mut self, n: usize) -> Option<(usize, I::Item)> { - self.iter.nth(n).map(|a| { - let i = self.count + n; - self.count = i + 1; - (i, a) - }) + let a = self.iter.nth(n)?; + // Possible undefined overflow. + let i = Add::add(self.count, n); + self.count = Add::add(i, 1); + Some((i, a)) } #[inline] @@ -975,29 +1087,43 @@ impl Iterator for Enumerate where I: Iterator { } #[inline] - #[rustc_inherit_overflow_checks] - fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where + fn try_fold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try { - let count = &mut self.count; - self.iter.try_fold(init, move |acc, item| { - let acc = fold(acc, (*count, item)); - *count += 1; - acc - }) + #[inline] + fn enumerate<'a, T, Acc, R>( + count: &'a mut usize, + mut fold: impl FnMut(Acc, (usize, T)) -> R + 'a, + ) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, item| { + let acc = fold(acc, (*count, item)); + // Possible undefined overflow. + AddAssign::add_assign(count, 1); + acc + } + } + + self.iter.try_fold(init, enumerate(&mut self.count, fold)) } #[inline] - #[rustc_inherit_overflow_checks] - fn fold(self, init: Acc, mut fold: Fold) -> Acc + fn fold(self, init: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - let mut count = self.count; - self.iter.fold(init, move |acc, item| { - let acc = fold(acc, (count, item)); - count += 1; - acc - }) + #[inline] + fn enumerate( + mut count: usize, + mut fold: impl FnMut(Acc, (usize, T)) -> Acc, + ) -> impl FnMut(Acc, T) -> Acc { + move |acc, item| { + let acc = fold(acc, (count, item)); + // Possible undefined overflow. + AddAssign::add_assign(&mut count, 1); + acc + } + } + + self.iter.fold(init, enumerate(self.count, fold)) } } @@ -1007,48 +1133,60 @@ impl DoubleEndedIterator for Enumerate where { #[inline] fn next_back(&mut self) -> Option<(usize, ::Item)> { - self.iter.next_back().map(|a| { - let len = self.iter.len(); - // Can safely add, `ExactSizeIterator` promises that the number of - // elements fits into a `usize`. - (self.count + len, a) - }) + let a = self.iter.next_back()?; + let len = self.iter.len(); + // Can safely add, `ExactSizeIterator` promises that the number of + // elements fits into a `usize`. + Some((self.count + len, a)) } #[inline] fn nth_back(&mut self, n: usize) -> Option<(usize, ::Item)> { - self.iter.nth_back(n).map(|a| { - let len = self.iter.len(); - // Can safely add, `ExactSizeIterator` promises that the number of - // elements fits into a `usize`. - (self.count + len, a) - }) + let a = self.iter.nth_back(n)?; + let len = self.iter.len(); + // Can safely add, `ExactSizeIterator` promises that the number of + // elements fits into a `usize`. + Some((self.count + len, a)) } #[inline] - fn try_rfold(&mut self, init: Acc, mut fold: Fold) -> R where + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try { // Can safely add and subtract the count, as `ExactSizeIterator` promises // that the number of elements fits into a `usize`. - let mut count = self.count + self.iter.len(); - self.iter.try_rfold(init, move |acc, item| { - count -= 1; - fold(acc, (count, item)) - }) + fn enumerate( + mut count: usize, + mut fold: impl FnMut(Acc, (usize, T)) -> R, + ) -> impl FnMut(Acc, T) -> R { + move |acc, item| { + count -= 1; + fold(acc, (count, item)) + } + } + + let count = self.count + self.iter.len(); + self.iter.try_rfold(init, enumerate(count, fold)) } #[inline] - fn rfold(self, init: Acc, mut fold: Fold) -> Acc + fn rfold(self, init: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { // Can safely add and subtract the count, as `ExactSizeIterator` promises // that the number of elements fits into a `usize`. - let mut count = self.count + self.iter.len(); - self.iter.rfold(init, move |acc, item| { - count -= 1; - fold(acc, (count, item)) - }) + fn enumerate( + mut count: usize, + mut fold: impl FnMut(Acc, (usize, T)) -> Acc, + ) -> impl FnMut(Acc, T) -> Acc { + move |acc, item| { + count -= 1; + fold(acc, (count, item)) + } + } + + let count = self.count + self.iter.len(); + self.iter.rfold(init, enumerate(count, fold)) } } @@ -1162,7 +1300,10 @@ impl Iterator for Peekable { }; let (lo, hi) = self.iter.size_hint(); let lo = lo.saturating_add(peek_len); - let hi = hi.and_then(|x| x.checked_add(peek_len)); + let hi = match hi { + Some(x) => x.checked_add(peek_len), + None => None, + }; (lo, hi) } @@ -1203,7 +1344,7 @@ impl DoubleEndedIterator for Peekable where I: DoubleEndedIterator { Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try { match self.peeked.take() { - Some(None) => return Try::from_ok(init), + Some(None) => Try::from_ok(init), Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() { Ok(acc) => f(acc, v), Err(e) => { @@ -1220,7 +1361,7 @@ impl DoubleEndedIterator for Peekable where I: DoubleEndedIterator { where Fold: FnMut(Acc, Self::Item) -> Acc, { match self.peeked { - Some(None) => return init, + Some(None) => init, Some(Some(v)) => { let acc = self.iter.rfold(init, &mut fold); fold(acc, v) @@ -1321,16 +1462,23 @@ impl Iterator for SkipWhile #[inline] fn next(&mut self) -> Option { + fn check<'a, T>( + flag: &'a mut bool, + pred: &'a mut impl FnMut(&T) -> bool, + ) -> impl FnMut(&T) -> bool + 'a { + move |x| { + if *flag || !pred(x) { + *flag = true; + true + } else { + false + } + } + } + let flag = &mut self.flag; let pred = &mut self.predicate; - self.iter.find(move |x| { - if *flag || !pred(x) { - *flag = true; - true - } else { - false - } - }) + self.iter.find(check(flag, pred)) } #[inline] @@ -1412,14 +1560,13 @@ impl Iterator for TakeWhile if self.flag { None } else { - self.iter.next().and_then(|x| { - if (self.predicate)(&x) { - Some(x) - } else { - self.flag = true; - None - } - }) + let x = self.iter.next()?; + if (self.predicate)(&x) { + Some(x) + } else { + self.flag = true; + None + } } } @@ -1434,22 +1581,30 @@ impl Iterator for TakeWhile } #[inline] - fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where + fn try_fold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try { - if self.flag { - Try::from_ok(init) - } else { - let flag = &mut self.flag; - let p = &mut self.predicate; - self.iter.try_fold(init, move |acc, x|{ + fn check<'a, T, Acc, R: Try>( + flag: &'a mut bool, + p: &'a mut impl FnMut(&T) -> bool, + mut fold: impl FnMut(Acc, T) -> R + 'a, + ) -> impl FnMut(Acc, T) -> LoopState + 'a { + move |acc, x| { if p(&x) { LoopState::from_try(fold(acc, x)) } else { *flag = true; LoopState::Break(Try::from_ok(acc)) } - }).into_try() + } + } + + if self.flag { + Try::from_ok(init) + } else { + let flag = &mut self.flag; + let p = &mut self.predicate; + self.iter.try_fold(init, check(flag, p, fold)).into_try() } } } @@ -1534,7 +1689,10 @@ impl Iterator for Skip where I: Iterator { let (lower, upper) = self.iter.size_hint(); let lower = lower.saturating_sub(self.n); - let upper = upper.map(|x| x.saturating_sub(self.n)); + let upper = match upper { + Some(x) => Some(x.saturating_sub(self.n)), + None => None, + }; (lower, upper) } @@ -1595,19 +1753,26 @@ impl DoubleEndedIterator for Skip where I: DoubleEndedIterator + ExactSize } } - fn try_rfold(&mut self, init: Acc, mut fold: Fold) -> R where + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try { - let mut n = self.len(); - if n == 0 { - Try::from_ok(init) - } else { - self.iter.try_rfold(init, move |acc, x| { + fn check>( + mut n: usize, + mut fold: impl FnMut(Acc, T) -> R, + ) -> impl FnMut(Acc, T) -> LoopState { + move |acc, x| { n -= 1; let r = fold(acc, x); if n == 0 { LoopState::Break(r) } else { LoopState::from_try(r) } - }).into_try() + } + } + + let n = self.len(); + if n == 0 { + Try::from_ok(init) + } else { + self.iter.try_rfold(init, check(n, fold)).into_try() } } } @@ -1682,19 +1847,26 @@ impl Iterator for Take where I: Iterator{ } #[inline] - fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where + fn try_fold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try { - if self.n == 0 { - Try::from_ok(init) - } else { - let n = &mut self.n; - self.iter.try_fold(init, move |acc, x| { + fn check<'a, T, Acc, R: Try>( + n: &'a mut usize, + mut fold: impl FnMut(Acc, T) -> R + 'a, + ) -> impl FnMut(Acc, T) -> LoopState + 'a { + move |acc, x| { *n -= 1; let r = fold(acc, x); if *n == 0 { LoopState::Break(r) } else { LoopState::from_try(r) } - }).into_try() + } + } + + if self.n == 0 { + Try::from_ok(init) + } else { + let n = &mut self.n; + self.iter.try_fold(init, check(n, fold)).into_try() } } } @@ -1793,7 +1965,8 @@ impl Iterator for Scan where #[inline] fn next(&mut self) -> Option { - self.iter.next().and_then(|a| (self.f)(&mut self.state, a)) + let a = self.iter.next()?; + (self.f)(&mut self.state, a) } #[inline] @@ -1803,17 +1976,25 @@ impl Iterator for Scan where } #[inline] - fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where + fn try_fold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try { + fn scan<'a, T, St, B, Acc, R: Try>( + state: &'a mut St, + f: &'a mut impl FnMut(&mut St, T) -> Option, + mut fold: impl FnMut(Acc, B) -> R + 'a, + ) -> impl FnMut(Acc, T) -> LoopState + 'a { + move |acc, x| { + match f(state, x) { + None => LoopState::Break(Try::from_ok(acc)), + Some(x) => LoopState::from_try(fold(acc, x)), + } + } + } + let state = &mut self.state; let f = &mut self.f; - self.iter.try_fold(init, move |acc, x| { - match f(state, x) { - None => LoopState::Break(Try::from_ok(acc)), - Some(x) => LoopState::from_try(fold(acc, x)), - } - }).into_try() + self.iter.try_fold(init, scan(state, f, fold)).into_try() } } @@ -2104,6 +2285,20 @@ impl Inspect where F: FnMut(&I::Item) { } } +fn inspect_fold( + mut f: impl FnMut(&T), + mut fold: impl FnMut(Acc, T) -> Acc, +) -> impl FnMut(Acc, T) -> Acc { + move |acc, item| { f(&item); fold(acc, item) } +} + +fn inspect_try_fold<'a, T, Acc, R>( + f: &'a mut impl FnMut(&T), + mut fold: impl FnMut(Acc, T) -> R + 'a, +) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, item| { f(&item); fold(acc, item) } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Inspect where F: FnMut(&I::Item) { type Item = I::Item; @@ -2120,19 +2315,17 @@ impl Iterator for Inspect where F: FnMut(&I::Item) { } #[inline] - fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where + fn try_fold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try { - let f = &mut self.f; - self.iter.try_fold(init, move |acc, item| { f(&item); fold(acc, item) }) + self.iter.try_fold(init, inspect_try_fold(&mut self.f, fold)) } #[inline] - fn fold(self, init: Acc, mut fold: Fold) -> Acc + fn fold(self, init: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - let mut f = self.f; - self.iter.fold(init, move |acc, item| { f(&item); fold(acc, item) }) + self.iter.fold(init, inspect_fold(self.f, fold)) } } @@ -2147,19 +2340,17 @@ impl DoubleEndedIterator for Inspect } #[inline] - fn try_rfold(&mut self, init: Acc, mut fold: Fold) -> R where + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try { - let f = &mut self.f; - self.iter.try_rfold(init, move |acc, item| { f(&item); fold(acc, item) }) + self.iter.try_rfold(init, inspect_try_fold(&mut self.f, fold)) } #[inline] - fn rfold(self, init: Acc, mut fold: Fold) -> Acc + fn rfold(self, init: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - let mut f = self.f; - self.iter.rfold(init, move |acc, item| { f(&item); fold(acc, item) }) + self.iter.rfold(init, inspect_fold(self.f, fold)) } } diff --git a/src/libcore/iter/adapters/zip.rs b/src/libcore/iter/adapters/zip.rs index 06f047d92872e..430ceacdd9fab 100644 --- a/src/libcore/iter/adapters/zip.rs +++ b/src/libcore/iter/adapters/zip.rs @@ -94,11 +94,9 @@ impl ZipImpl for Zip #[inline] default fn next(&mut self) -> Option<(A::Item, B::Item)> { - self.a.next().and_then(|x| { - self.b.next().and_then(|y| { - Some((x, y)) - }) - }) + let x = self.a.next()?; + let y = self.b.next()?; + Some((x, y)) } #[inline] diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 70a3b70c180dc..183176005ede9 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -394,7 +394,8 @@ impl A> Iterator for OnceWith { #[inline] fn next(&mut self) -> Option { - self.gen.take().map(|f| f()) + let f = self.gen.take()?; + Some(f()) } #[inline] @@ -608,10 +609,9 @@ impl Iterator for Successors #[inline] fn next(&mut self) -> Option { - self.next.take().map(|item| { - self.next = (self.succ)(&item); - item - }) + let item = self.next.take()?; + self.next = (self.succ)(&item); + Some(item) } #[inline] diff --git a/src/libcore/iter/traits/accum.rs b/src/libcore/iter/traits/accum.rs index 812463e77f976..818f03303298f 100644 --- a/src/libcore/iter/traits/accum.rs +++ b/src/libcore/iter/traits/accum.rs @@ -85,28 +85,28 @@ macro_rules! float_sum_product { #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Sum for $a { fn sum>(iter: I) -> $a { - iter.fold(0.0, |a, b| a + b) + iter.fold(0.0, Add::add) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Product for $a { fn product>(iter: I) -> $a { - iter.fold(1.0, |a, b| a * b) + iter.fold(1.0, Mul::mul) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Sum<&'a $a> for $a { fn sum>(iter: I) -> $a { - iter.fold(0.0, |a, b| a + *b) + iter.fold(0.0, Add::add) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Product<&'a $a> for $a { fn product>(iter: I) -> $a { - iter.fold(1.0, |a, b| a * *b) + iter.fold(1.0, Mul::mul) } } )*) diff --git a/src/libcore/iter/traits/collect.rs b/src/libcore/iter/traits/collect.rs index 1865160bc3cf4..25439136b8538 100644 --- a/src/libcore/iter/traits/collect.rs +++ b/src/libcore/iter/traits/collect.rs @@ -195,8 +195,9 @@ pub trait FromIterator: Sized { /// /// ```rust /// fn collect_as_strings(collection: T) -> Vec -/// where T: IntoIterator, -/// T::Item: std::fmt::Debug, +/// where +/// T: IntoIterator, +/// T::Item: std::fmt::Debug, /// { /// collection /// .into_iter() diff --git a/src/libcore/iter/traits/double_ended.rs b/src/libcore/iter/traits/double_ended.rs index 2c1aeb5690a58..006b243ca42aa 100644 --- a/src/libcore/iter/traits/double_ended.rs +++ b/src/libcore/iter/traits/double_ended.rs @@ -69,7 +69,7 @@ pub trait DoubleEndedIterator: Iterator { /// Returns the `n`th element from the end of the iterator. /// /// This is essentially the reversed version of [`nth`]. Although like most indexing - /// operations, the count starts from zero, so `nth_back(0)` returns the first value fro + /// operations, the count starts from zero, so `nth_back(0)` returns the first value from /// the end, `nth_back(1)` the second, and so on. /// /// Note that all elements between the end and the returned element will be @@ -219,12 +219,17 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iter_rfold", since = "1.27.0")] - fn rfold(mut self, accum: B, mut f: F) -> B + fn rfold(mut self, accum: B, f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { - self.try_rfold(accum, move |acc, x| Ok::(f(acc, x))).unwrap() + #[inline] + fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { + move |acc, x| Ok(f(acc, x)) + } + + self.try_rfold(accum, ok(f)).unwrap() } /// Searches for an element of an iterator from the back that satisfies a predicate. @@ -271,15 +276,21 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iter_rfind", since = "1.27.0")] - fn rfind

(&mut self, mut predicate: P) -> Option + fn rfind

(&mut self, predicate: P) -> Option where Self: Sized, P: FnMut(&Self::Item) -> bool { - self.try_rfold((), move |(), x| { - if predicate(&x) { LoopState::Break(x) } - else { LoopState::Continue(()) } - }).break_value() + #[inline] + fn check( + mut predicate: impl FnMut(&T) -> bool, + ) -> impl FnMut((), T) -> LoopState<(), T> { + move |(), x| { + if predicate(&x) { LoopState::Break(x) } else { LoopState::Continue(()) } + } + } + + self.try_rfold((), check(predicate)).break_value() } } diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index 7e941267ce824..a272035150a15 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -1,5 +1,5 @@ -use crate::cmp::Ordering; -use crate::ops::Try; +use crate::cmp::{self, Ordering}; +use crate::ops::{Add, Try}; use super::super::LoopState; use super::super::{Chain, Cycle, Copied, Cloned, Enumerate, Filter, FilterMap, Fuse}; @@ -234,11 +234,15 @@ pub trait Iterator { /// assert_eq!(a.iter().count(), 5); /// ``` #[inline] - #[rustc_inherit_overflow_checks] #[stable(feature = "rust1", since = "1.0.0")] fn count(self) -> usize where Self: Sized { - // Might overflow. - self.fold(0, |cnt, _| cnt + 1) + #[inline] + fn add1(count: usize, _: T) -> usize { + // Might overflow. + Add::add(count, 1) + } + + self.fold(0, add1) } /// Consumes the iterator, returning the last element. @@ -263,7 +267,12 @@ pub trait Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn last(self) -> Option where Self: Sized { - self.fold(None, |_, x| Some(x)) + #[inline] + fn some(_: Option, x: T) -> Option { + Some(x) + } + + self.fold(None, some) } /// Returns the `n`th element of the iterator. @@ -596,10 +605,15 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_for_each", since = "1.21.0")] - fn for_each(self, mut f: F) where + fn for_each(self, f: F) where Self: Sized, F: FnMut(Self::Item), { - self.fold((), move |(), item| f(item)); + #[inline] + fn call(mut f: impl FnMut(T)) -> impl FnMut((), T) { + move |(), item| f(item) + } + + self.fold((), call(f)); } /// Creates an iterator which uses a closure to determine if an element @@ -1490,21 +1504,30 @@ pub trait Iterator { /// assert_eq!(odd, vec![1, 3]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - fn partition(self, mut f: F) -> (B, B) where + fn partition(self, f: F) -> (B, B) where Self: Sized, B: Default + Extend, F: FnMut(&Self::Item) -> bool { + #[inline] + fn extend<'a, T, B: Extend>( + mut f: impl FnMut(&T) -> bool + 'a, + left: &'a mut B, + right: &'a mut B, + ) -> impl FnMut(T) + 'a { + move |x| { + if f(&x) { + left.extend(Some(x)); + } else { + right.extend(Some(x)); + } + } + } + let mut left: B = Default::default(); let mut right: B = Default::default(); - self.for_each(|x| { - if f(&x) { - left.extend(Some(x)) - } else { - right.extend(Some(x)) - } - }); + self.for_each(extend(f, &mut left, &mut right)); (left, right) } @@ -1702,10 +1725,15 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_try_fold", since = "1.27.0")] - fn try_for_each(&mut self, mut f: F) -> R where + fn try_for_each(&mut self, f: F) -> R where Self: Sized, F: FnMut(Self::Item) -> R, R: Try { - self.try_fold((), move |(), x| f(x)) + #[inline] + fn call(mut f: impl FnMut(T) -> R) -> impl FnMut((), T) -> R { + move |(), x| f(x) + } + + self.try_fold((), call(f)) } /// An iterator method that applies a function, producing a single, final value. @@ -1777,10 +1805,15 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn fold(mut self, init: B, mut f: F) -> B where + fn fold(mut self, init: B, f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { - self.try_fold(init, move |acc, x| Ok::(f(acc, x))).unwrap() + #[inline] + fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { + move |acc, x| Ok(f(acc, x)) + } + + self.try_fold(init, ok(f)).unwrap() } /// Tests if every element of the iterator matches a predicate. @@ -1822,13 +1855,17 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn all(&mut self, mut f: F) -> bool where + fn all(&mut self, f: F) -> bool where Self: Sized, F: FnMut(Self::Item) -> bool { - self.try_for_each(move |x| { - if f(x) { LoopState::Continue(()) } - else { LoopState::Break(()) } - }) == LoopState::Continue(()) + #[inline] + fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> LoopState<(), ()> { + move |(), x| { + if f(x) { LoopState::Continue(()) } + else { LoopState::Break(()) } + } + } + self.try_fold((), check(f)) == LoopState::Continue(()) } /// Tests if any element of the iterator matches a predicate. @@ -1870,14 +1907,19 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn any(&mut self, mut f: F) -> bool where + fn any(&mut self, f: F) -> bool where Self: Sized, F: FnMut(Self::Item) -> bool { - self.try_for_each(move |x| { - if f(x) { LoopState::Break(()) } - else { LoopState::Continue(()) } - }) == LoopState::Break(()) + #[inline] + fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> LoopState<(), ()> { + move |(), x| { + if f(x) { LoopState::Break(()) } + else { LoopState::Continue(()) } + } + } + + self.try_fold((), check(f)) == LoopState::Break(()) } /// Searches for an element of an iterator that satisfies a predicate. @@ -1924,14 +1966,21 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn find

(&mut self, mut predicate: P) -> Option where + fn find

(&mut self, predicate: P) -> Option where Self: Sized, P: FnMut(&Self::Item) -> bool, { - self.try_for_each(move |x| { - if predicate(&x) { LoopState::Break(x) } - else { LoopState::Continue(()) } - }).break_value() + #[inline] + fn check( + mut predicate: impl FnMut(&T) -> bool + ) -> impl FnMut((), T) -> LoopState<(), T> { + move |(), x| { + if predicate(&x) { LoopState::Break(x) } + else { LoopState::Continue(()) } + } + } + + self.try_fold((), check(predicate)).break_value() } /// Applies function to the elements of iterator and returns @@ -1951,16 +2000,19 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_find_map", since = "1.30.0")] - fn find_map(&mut self, mut f: F) -> Option where + fn find_map(&mut self, f: F) -> Option where Self: Sized, F: FnMut(Self::Item) -> Option, { - self.try_for_each(move |x| { - match f(x) { + #[inline] + fn check(mut f: impl FnMut(T) -> Option) -> impl FnMut((), T) -> LoopState<(), B> { + move |(), x| match f(x) { Some(x) => LoopState::Break(x), None => LoopState::Continue(()), } - }).break_value() + } + + self.try_fold((), check(f)).break_value() } /// Searches for an element in an iterator, returning its index. @@ -2018,17 +2070,23 @@ pub trait Iterator { /// /// ``` #[inline] - #[rustc_inherit_overflow_checks] #[stable(feature = "rust1", since = "1.0.0")] - fn position

(&mut self, mut predicate: P) -> Option where + fn position

(&mut self, predicate: P) -> Option where Self: Sized, P: FnMut(Self::Item) -> bool, { - // The addition might panic on overflow - self.try_fold(0, move |i, x| { - if predicate(x) { LoopState::Break(i) } - else { LoopState::Continue(i + 1) } - }).break_value() + #[inline] + fn check( + mut predicate: impl FnMut(T) -> bool, + ) -> impl FnMut(usize, T) -> LoopState { + // The addition might panic on overflow + move |i, x| { + if predicate(x) { LoopState::Break(i) } + else { LoopState::Continue(Add::add(i, 1)) } + } + } + + self.try_fold(0, check(predicate)).break_value() } /// Searches for an element in an iterator from the right, returning its @@ -2071,18 +2129,25 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn rposition

(&mut self, mut predicate: P) -> Option where + fn rposition

(&mut self, predicate: P) -> Option where P: FnMut(Self::Item) -> bool, Self: Sized + ExactSizeIterator + DoubleEndedIterator { // No need for an overflow check here, because `ExactSizeIterator` // implies that the number of elements fits into a `usize`. + #[inline] + fn check( + mut predicate: impl FnMut(T) -> bool, + ) -> impl FnMut(usize, T) -> LoopState { + move |i, x| { + let i = i - 1; + if predicate(x) { LoopState::Break(i) } + else { LoopState::Continue(i) } + } + } + let n = self.len(); - self.try_rfold(n, move |i, x| { - let i = i - 1; - if predicate(x) { LoopState::Break(i) } - else { LoopState::Continue(i) } - }).break_value() + self.try_rfold(n, check(predicate)).break_value() } /// Returns the maximum element of an iterator. @@ -2151,11 +2216,21 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_cmp_by_key", since = "1.6.0")] - fn max_by_key(self, mut f: F) -> Option + fn max_by_key(self, f: F) -> Option where Self: Sized, F: FnMut(&Self::Item) -> B, { - // switch to y even if it is only equal, to preserve stability. - select_fold1(self.map(|x| (f(&x), x)), |(x_p, _), (y_p, _)| x_p <= y_p).map(|(_, x)| x) + #[inline] + fn key(mut f: impl FnMut(&T) -> B) -> impl FnMut(T) -> (B, T) { + move |x| (f(&x), x) + } + + #[inline] + fn compare((x_p, _): &(B, T), (y_p, _): &(B, T)) -> Ordering { + x_p.cmp(y_p) + } + + let (_, x) = self.map(key(f)).max_by(compare)?; + Some(x) } /// Returns the element that gives the maximum value with respect to the @@ -2174,11 +2249,15 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_max_by", since = "1.15.0")] - fn max_by(self, mut compare: F) -> Option + fn max_by(self, compare: F) -> Option where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering, { - // switch to y even if it is only equal, to preserve stability. - select_fold1(self, |x, y| compare(x, y) != Ordering::Greater) + #[inline] + fn fold(mut compare: impl FnMut(&T, &T) -> Ordering) -> impl FnMut(T, T) -> T { + move |x, y| cmp::max_by(x, y, &mut compare) + } + + fold1(self, fold(compare)) } /// Returns the element that gives the minimum value from the @@ -2195,12 +2274,23 @@ pub trait Iterator { /// let a = [-3_i32, 0, 1, 5, -10]; /// assert_eq!(*a.iter().min_by_key(|x| x.abs()).unwrap(), 0); /// ``` + #[inline] #[stable(feature = "iter_cmp_by_key", since = "1.6.0")] - fn min_by_key(self, mut f: F) -> Option + fn min_by_key(self, f: F) -> Option where Self: Sized, F: FnMut(&Self::Item) -> B, { - // only switch to y if it is strictly smaller, to preserve stability. - select_fold1(self.map(|x| (f(&x), x)), |(x_p, _), (y_p, _)| x_p > y_p).map(|(_, x)| x) + #[inline] + fn key(mut f: impl FnMut(&T) -> B) -> impl FnMut(T) -> (B, T) { + move |x| (f(&x), x) + } + + #[inline] + fn compare((x_p, _): &(B, T), (y_p, _): &(B, T)) -> Ordering { + x_p.cmp(y_p) + } + + let (_, x) = self.map(key(f)).min_by(compare)?; + Some(x) } /// Returns the element that gives the minimum value with respect to the @@ -2219,11 +2309,15 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_min_by", since = "1.15.0")] - fn min_by(self, mut compare: F) -> Option + fn min_by(self, compare: F) -> Option where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering, { - // only switch to y if it is strictly smaller, to preserve stability. - select_fold1(self, |x, y| compare(x, y) == Ordering::Greater) + #[inline] + fn fold(mut compare: impl FnMut(&T, &T) -> Ordering) -> impl FnMut(T, T) -> T { + move |x, y| cmp::min_by(x, y, &mut compare) + } + + fold1(self, fold(compare)) } @@ -2284,13 +2378,20 @@ pub trait Iterator { FromB: Default + Extend, Self: Sized + Iterator, { + fn extend<'a, A, B>( + ts: &'a mut impl Extend, + us: &'a mut impl Extend, + ) -> impl FnMut((A, B)) + 'a { + move |(t, u)| { + ts.extend(Some(t)); + us.extend(Some(u)); + } + } + let mut ts: FromA = Default::default(); let mut us: FromB = Default::default(); - self.for_each(|(t, u)| { - ts.extend(Some(t)); - us.extend(Some(u)); - }); + self.for_each(extend(&mut ts, &mut us)); (ts, us) } @@ -2442,11 +2543,51 @@ pub trait Iterator { /// Lexicographically compares the elements of this `Iterator` with those /// of another. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!([1].iter().cmp([1].iter()), Ordering::Equal); + /// assert_eq!([1].iter().cmp([1, 2].iter()), Ordering::Less); + /// assert_eq!([1, 2].iter().cmp([1].iter()), Ordering::Greater); + /// ``` #[stable(feature = "iter_order", since = "1.5.0")] - fn cmp(mut self, other: I) -> Ordering where + fn cmp(self, other: I) -> Ordering + where I: IntoIterator, Self::Item: Ord, Self: Sized, + { + self.cmp_by(other, |x, y| x.cmp(&y)) + } + + /// Lexicographically compares the elements of this `Iterator` with those + /// of another with respect to the specified comparison function. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_order_by)] + /// + /// use std::cmp::Ordering; + /// + /// let xs = [1, 2, 3, 4]; + /// let ys = [1, 4, 9, 16]; + /// + /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| x.cmp(&y)), Ordering::Less); + /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (x * x).cmp(&y)), Ordering::Equal); + /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (2 * x).cmp(&y)), Ordering::Greater); + /// ``` + #[unstable(feature = "iter_order_by", issue = "64295")] + fn cmp_by(mut self, other: I, mut cmp: F) -> Ordering + where + Self: Sized, + I: IntoIterator, + F: FnMut(Self::Item, I::Item) -> Ordering, { let mut other = other.into_iter(); @@ -2465,7 +2606,7 @@ pub trait Iterator { Some(val) => val, }; - match x.cmp(&y) { + match cmp(x, y) { Ordering::Equal => (), non_eq => return non_eq, } @@ -2474,11 +2615,62 @@ pub trait Iterator { /// Lexicographically compares the elements of this `Iterator` with those /// of another. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!([1.].iter().partial_cmp([1.].iter()), Some(Ordering::Equal)); + /// assert_eq!([1.].iter().partial_cmp([1., 2.].iter()), Some(Ordering::Less)); + /// assert_eq!([1., 2.].iter().partial_cmp([1.].iter()), Some(Ordering::Greater)); + /// + /// assert_eq!([std::f64::NAN].iter().partial_cmp([1.].iter()), None); + /// ``` #[stable(feature = "iter_order", since = "1.5.0")] - fn partial_cmp(mut self, other: I) -> Option where + fn partial_cmp(self, other: I) -> Option + where I: IntoIterator, Self::Item: PartialOrd, Self: Sized, + { + self.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) + } + + /// Lexicographically compares the elements of this `Iterator` with those + /// of another with respect to the specified comparison function. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_order_by)] + /// + /// use std::cmp::Ordering; + /// + /// let xs = [1.0, 2.0, 3.0, 4.0]; + /// let ys = [1.0, 4.0, 9.0, 16.0]; + /// + /// assert_eq!( + /// xs.iter().partial_cmp_by(&ys, |&x, &y| x.partial_cmp(&y)), + /// Some(Ordering::Less) + /// ); + /// assert_eq!( + /// xs.iter().partial_cmp_by(&ys, |&x, &y| (x * x).partial_cmp(&y)), + /// Some(Ordering::Equal) + /// ); + /// assert_eq!( + /// xs.iter().partial_cmp_by(&ys, |&x, &y| (2.0 * x).partial_cmp(&y)), + /// Some(Ordering::Greater) + /// ); + /// ``` + #[unstable(feature = "iter_order_by", issue = "64295")] + fn partial_cmp_by(mut self, other: I, mut partial_cmp: F) -> Option + where + Self: Sized, + I: IntoIterator, + F: FnMut(Self::Item, I::Item) -> Option, { let mut other = other.into_iter(); @@ -2497,7 +2689,7 @@ pub trait Iterator { Some(val) => val, }; - match x.partial_cmp(&y) { + match partial_cmp(x, y) { Some(Ordering::Equal) => (), non_eq => return non_eq, } @@ -2506,11 +2698,44 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are equal to those of /// another. + /// + /// # Examples + /// + /// ``` + /// assert_eq!([1].iter().eq([1].iter()), true); + /// assert_eq!([1].iter().eq([1, 2].iter()), false); + /// ``` #[stable(feature = "iter_order", since = "1.5.0")] - fn eq(mut self, other: I) -> bool where + fn eq(self, other: I) -> bool + where I: IntoIterator, Self::Item: PartialEq, Self: Sized, + { + self.eq_by(other, |x, y| x == y) + } + + /// Determines if the elements of this `Iterator` are equal to those of + /// another with respect to the specified equality function. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_order_by)] + /// + /// let xs = [1, 2, 3, 4]; + /// let ys = [1, 4, 9, 16]; + /// + /// assert!(xs.iter().eq_by(&ys, |&x, &y| x * x == y)); + /// ``` + #[unstable(feature = "iter_order_by", issue = "64295")] + fn eq_by(mut self, other: I, mut eq: F) -> bool + where + Self: Sized, + I: IntoIterator, + F: FnMut(Self::Item, I::Item) -> bool, { let mut other = other.into_iter(); @@ -2525,12 +2750,21 @@ pub trait Iterator { Some(val) => val, }; - if x != y { return false } + if !eq(x, y) { + return false; + } } } /// Determines if the elements of this `Iterator` are unequal to those of /// another. + /// + /// # Examples + /// + /// ``` + /// assert_eq!([1].iter().ne([1].iter()), false); + /// assert_eq!([1].iter().ne([1, 2].iter()), true); + /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn ne(self, other: I) -> bool where I: IntoIterator, @@ -2542,6 +2776,14 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are lexicographically /// less than those of another. + /// + /// # Examples + /// + /// ``` + /// assert_eq!([1].iter().lt([1].iter()), false); + /// assert_eq!([1].iter().lt([1, 2].iter()), true); + /// assert_eq!([1, 2].iter().lt([1].iter()), false); + /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn lt(self, other: I) -> bool where I: IntoIterator, @@ -2553,6 +2795,14 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are lexicographically /// less or equal to those of another. + /// + /// # Examples + /// + /// ``` + /// assert_eq!([1].iter().le([1].iter()), true); + /// assert_eq!([1].iter().le([1, 2].iter()), true); + /// assert_eq!([1, 2].iter().le([1].iter()), false); + /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn le(self, other: I) -> bool where I: IntoIterator, @@ -2567,6 +2817,14 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are lexicographically /// greater than those of another. + /// + /// # Examples + /// + /// ``` + /// assert_eq!([1].iter().gt([1].iter()), false); + /// assert_eq!([1].iter().gt([1, 2].iter()), false); + /// assert_eq!([1, 2].iter().gt([1].iter()), true); + /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn gt(self, other: I) -> bool where I: IntoIterator, @@ -2578,6 +2836,14 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are lexicographically /// greater than or equal to those of another. + /// + /// # Examples + /// + /// ``` + /// assert_eq!([1].iter().ge([1].iter()), true); + /// assert_eq!([1].iter().ge([1, 2].iter()), false); + /// assert_eq!([1, 2].iter().ge([1].iter()), true); + /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn ge(self, other: I) -> bool where I: IntoIterator, @@ -2617,7 +2883,7 @@ pub trait Iterator { Self: Sized, Self::Item: PartialOrd, { - self.is_sorted_by(|a, b| a.partial_cmp(b)) + self.is_sorted_by(PartialOrd::partial_cmp) } /// Checks if the elements of this iterator are sorted using the given comparator function. @@ -2626,6 +2892,18 @@ pub trait Iterator { /// function to determine the ordering of two elements. Apart from that, it's equivalent to /// [`is_sorted`]; see its documentation for more information. /// + /// # Examples + /// + /// ``` + /// #![feature(is_sorted)] + /// + /// assert!([1, 2, 2, 9].iter().is_sorted_by(|a, b| a.partial_cmp(b))); + /// assert!(![1, 3, 2, 4].iter().is_sorted_by(|a, b| a.partial_cmp(b))); + /// assert!([0].iter().is_sorted_by(|a, b| a.partial_cmp(b))); + /// assert!(std::iter::empty::().is_sorted_by(|a, b| a.partial_cmp(b))); + /// assert!(![0.0, 1.0, std::f32::NAN].iter().is_sorted_by(|a, b| a.partial_cmp(b))); + /// ``` + /// /// [`is_sorted`]: trait.Iterator.html#method.is_sorted #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] fn is_sorted_by(mut self, mut compare: F) -> bool @@ -2639,10 +2917,7 @@ pub trait Iterator { }; while let Some(curr) = self.next() { - if compare(&last, &curr) - .map(|o| o == Ordering::Greater) - .unwrap_or(true) - { + if let Some(Ordering::Greater) | None = compare(&last, &curr) { return false; } last = curr; @@ -2680,24 +2955,18 @@ pub trait Iterator { } } -/// Select an element from an iterator based on the given "comparison" -/// function. -/// -/// This is an idiosyncratic helper to try to factor out the -/// commonalities of {max,min}{,_by}. In particular, this avoids -/// having to implement optimizations several times. +/// Fold an iterator without having to provide an initial value. #[inline] -fn select_fold1(mut it: I, mut f: F) -> Option +fn fold1(mut it: I, f: F) -> Option where I: Iterator, - F: FnMut(&I::Item, &I::Item) -> bool, + F: FnMut(I::Item, I::Item) -> I::Item, { // start with the first element as our selection. This avoids // having to use `Option`s inside the loop, translating to a // sizeable performance gain (6x in one case). - it.next().map(|first| { - it.fold(first, |sel, x| if f(&sel, &x) { x } else { sel }) - }) + let first = it.next()?; + Some(it.fold(first, f)) } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 4d627383fd7cc..30e8dddff85ad 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -63,7 +63,7 @@ #![warn(missing_debug_implementations)] #![deny(intra_doc_link_resolution_failure)] // rustdoc is run without -D warnings #![allow(explicit_outlives_requirements)] -#![cfg_attr(not(bootstrap), allow(incomplete_features))] +#![allow(incomplete_features)] #![feature(allow_internal_unstable)] #![feature(arbitrary_self_types)] @@ -87,7 +87,6 @@ #![feature(link_llvm_intrinsics)] #![feature(never_type)] #![feature(nll)] -#![feature(bind_by_move_pattern_guards)] #![feature(exhaustive_patterns)] #![feature(no_core)] #![feature(on_unimplemented)] @@ -120,18 +119,15 @@ #![feature(rtm_target_feature)] #![feature(f16c_target_feature)] #![feature(hexagon_target_feature)] -#![feature(const_slice_len)] -#![feature(const_str_as_bytes)] -#![feature(const_str_len)] #![feature(const_int_conversion)] #![feature(const_transmute)] #![feature(non_exhaustive)] #![feature(structural_match)] #![feature(abi_unadjusted)] #![feature(adx_target_feature)] -#![feature(maybe_uninit_slice, maybe_uninit_array)] +#![feature(maybe_uninit_slice)] #![feature(external_doc)] -#![feature(mem_take)] +#![feature(associated_type_bounds)] #[prelude_import] #[allow(unused)] @@ -226,6 +222,7 @@ pub mod task; pub mod alloc; // note: does not need to be public +mod bool; mod tuple; mod unit; diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 09d2331b60fed..1320e63df0635 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -2,21 +2,21 @@ /// /// For details, see `std::macros`. #[macro_export] -#[allow_internal_unstable(core_panic, __rust_unstable_column)] +#[allow_internal_unstable(core_panic)] #[stable(feature = "core", since = "1.6.0")] macro_rules! panic { () => ( $crate::panic!("explicit panic") ); ($msg:expr) => ({ - $crate::panicking::panic(&($msg, file!(), line!(), __rust_unstable_column!())) + $crate::panicking::panic(&($msg, $crate::file!(), $crate::line!(), $crate::column!())) }); ($msg:expr,) => ( $crate::panic!($msg) ); ($fmt:expr, $($arg:tt)+) => ({ - $crate::panicking::panic_fmt(format_args!($fmt, $($arg)+), - &(file!(), line!(), __rust_unstable_column!())) + $crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+), + &($crate::file!(), $crate::line!(), $crate::column!())) }); } @@ -70,7 +70,7 @@ macro_rules! assert_eq { panic!(r#"assertion failed: `(left == right)` left: `{:?}`, right: `{:?}`: {}"#, &*left_val, &*right_val, - format_args!($($arg)+)) + $crate::format_args!($($arg)+)) } } } @@ -127,7 +127,7 @@ macro_rules! assert_ne { panic!(r#"assertion failed: `(left != right)` left: `{:?}`, right: `{:?}`: {}"#, &*left_val, &*right_val, - format_args!($($arg)+)) + $crate::format_args!($($arg)+)) } } } @@ -181,7 +181,7 @@ macro_rules! assert_ne { #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] macro_rules! debug_assert { - ($($arg:tt)*) => (if cfg!(debug_assertions) { assert!($($arg)*); }) + ($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert!($($arg)*); }) } /// Asserts that two expressions are equal to each other. @@ -208,7 +208,7 @@ macro_rules! debug_assert { #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] macro_rules! debug_assert_eq { - ($($arg:tt)*) => (if cfg!(debug_assertions) { $crate::assert_eq!($($arg)*); }) + ($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_eq!($($arg)*); }) } /// Asserts that two expressions are not equal to each other. @@ -235,7 +235,7 @@ macro_rules! debug_assert_eq { #[macro_export] #[stable(feature = "assert_ne", since = "1.13.0")] macro_rules! debug_assert_ne { - ($($arg:tt)*) => (if cfg!(debug_assertions) { $crate::assert_ne!($($arg)*); }) + ($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_ne!($($arg)*); }) } /// Unwraps a result or propagates its error. @@ -302,6 +302,7 @@ macro_rules! debug_assert_ne { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_deprecated(since = "1.39.0", reason = "use the `?` operator instead")] #[doc(alias = "?")] macro_rules! r#try { ($expr:expr) => (match $expr { @@ -385,7 +386,7 @@ macro_rules! r#try { #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] macro_rules! write { - ($dst:expr, $($arg:tt)*) => ($dst.write_fmt(format_args!($($arg)*))) + ($dst:expr, $($arg:tt)*) => ($dst.write_fmt($crate::format_args!($($arg)*))) } /// Write formatted data into a buffer, with a newline appended. @@ -445,7 +446,7 @@ macro_rules! writeln { $crate::writeln!($dst) ); ($dst:expr, $($arg:tt)*) => ( - $dst.write_fmt(format_args_nl!($($arg)*)) + $dst.write_fmt($crate::format_args_nl!($($arg)*)) ); } @@ -464,7 +465,7 @@ macro_rules! writeln { /// The unsafe counterpart of this macro is the [`unreachable_unchecked`] function, which /// will cause undefined behavior if the code is reached. /// -/// [`panic!`]: ../std/macro.panic.html +/// [`panic!`]: ../std/macro.panic.html /// [`unreachable_unchecked`]: ../std/hint/fn.unreachable_unchecked.html /// [`std::hint`]: ../std/hint/index.html /// @@ -473,6 +474,7 @@ macro_rules! writeln { /// This will always [`panic!`] /// /// [`panic!`]: ../std/macro.panic.html +/// /// # Examples /// /// Match arms: @@ -514,19 +516,24 @@ macro_rules! unreachable { $crate::unreachable!($msg) }); ($fmt:expr, $($arg:tt)*) => ({ - panic!(concat!("internal error: entered unreachable code: ", $fmt), $($arg)*) + panic!($crate::concat!("internal error: entered unreachable code: ", $fmt), $($arg)*) }); } -/// Indicates unfinished code. +/// Indicates unfinished code by panicking with a message of "not yet implemented". /// -/// This can be useful if you are prototyping and are just looking to have your -/// code type-check, or if you're implementing a trait that requires multiple -/// methods, and you're only planning on using one of them. +/// This allows the your code to type-check, which is useful if you are prototyping or +/// implementing a trait that requires multiple methods which you don't plan of using all of. +/// +/// There is no difference between `unimplemented!` and `todo!` apart from the +/// name. /// /// # Panics /// -/// This will always [panic!](macro.panic.html) +/// This will always [panic!](macro.panic.html) because `unimplemented!` is just a +/// shorthand for `panic!` with a fixed, specific message. +/// +/// Like `panic!`, this macro has a second form for displaying custom values. /// /// # Examples /// @@ -534,52 +541,69 @@ macro_rules! unreachable { /// /// ``` /// trait Foo { -/// fn bar(&self); +/// fn bar(&self) -> u8; /// fn baz(&self); +/// fn qux(&self) -> Result; /// } /// ``` /// -/// We want to implement `Foo` on one of our types, but we also want to work on -/// just `bar()` first. In order for our code to compile, we need to implement -/// `baz()`, so we can use `unimplemented!`: +/// We want to implement `Foo` for 'MyStruct', but so far we only know how to +/// implement the `bar()` function. `baz()` and `qux()` will still need to be defined +/// in our implementation of `Foo`, but we can use `unimplemented!` in their definitions +/// to allow our code to compile. +/// +/// In the meantime, we want to have our program stop running once these +/// unimplemented functions are reached. /// /// ``` /// # trait Foo { -/// # fn bar(&self); +/// # fn bar(&self) -> u8; /// # fn baz(&self); +/// # fn qux(&self) -> Result; /// # } /// struct MyStruct; /// /// impl Foo for MyStruct { -/// fn bar(&self) { -/// // implementation goes here +/// fn bar(&self) -> u8 { +/// 1 + 1 /// } /// /// fn baz(&self) { -/// // let's not worry about implementing baz() for now +/// // We aren't sure how to even start writing baz yet, +/// // so we have no logic here at all. +/// // This will display "thread 'main' panicked at 'not yet implemented'". /// unimplemented!(); /// } +/// +/// fn qux(&self) -> Result { +/// let n = self.bar(); +/// // We have some logic here, +/// // so we can use unimplemented! to display what we have so far. +/// // This will display: +/// // "thread 'main' panicked at 'not yet implemented: we need to divide by 2'". +/// unimplemented!("we need to divide by {}", n); +/// } /// } /// /// fn main() { /// let s = MyStruct; /// s.bar(); -/// -/// // we aren't even using baz() yet, so this is fine. /// } /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] macro_rules! unimplemented { () => (panic!("not yet implemented")); - ($($arg:tt)+) => (panic!("not yet implemented: {}", format_args!($($arg)+))); + ($($arg:tt)+) => (panic!("not yet implemented: {}", $crate::format_args!($($arg)+))); } /// Indicates unfinished code. /// /// This can be useful if you are prototyping and are just looking to have your -/// code typecheck. `todo!` works exactly like `unimplemented!`. The only -/// difference between the two macros is the name. +/// code typecheck. +/// +/// There is no difference between `unimplemented!` and `todo!` apart from the +/// name. /// /// # Panics /// @@ -601,8 +625,6 @@ macro_rules! unimplemented { /// `baz()`, so we can use `todo!`: /// /// ``` -/// #![feature(todo_macro)] -/// /// # trait Foo { /// # fn bar(&self); /// # fn baz(&self); @@ -628,44 +650,10 @@ macro_rules! unimplemented { /// } /// ``` #[macro_export] -#[unstable(feature = "todo_macro", issue = "59277")] +#[stable(feature = "todo_macro", since = "1.39.0")] macro_rules! todo { () => (panic!("not yet implemented")); - ($($arg:tt)+) => (panic!("not yet implemented: {}", format_args!($($arg)+))); -} - -/// Creates an array of [`MaybeUninit`]. -/// -/// This macro constructs an uninitialized array of the type `[MaybeUninit; N]`. -/// It exists solely because bootstrap does not yet support const array-init expressions. -/// -/// [`MaybeUninit`]: mem/union.MaybeUninit.html -// FIXME: Remove both versions of this macro once bootstrap is 1.38. -#[macro_export] -#[unstable(feature = "maybe_uninit_array", issue = "53491")] -#[cfg(bootstrap)] -macro_rules! uninit_array { - // This `assume_init` is safe because an array of `MaybeUninit` does not - // require initialization. - ($t:ty; $size:expr) => (unsafe { - MaybeUninit::<[MaybeUninit<$t>; $size]>::uninit().assume_init() - }); -} - -/// Creates an array of [`MaybeUninit`]. -/// -/// This macro constructs an uninitialized array of the type `[MaybeUninit; N]`. -/// It exists solely because bootstrap does not yet support const array-init expressions. -/// -/// [`MaybeUninit`]: mem/union.MaybeUninit.html -// FIXME: Just inline this version of the macro once bootstrap is 1.38. -#[macro_export] -#[unstable(feature = "maybe_uninit_array", issue = "53491")] -#[cfg(not(bootstrap))] -macro_rules! uninit_array { - ($t:ty; $size:expr) => ( - [MaybeUninit::<$t>::UNINIT; $size] - ); + ($($arg:tt)+) => (panic!("not yet implemented: {}", $crate::format_args!($($arg)+))); } /// Definitions of built-in macros. @@ -673,7 +661,6 @@ macro_rules! uninit_array { /// Most of the macro properties (stability, visibility, etc.) are taken from the source code here, /// with exception of expansion functions transforming macro inputs into outputs, /// those functions are provided by the compiler. -#[cfg(not(bootstrap))] pub(crate) mod builtin { /// Causes compilation to fail with the given error message when encountered. @@ -713,9 +700,9 @@ pub(crate) mod builtin { /// [`panic!`]: ../std/macro.panic.html #[stable(feature = "compile_error_macro", since = "1.20.0")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro compile_error { - ($msg:expr) => ({ /* compiler built-in */ }), + #[macro_export] + macro_rules! compile_error { + ($msg:expr) => ({ /* compiler built-in */ }); ($msg:expr,) => ({ /* compiler built-in */ }) } @@ -767,9 +754,9 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(fmt_internals)] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro format_args { - ($fmt:expr) => ({ /* compiler built-in */ }), + #[macro_export] + macro_rules! format_args { + ($fmt:expr) => ({ /* compiler built-in */ }); ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) } @@ -779,9 +766,9 @@ pub(crate) mod builtin { language use and is subject to change")] #[allow_internal_unstable(fmt_internals)] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro format_args_nl { - ($fmt:expr) => ({ /* compiler built-in */ }), + #[macro_export] + macro_rules! format_args_nl { + ($fmt:expr) => ({ /* compiler built-in */ }); ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) } @@ -818,9 +805,9 @@ pub(crate) mod builtin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro env { - ($name:expr) => ({ /* compiler built-in */ }), + #[macro_export] + macro_rules! env { + ($name:expr) => ({ /* compiler built-in */ }); ($name:expr,) => ({ /* compiler built-in */ }) } @@ -845,9 +832,9 @@ pub(crate) mod builtin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro option_env { - ($name:expr) => ({ /* compiler built-in */ }), + #[macro_export] + macro_rules! option_env { + ($name:expr) => ({ /* compiler built-in */ }); ($name:expr,) => ({ /* compiler built-in */ }) } @@ -878,9 +865,9 @@ pub(crate) mod builtin { #[unstable(feature = "concat_idents", issue = "29599", reason = "`concat_idents` is not stable enough for use and is subject to change")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro concat_idents { - ($($e:ident),+) => ({ /* compiler built-in */ }), + #[macro_export] + macro_rules! concat_idents { + ($($e:ident),+) => ({ /* compiler built-in */ }); ($($e:ident,)+) => ({ /* compiler built-in */ }) } @@ -901,9 +888,9 @@ pub(crate) mod builtin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro concat { - ($($e:expr),*) => ({ /* compiler built-in */ }), + #[macro_export] + macro_rules! concat { + ($($e:expr),*) => ({ /* compiler built-in */ }); ($($e:expr,)*) => ({ /* compiler built-in */ }) } @@ -930,8 +917,8 @@ pub(crate) mod builtin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro line() { /* compiler built-in */ } + #[macro_export] + macro_rules! line { () => { /* compiler built-in */ } } /// Expands to the column number at which it was invoked. /// @@ -956,15 +943,8 @@ pub(crate) mod builtin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro column() { /* compiler built-in */ } - - /// Same as `column`, but less likely to be shadowed. - #[unstable(feature = "__rust_unstable_column", issue = "0", - reason = "internal implementation detail of the `panic` macro")] - #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro __rust_unstable_column() { /* compiler built-in */ } + #[macro_export] + macro_rules! column { () => { /* compiler built-in */ } } /// Expands to the file name in which it was invoked. /// @@ -988,8 +968,8 @@ pub(crate) mod builtin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro file() { /* compiler built-in */ } + #[macro_export] + macro_rules! file { () => { /* compiler built-in */ } } /// Stringifies its arguments. /// @@ -1008,8 +988,8 @@ pub(crate) mod builtin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro stringify($($t:tt)*) { /* compiler built-in */ } + #[macro_export] + macro_rules! stringify { ($($t:tt)*) => { /* compiler built-in */ } } /// Includes a utf8-encoded file as a string. /// @@ -1043,9 +1023,9 @@ pub(crate) mod builtin { /// Compiling 'main.rs' and running the resulting binary will print "adiós". #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro include_str { - ($file:expr) => ({ /* compiler built-in */ }), + #[macro_export] + macro_rules! include_str { + ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }) } @@ -1081,9 +1061,9 @@ pub(crate) mod builtin { /// Compiling 'main.rs' and running the resulting binary will print "adiós". #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro include_bytes { - ($file:expr) => ({ /* compiler built-in */ }), + #[macro_export] + macro_rules! include_bytes { + ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }) } @@ -1106,8 +1086,8 @@ pub(crate) mod builtin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro module_path() { /* compiler built-in */ } + #[macro_export] + macro_rules! module_path { () => { /* compiler built-in */ } } /// Evaluates boolean combinations of configuration flags at compile-time. /// @@ -1131,8 +1111,8 @@ pub(crate) mod builtin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro cfg($($cfg:tt)*) { /* compiler built-in */ } + #[macro_export] + macro_rules! cfg { ($($cfg:tt)*) => { /* compiler built-in */ } } /// Parses a file as an expression or an item according to the context. /// @@ -1175,9 +1155,9 @@ pub(crate) mod builtin { /// "🙈🙊🙉🙈🙊🙉". #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro include { - ($file:expr) => ({ /* compiler built-in */ }), + #[macro_export] + macro_rules! include { + ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }) } @@ -1228,10 +1208,10 @@ pub(crate) mod builtin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro assert { - ($cond:expr) => ({ /* compiler built-in */ }), - ($cond:expr,) => ({ /* compiler built-in */ }), + #[macro_export] + macro_rules! assert { + ($cond:expr) => ({ /* compiler built-in */ }); + ($cond:expr,) => ({ /* compiler built-in */ }); ($cond:expr, $($arg:tt)+) => ({ /* compiler built-in */ }) } @@ -1239,34 +1219,34 @@ pub(crate) mod builtin { #[unstable(feature = "asm", issue = "29722", reason = "inline assembly is not stable enough for use and is subject to change")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro asm("assembly template" - : $("output"(operand),)* - : $("input"(operand),)* - : $("clobbers",)* - : $("options",)*) { /* compiler built-in */ } + #[macro_export] + macro_rules! asm { ("assembly template" + : $("output"(operand),)* + : $("input"(operand),)* + : $("clobbers",)* + : $("options",)*) => { /* compiler built-in */ } } /// Module-level inline assembly. #[unstable(feature = "global_asm", issue = "35119", reason = "`global_asm!` is not stable enough for use and is subject to change")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro global_asm("assembly") { /* compiler built-in */ } + #[macro_export] + macro_rules! global_asm { ("assembly") => { /* compiler built-in */ } } /// Prints passed tokens into the standard output. #[unstable(feature = "log_syntax", issue = "29598", reason = "`log_syntax!` is not stable enough for use and is subject to change")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro log_syntax($($arg:tt)*) { /* compiler built-in */ } + #[macro_export] + macro_rules! log_syntax { ($($arg:tt)*) => { /* compiler built-in */ } } /// Enables or disables tracing functionality used for debugging other macros. #[unstable(feature = "trace_macros", issue = "29598", reason = "`trace_macros` is not stable enough for use and is subject to change")] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - pub macro trace_macros { - (true) => ({ /* compiler built-in */ }), + #[macro_export] + macro_rules! trace_macros { + (true) => ({ /* compiler built-in */ }); (false) => ({ /* compiler built-in */ }) } @@ -1274,15 +1254,13 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(test, rustc_attrs)] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] pub macro test($item:item) { /* compiler built-in */ } /// Attribute macro applied to a function to turn it into a benchmark test. - #[unstable(feature = "test", issue = "50297", + #[unstable(soft, feature = "test", issue = "50297", reason = "`bench` is a part of custom test frameworks which are unstable")] #[allow_internal_unstable(test, rustc_attrs)] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] pub macro bench($item:item) { /* compiler built-in */ } /// An implementation detail of the `#[test]` and `#[bench]` macros. @@ -1290,89 +1268,22 @@ pub(crate) mod builtin { reason = "custom test frameworks are an unstable feature")] #[allow_internal_unstable(test, rustc_attrs)] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] pub macro test_case($item:item) { /* compiler built-in */ } /// Attribute macro applied to a static to register it as a global allocator. #[stable(feature = "global_allocator", since = "1.28.0")] #[allow_internal_unstable(rustc_attrs)] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] pub macro global_allocator($item:item) { /* compiler built-in */ } - /// Derive macro generating an impl of the trait `Clone`. - #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(core_intrinsics, derive_clone_copy)] - pub macro Clone($item:item) { /* compiler built-in */ } - - /// Derive macro generating an impl of the trait `Copy`. - #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(core_intrinsics, derive_clone_copy)] - pub macro Copy($item:item) { /* compiler built-in */ } - - /// Derive macro generating an impl of the trait `Debug`. - #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(core_intrinsics)] - pub macro Debug($item:item) { /* compiler built-in */ } - - /// Derive macro generating an impl of the trait `Default`. - #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(core_intrinsics)] - pub macro Default($item:item) { /* compiler built-in */ } - - /// Derive macro generating an impl of the trait `Eq`. - #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(core_intrinsics, derive_eq)] - pub macro Eq($item:item) { /* compiler built-in */ } - - /// Derive macro generating an impl of the trait `Hash`. - #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(core_intrinsics)] - pub macro Hash($item:item) { /* compiler built-in */ } - - /// Derive macro generating an impl of the trait `Ord`. - #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(core_intrinsics)] - pub macro Ord($item:item) { /* compiler built-in */ } - - /// Derive macro generating an impl of the trait `PartialEq`. - #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(core_intrinsics)] - pub macro PartialEq($item:item) { /* compiler built-in */ } - - /// Derive macro generating an impl of the trait `PartialOrd`. - #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] - #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(core_intrinsics)] - pub macro PartialOrd($item:item) { /* compiler built-in */ } - /// Unstable implementation detail of the `rustc` compiler, do not use. #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(core_intrinsics, libstd_sys_internals)] pub macro RustcDecodable($item:item) { /* compiler built-in */ } /// Unstable implementation detail of the `rustc` compiler, do not use. #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(core_intrinsics)] pub macro RustcEncodable($item:item) { /* compiler built-in */ } diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 79a188dbac99d..7f3d958f5dc80 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -288,6 +288,12 @@ pub trait Copy : Clone { // Empty. } +/// Derive macro generating an impl of the trait `Copy`. +#[rustc_builtin_macro] +#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[allow_internal_unstable(core_intrinsics, derive_clone_copy)] +pub macro Copy($item:item) { /* compiler built-in */ } + /// Types for which it is safe to share references between threads. /// /// This trait is automatically implemented when the compiler determines @@ -595,10 +601,10 @@ unsafe impl Freeze for *mut T {} unsafe impl Freeze for &T {} unsafe impl Freeze for &mut T {} -/// Types which can be safely moved after being pinned. +/// Types that can be safely moved after being pinned. /// /// Since Rust itself has no notion of immovable types, and considers moves -/// (e.g. through assignment or [`mem::replace`]) to always be safe, +/// (e.g., through assignment or [`mem::replace`]) to always be safe, /// this trait cannot prevent types from moving by itself. /// /// Instead it is used to prevent moves through the type system, diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs index 8d064de6f4751..792ce9dfad419 100644 --- a/src/libcore/mem/maybe_uninit.rs +++ b/src/libcore/mem/maybe_uninit.rs @@ -5,14 +5,15 @@ use crate::mem::ManuallyDrop; /// /// # Initialization invariant /// -/// The compiler, in general, assumes that variables are properly initialized -/// at their respective type. For example, a variable of reference type must -/// be aligned and non-NULL. This is an invariant that must *always* be upheld, -/// even in unsafe code. As a consequence, zero-initializing a variable of reference -/// type causes instantaneous [undefined behavior][ub], no matter whether that reference -/// ever gets used to access memory: +/// The compiler, in general, assumes that a variable is properly initialized +/// according to the requirements of the variable's type. For example, a variable of +/// reference type must be aligned and non-NULL. This is an invariant that must +/// *always* be upheld, even in unsafe code. As a consequence, zero-initializing a +/// variable of reference type causes instantaneous [undefined behavior][ub], +/// no matter whether that reference ever gets used to access memory: /// /// ```rust,no_run +/// # #![allow(invalid_value)] /// use std::mem::{self, MaybeUninit}; /// /// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior! @@ -27,6 +28,7 @@ use crate::mem::ManuallyDrop; /// always be `true` or `false`. Hence, creating an uninitialized `bool` is undefined behavior: /// /// ```rust,no_run +/// # #![allow(invalid_value)] /// use std::mem::{self, MaybeUninit}; /// /// let b: bool = unsafe { mem::uninitialized() }; // undefined behavior! @@ -40,6 +42,7 @@ use crate::mem::ManuallyDrop; /// which otherwise can hold any *fixed* bit pattern: /// /// ```rust,no_run +/// # #![allow(invalid_value)] /// use std::mem::{self, MaybeUninit}; /// /// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior! @@ -210,7 +213,7 @@ use crate::mem::ManuallyDrop; #[allow(missing_debug_implementations)] #[stable(feature = "maybe_uninit", since = "1.36.0")] // Lang item so we can wrap other types in it. This is useful for generators. -#[cfg_attr(not(bootstrap), lang = "maybe_uninit")] +#[lang = "maybe_uninit"] #[derive(Copy)] #[repr(transparent)] pub union MaybeUninit { @@ -309,7 +312,7 @@ impl MaybeUninit { /// without dropping it, so be careful not to use this twice unless you want to /// skip running the destructor. For your convenience, this also returns a mutable /// reference to the (now safely initialized) contents of `self`. - #[unstable(feature = "maybe_uninit_extra", issue = "53491")] + #[unstable(feature = "maybe_uninit_extra", issue = "63567")] #[inline(always)] pub fn write(&mut self, val: T) -> &mut T { unsafe { @@ -499,7 +502,7 @@ impl MaybeUninit { /// // We now created two copies of the same vector, leading to a double-free when /// // they both get dropped! /// ``` - #[unstable(feature = "maybe_uninit_extra", issue = "53491")] + #[unstable(feature = "maybe_uninit_extra", issue = "63567")] #[inline(always)] pub unsafe fn read(&self) -> T { intrinsics::panic_if_uninhabited::(); @@ -513,7 +516,7 @@ impl MaybeUninit { /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized /// state. Calling this when the content is not yet fully initialized causes undefined /// behavior. - #[unstable(feature = "maybe_uninit_ref", issue = "53491")] + #[unstable(feature = "maybe_uninit_ref", issue = "63568")] #[inline(always)] pub unsafe fn get_ref(&self) -> &T { &*self.value @@ -529,21 +532,21 @@ impl MaybeUninit { // FIXME(#53491): We currently rely on the above being incorrect, i.e., we have references // to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make // a final decision about the rules before stabilization. - #[unstable(feature = "maybe_uninit_ref", issue = "53491")] + #[unstable(feature = "maybe_uninit_ref", issue = "63568")] #[inline(always)] pub unsafe fn get_mut(&mut self) -> &mut T { &mut *self.value } /// Gets a pointer to the first element of the array. - #[unstable(feature = "maybe_uninit_slice", issue = "53491")] + #[unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] pub fn first_ptr(this: &[MaybeUninit]) -> *const T { this as *const [MaybeUninit] as *const T } /// Gets a mutable pointer to the first element of the array. - #[unstable(feature = "maybe_uninit_slice", issue = "53491")] + #[unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] pub fn first_ptr_mut(this: &mut [MaybeUninit]) -> *mut T { this as *mut [MaybeUninit] as *mut T diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 86dae985fdb00..23608931b1dd3 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -368,15 +368,17 @@ pub fn align_of_val(val: &T) -> usize { /// make a difference in release builds (where a loop that has no side-effects /// is easily detected and eliminated), but is often a big win for debug builds. /// -/// Note that `ptr::drop_in_place` already performs this check, so if your workload -/// can be reduced to some small number of drop_in_place calls, using this is -/// unnecessary. In particular note that you can drop_in_place a slice, and that +/// Note that [`drop_in_place`] already performs this check, so if your workload +/// can be reduced to some small number of [`drop_in_place`] calls, using this is +/// unnecessary. In particular note that you can [`drop_in_place`] a slice, and that /// will do a single needs_drop check for all the values. /// /// Types like Vec therefore just `drop_in_place(&mut self[..])` without using -/// needs_drop explicitly. Types like `HashMap`, on the other hand, have to drop +/// `needs_drop` explicitly. Types like [`HashMap`], on the other hand, have to drop /// values one at a time and should use this API. /// +/// [`drop_in_place`]: ../ptr/fn.drop_in_place.html +/// [`HashMap`]: ../../std/collections/struct.HashMap.html /// /// # Examples /// @@ -445,15 +447,19 @@ pub const fn needs_drop() -> bool { /// /// *Incorrect* usage of this function: initializing a reference with zero. /// -/// ```no_run +/// ```rust,no_run +/// # #![allow(invalid_value)] /// use std::mem; /// /// let _x: &i32 = unsafe { mem::zeroed() }; // Undefined behavior! /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated_in_future)] +#[allow(deprecated)] pub unsafe fn zeroed() -> T { - MaybeUninit::zeroed().assume_init() + intrinsics::panic_if_uninhabited::(); + intrinsics::init() } /// Bypasses Rust's normal memory-initialization checks by pretending to @@ -477,8 +483,11 @@ pub unsafe fn zeroed() -> T { #[inline] #[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")] #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated_in_future)] +#[allow(deprecated)] pub unsafe fn uninitialized() -> T { - MaybeUninit::uninit().assume_init() + intrinsics::panic_if_uninhabited::(); + intrinsics::uninit() } /// Swaps the values at two mutable locations, without deinitializing either one. @@ -511,8 +520,6 @@ pub fn swap(x: &mut T, y: &mut T) { /// A simple example: /// /// ``` -/// #![feature(mem_take)] -/// /// use std::mem; /// /// let mut v: Vec = vec![1, 2]; @@ -543,8 +550,6 @@ pub fn swap(x: &mut T, y: &mut T) { /// `self`, allowing it to be returned: /// /// ``` -/// #![feature(mem_take)] -/// /// use std::mem; /// /// # struct Buffer { buf: Vec } @@ -563,7 +568,7 @@ pub fn swap(x: &mut T, y: &mut T) { /// /// [`Clone`]: ../../std/clone/trait.Clone.html #[inline] -#[unstable(feature = "mem_take", issue = "61129")] +#[stable(feature = "mem_take", since = "1.40.0")] pub fn take(dest: &mut T) -> T { replace(dest, T::default()) } @@ -811,9 +816,9 @@ impl fmt::Debug for Discriminant { /// /// enum Foo { A(&'static str), B(i32), C(i32) } /// -/// assert!(mem::discriminant(&Foo::A("bar")) == mem::discriminant(&Foo::A("baz"))); -/// assert!(mem::discriminant(&Foo::B(1)) == mem::discriminant(&Foo::B(2))); -/// assert!(mem::discriminant(&Foo::B(3)) != mem::discriminant(&Foo::C(3))); +/// assert_eq!(mem::discriminant(&Foo::A("bar")), mem::discriminant(&Foo::A("baz"))); +/// assert_eq!(mem::discriminant(&Foo::B(1)), mem::discriminant(&Foo::B(2))); +/// assert_ne!(mem::discriminant(&Foo::B(3)), mem::discriminant(&Foo::C(3))); /// ``` #[stable(feature = "discriminant_value", since = "1.21.0")] pub fn discriminant(v: &T) -> Discriminant { diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 8ff78166a9f2d..22e7573eca65b 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -315,7 +315,7 @@ impl f32 { /// use std::f32; /// /// let x = 2.0_f32; - /// let abs_difference = (x.recip() - (1.0/x)).abs(); + /// let abs_difference = (x.recip() - (1.0 / x)).abs(); /// /// assert!(abs_difference <= f32::EPSILON); /// ``` diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index d45c04f45afc2..bbe1d04078060 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -327,7 +327,7 @@ impl f64 { /// /// ``` /// let x = 2.0_f64; - /// let abs_difference = (x.recip() - (1.0/x)).abs(); + /// let abs_difference = (x.recip() - (1.0 / x)).abs(); /// /// assert!(abs_difference < 1e-10); /// ``` diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 67e30e7ffcb24..ebde82de83457 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -252,7 +252,7 @@ Basic usage: $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[inline] + #[inline(always)] #[rustc_promotable] pub const fn min_value() -> Self { !0 ^ ((!0 as $UnsignedT) >> 1) as Self @@ -271,7 +271,7 @@ Basic usage: $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[inline] + #[inline(always)] #[rustc_promotable] pub const fn max_value() -> Self { !Self::min_value() @@ -938,7 +938,9 @@ Basic usage: ``` ", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); assert_eq!(", stringify!($SelfT), "::max_value().saturating_add(100), ", stringify!($SelfT), -"::max_value());", +"::max_value()); +assert_eq!(", stringify!($SelfT), "::min_value().saturating_add(-1), ", stringify!($SelfT), +"::min_value());", $EndFeature, " ```"), @@ -952,7 +954,6 @@ $EndFeature, " } } - doc_comment! { concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the numeric bounds instead of overflowing. @@ -964,7 +965,9 @@ Basic usage: ``` ", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27); assert_eq!(", stringify!($SelfT), "::min_value().saturating_sub(100), ", stringify!($SelfT), -"::min_value());", +"::min_value()); +assert_eq!(", stringify!($SelfT), "::max_value().saturating_sub(-1), ", stringify!($SelfT), +"::max_value());", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] @@ -1112,7 +1115,7 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_add(self, rhs: Self) -> Self { - intrinsics::overflowing_add(self, rhs) + intrinsics::wrapping_add(self, rhs) } } @@ -1135,7 +1138,7 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_sub(self, rhs: Self) -> Self { - intrinsics::overflowing_sub(self, rhs) + intrinsics::wrapping_sub(self, rhs) } } @@ -1157,7 +1160,7 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_mul(self, rhs: Self) -> Self { - intrinsics::overflowing_mul(self, rhs) + intrinsics::wrapping_mul(self, rhs) } } @@ -1383,12 +1386,17 @@ $EndFeature, " ```"), #[stable(feature = "no_panic_abs", since = "1.13.0")] #[inline] - pub fn wrapping_abs(self) -> Self { - if self.is_negative() { - self.wrapping_neg() - } else { - self - } + pub const fn wrapping_abs(self) -> Self { + // sign is -1 (all ones) for negative numbers, 0 otherwise. + let sign = self >> ($BITS - 1); + // For positive self, sign == 0 so the expression is simply + // (self ^ 0).wrapping_sub(0) == self == abs(self). + // + // For negative self, self ^ sign == self ^ all_ones. + // But all_ones ^ self == all_ones - self == -1 - self. + // So for negative numbers, (self ^ sign).wrapping_sub(sign) is + // (-1 - self).wrapping_sub(-1) == -self == abs(self). + (self ^ sign).wrapping_sub(sign) } } @@ -1746,12 +1754,8 @@ $EndFeature, " ```"), #[stable(feature = "no_panic_abs", since = "1.13.0")] #[inline] - pub fn overflowing_abs(self) -> (Self, bool) { - if self.is_negative() { - self.overflowing_neg() - } else { - (self, false) - } + pub const fn overflowing_abs(self) -> (Self, bool) { + (self.wrapping_abs(), self == Self::min_value()) } } @@ -1955,15 +1959,25 @@ $EndFeature, " #[stable(feature = "rust1", since = "1.0.0")] #[inline] #[rustc_inherit_overflow_checks] - pub fn abs(self) -> Self { - if self.is_negative() { - // Note that the #[inline] above means that the overflow - // semantics of this negation depend on the crate we're being - // inlined into. - -self - } else { - self - } + pub const fn abs(self) -> Self { + // Note that the #[inline] above means that the overflow + // semantics of the subtraction depend on the crate we're being + // inlined into. + + // sign is -1 (all ones) for negative numbers, 0 otherwise. + let sign = self >> ($BITS - 1); + // For positive self, sign == 0 so the expression is simply + // (self ^ 0) - 0 == self == abs(self). + // + // For negative self, self ^ sign == self ^ all_ones. + // But all_ones ^ self == all_ones - self == -1 - self. + // So for negative numbers, (self ^ sign) - sign is + // (-1 - self) - -1 == -self == abs(self). + // + // The subtraction overflows when self is min_value(), because + // (-1 - min_value()) - -1 is max_value() - -1 which overflows. + // This is exactly when we want self.abs() to overflow. + (self ^ sign) - sign } } @@ -2086,11 +2100,14 @@ $to_xe_bytes_doc, ``` let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes(); -assert_eq!(bytes, if cfg!(target_endian = \"big\") { +assert_eq!( + bytes, + if cfg!(target_endian = \"big\") { ", $be_bytes, " } else { ", $le_bytes, " - }); + } +); ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] @@ -2182,10 +2199,10 @@ $from_xe_bytes_doc, ``` let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") { - ", $be_bytes, " - } else { - ", $le_bytes, " - }); + ", $be_bytes, " +} else { + ", $le_bytes, " +}); assert_eq!(value, ", $swap_op, "); ``` @@ -2294,7 +2311,7 @@ Basic usage: ```"), #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] - #[inline] + #[inline(always)] pub const fn min_value() -> Self { 0 } } @@ -2311,7 +2328,7 @@ stringify!($MaxV), ");", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] - #[inline] + #[inline(always)] pub const fn max_value() -> Self { !0 } } @@ -3031,7 +3048,7 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_add(self, rhs: Self) -> Self { - intrinsics::overflowing_add(self, rhs) + intrinsics::wrapping_add(self, rhs) } } @@ -3053,7 +3070,7 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_sub(self, rhs: Self) -> Self { - intrinsics::overflowing_sub(self, rhs) + intrinsics::wrapping_sub(self, rhs) } } @@ -3076,7 +3093,7 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_mul(self, rhs: Self) -> Self { - intrinsics::overflowing_mul(self, rhs) + intrinsics::wrapping_mul(self, rhs) } doc_comment! { @@ -3887,11 +3904,14 @@ $to_xe_bytes_doc, ``` let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes(); -assert_eq!(bytes, if cfg!(target_endian = \"big\") { +assert_eq!( + bytes, + if cfg!(target_endian = \"big\") { ", $be_bytes, " } else { ", $le_bytes, " - }); + } +); ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] @@ -3983,10 +4003,10 @@ $from_xe_bytes_doc, ``` let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") { - ", $be_bytes, " - } else { - ", $le_bytes, " - }); + ", $be_bytes, " +} else { + ", $le_bytes, " +}); assert_eq!(value, ", $swap_op, "); ``` diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index fd129a306d1c5..59a10ae99bb6a 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -18,6 +18,8 @@ macro_rules! sh_impl_signed { } } } + forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f, + #[stable(feature = "wrapping_ref_ops", since = "1.39.0")] } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl ShlAssign<$f> for Wrapping<$t> { @@ -41,6 +43,8 @@ macro_rules! sh_impl_signed { } } } + forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f, + #[stable(feature = "wrapping_ref_ops", since = "1.39.0")] } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl ShrAssign<$f> for Wrapping<$t> { @@ -64,6 +68,8 @@ macro_rules! sh_impl_unsigned { Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32)) } } + forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f, + #[stable(feature = "wrapping_ref_ops", since = "1.39.0")] } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl ShlAssign<$f> for Wrapping<$t> { @@ -83,6 +89,8 @@ macro_rules! sh_impl_unsigned { Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32)) } } + forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f, + #[stable(feature = "wrapping_ref_ops", since = "1.39.0")] } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl ShrAssign<$f> for Wrapping<$t> { diff --git a/src/libcore/ops/function.rs b/src/libcore/ops/function.rs index b9552eaa1a0e5..4a0a2720fe441 100644 --- a/src/libcore/ops/function.rs +++ b/src/libcore/ops/function.rs @@ -185,14 +185,6 @@ pub trait FnMut : FnOnce { /// /// # Examples /// -/// ## Calling a by-value closure -/// -/// ``` -/// let x = 5; -/// let square_x = move || x * x; -/// assert_eq!(square_x(), 25); -/// ``` -/// /// ## Using a `FnOnce` parameter /// /// ``` diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 259ed36c57885..47e3a0d21676f 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -46,7 +46,7 @@ //! # Options and pointers ("nullable" pointers) //! //! Rust's pointer types must always point to a valid location; there are -//! no "null" pointers. Instead, Rust has *optional* pointers, like +//! no "null" references. Instead, Rust has *optional* pointers, like //! the optional owned box, [`Option`]`<`[`Box`]`>`. //! //! The following example uses [`Option`] to create an optional box of @@ -295,7 +295,7 @@ impl Option { /// [`Pin`]: ../pin/struct.Pin.html #[inline] #[stable(feature = "pin", since = "1.33.0")] - pub fn as_pin_ref<'a>(self: Pin<&'a Option>) -> Option> { + pub fn as_pin_ref(self: Pin<&Self>) -> Option> { unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) } @@ -306,7 +306,7 @@ impl Option { /// [`Pin`]: ../pin/struct.Pin.html #[inline] #[stable(feature = "pin", since = "1.33.0")] - pub fn as_pin_mut<'a>(self: Pin<&'a mut Option>) -> Option> { + pub fn as_pin_mut(self: Pin<&mut Self>) -> Option> { unsafe { Pin::get_unchecked_mut(self).as_mut().map(|x| Pin::new_unchecked(x)) } @@ -1102,7 +1102,6 @@ impl Option { } } -#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] impl Option { /// Converts from `Option` (or `&Option`) to `Option<&T::Target>`. /// @@ -1110,17 +1109,38 @@ impl Option { /// to the original one, additionally coercing the contents via [`Deref`]. /// /// [`Deref`]: ../../std/ops/trait.Deref.html + /// + /// # Examples + /// + /// ``` + /// let x: Option = Some("hey".to_owned()); + /// assert_eq!(x.as_deref(), Some("hey")); + /// + /// let x: Option = None; + /// assert_eq!(x.as_deref(), None); + /// ``` + #[stable(feature = "option_deref", since = "1.40.0")] pub fn as_deref(&self) -> Option<&T::Target> { self.as_ref().map(|t| t.deref()) } } -#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] impl Option { /// Converts from `Option` (or `&mut Option`) to `Option<&mut T::Target>`. /// /// Leaves the original `Option` in-place, creating a new one containing a mutable reference to /// the inner type's `Deref::Target` type. + /// + /// # Examples + /// + /// ``` + /// let mut x: Option = Some("hey".to_owned()); + /// assert_eq!(x.as_deref_mut().map(|x| { + /// x.make_ascii_uppercase(); + /// x + /// }), Some("HEY".to_owned().as_mut_str())); + /// ``` + #[stable(feature = "option_deref", since = "1.40.0")] pub fn as_deref_mut(&mut self) -> Option<&mut T::Target> { self.as_mut().map(|t| t.deref_mut()) } @@ -1199,6 +1219,13 @@ impl Clone for Option { #[stable(feature = "rust1", since = "1.0.0")] impl Default for Option { /// Returns [`None`][Option::None]. + /// + /// # Examples + /// + /// ``` + /// let opt: Option = Option::default(); + /// assert!(opt.is_none()); + /// ``` #[inline] fn default() -> Option { None } } diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 15b7d69c58d24..e8f0561604aec 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -71,7 +71,6 @@ pub fn panic_fmt(fmt: fmt::Arguments<'_>, file_line_col: &(&'static str, u32, u3 } // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call - #[allow(improper_ctypes)] // PanicInfo contains a trait object which is not FFI safe extern "Rust" { #[lang = "panic_impl"] fn panic_impl(pi: &PanicInfo<'_>) -> !; diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 271ddcc4662cf..be057ed6d59a7 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -233,7 +233,7 @@ //! # type Field = i32; //! # struct Struct { field: Field } //! impl Struct { -//! fn pin_get_field<'a>(self: Pin<&'a mut Self>) -> &'a mut Field { +//! fn pin_get_field(self: Pin<&mut Self>) -> &mut Field { //! // This is okay because `field` is never considered pinned. //! unsafe { &mut self.get_unchecked_mut().field } //! } @@ -257,7 +257,7 @@ //! # type Field = i32; //! # struct Struct { field: Field } //! impl Struct { -//! fn pin_get_field<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut Field> { +//! fn pin_get_field(self: Pin<&mut Self>) -> Pin<&mut Field> { //! // This is okay because `field` is pinned when `self` is. //! unsafe { self.map_unchecked_mut(|s| &mut s.field) } //! } @@ -369,6 +369,8 @@ //! [drop-guarantee]: #drop-guarantee //! [`poll`]: ../../std/future/trait.Future.html#tymethod.poll //! [`Pin::get_unchecked_mut`]: struct.Pin.html#method.get_unchecked_mut +//! [`bool`]: ../../std/primitive.bool.html +//! [`i32`]: ../../std/primitive.i32.html #![stable(feature = "pin", since = "1.33.0")] @@ -440,10 +442,7 @@ where } } -impl Pin

-where - P::Target: Unpin, -{ +impl> Pin

{ /// Construct a new `Pin

` around a pointer to some data of a type that /// implements [`Unpin`]. /// @@ -465,7 +464,7 @@ where /// can ignore the pinning invariants when unwrapping it. /// /// [`Unpin`]: ../../std/marker/trait.Unpin.html - #[unstable(feature = "pin_into_inner", issue = "60245")] + #[stable(feature = "pin_into_inner", since = "1.39.0")] #[inline(always)] pub fn into_inner(pin: Pin

) -> P { pin.pointer @@ -552,7 +551,7 @@ impl Pin

{ /// ruled out by the contract of `Pin::new_unchecked`. #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn as_ref(self: &Pin

) -> Pin<&P::Target> { + pub fn as_ref(&self) -> Pin<&P::Target> { unsafe { Pin::new_unchecked(&*self.pointer) } } @@ -572,7 +571,7 @@ impl Pin

{ /// /// [`Unpin`]: ../../std/marker/trait.Unpin.html /// [`Pin::into_inner`]: #method.into_inner - #[unstable(feature = "pin_into_inner", issue = "60245")] + #[stable(feature = "pin_into_inner", since = "1.39.0")] #[inline(always)] pub unsafe fn into_inner_unchecked(pin: Pin

) -> P { pin.pointer @@ -587,9 +586,30 @@ impl Pin

{ /// the pointee cannot move after `Pin>` got created. /// "Malicious" implementations of `Pointer::DerefMut` are likewise /// ruled out by the contract of `Pin::new_unchecked`. + /// + /// This method is useful when doing multiple calls to functions that consume the pinned type. + /// + /// # Example + /// + /// ``` + /// use std::pin::Pin; + /// + /// # struct Type {} + /// impl Type { + /// fn method(self: Pin<&mut Self>) { + /// // do something + /// } + /// + /// fn call_method_twice(mut self: Pin<&mut Self>) { + /// // `method` consumes `self`, so reborrow the `Pin<&mut Self>` via `as_mut`. + /// self.as_mut().method(); + /// self.as_mut().method(); + /// } + /// } + /// ``` #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn as_mut(self: &mut Pin

) -> Pin<&mut P::Target> { + pub fn as_mut(&mut self) -> Pin<&mut P::Target> { unsafe { Pin::new_unchecked(&mut *self.pointer) } } @@ -599,7 +619,7 @@ impl Pin

{ /// run before being overwritten, so no pinning guarantee is violated. #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn set(self: &mut Pin

, value: P::Target) + pub fn set(&mut self, value: P::Target) where P::Target: Sized, { @@ -624,7 +644,7 @@ impl<'a, T: ?Sized> Pin<&'a T> { /// /// [`pin` module]: ../../std/pin/index.html#projections-and-structural-pinning #[stable(feature = "pin", since = "1.33.0")] - pub unsafe fn map_unchecked(self: Pin<&'a T>, func: F) -> Pin<&'a U> where + pub unsafe fn map_unchecked(self, func: F) -> Pin<&'a U> where F: FnOnce(&T) -> &U, { let pointer = &*self.pointer; @@ -651,7 +671,7 @@ impl<'a, T: ?Sized> Pin<&'a T> { /// ["pinning projections"]: ../../std/pin/index.html#projections-and-structural-pinning #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn get_ref(self: Pin<&'a T>) -> &'a T { + pub fn get_ref(self) -> &'a T { self.pointer } } @@ -660,7 +680,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime. #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn into_ref(self: Pin<&'a mut T>) -> Pin<&'a T> { + pub fn into_ref(self) -> Pin<&'a T> { Pin { pointer: self.pointer } } @@ -675,7 +695,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// with the same lifetime as the original `Pin`. #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn get_mut(self: Pin<&'a mut T>) -> &'a mut T + pub fn get_mut(self) -> &'a mut T where T: Unpin, { self.pointer @@ -693,7 +713,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// instead. #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub unsafe fn get_unchecked_mut(self: Pin<&'a mut T>) -> &'a mut T { + pub unsafe fn get_unchecked_mut(self) -> &'a mut T { self.pointer } @@ -713,7 +733,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// /// [`pin` module]: ../../std/pin/index.html#projections-and-structural-pinning #[stable(feature = "pin", since = "1.33.0")] - pub unsafe fn map_unchecked_mut(self: Pin<&'a mut T>, func: F) -> Pin<&'a mut U> where + pub unsafe fn map_unchecked_mut(self, func: F) -> Pin<&'a mut U> where F: FnOnce(&mut T) -> &mut U, { let pointer = Pin::get_unchecked_mut(self); @@ -731,10 +751,7 @@ impl Deref for Pin

{ } #[stable(feature = "pin", since = "1.33.0")] -impl DerefMut for Pin

-where - P::Target: Unpin -{ +impl> DerefMut for Pin

{ fn deref_mut(&mut self) -> &mut P::Target { Pin::get_mut(Pin::as_mut(self)) } diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index c503d8c701938..7cc279a9ef2ec 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -46,26 +46,18 @@ pub use crate::option::Option::{self, Some, None}; pub use crate::result::Result::{self, Ok, Err}; // Re-exported built-in macros -#[cfg(not(bootstrap))] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow(deprecated)] #[doc(no_inline)] -pub use crate::macros::builtin::{ - Clone, - Copy, - Debug, - Default, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - RustcDecodable, - RustcEncodable, - __rust_unstable_column, +pub use crate::fmt::macros::Debug; +#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[doc(no_inline)] +pub use crate::hash::macros::Hash; + +#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[doc(no_inline)] +pub use crate::{ asm, assert, - bench, cfg, column, compile_error, @@ -75,7 +67,6 @@ pub use crate::macros::builtin::{ file, format_args, format_args_nl, - global_allocator, global_asm, include, include_bytes, @@ -85,7 +76,17 @@ pub use crate::macros::builtin::{ module_path, option_env, stringify, + trace_macros, +}; + +#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[allow(deprecated)] +#[doc(no_inline)] +pub use crate::macros::builtin::{ + RustcDecodable, + RustcEncodable, + bench, + global_allocator, test, test_case, - trace_macros, }; diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index fa55bbf9c1650..933919185956e 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -1042,7 +1042,7 @@ impl *const T { (self as *const u8) == null() } - /// Cast to a pointer to a different type + /// Casts to a pointer of another type. #[stable(feature = "ptr_cast", since = "1.38.0")] #[inline] pub const fn cast(self) -> *const U { @@ -1120,7 +1120,8 @@ impl *const T { /// Behavior: /// /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. + /// byte past the end of the same allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. /// /// * The computed offset, **in bytes**, cannot overflow an `isize`. /// @@ -1140,10 +1141,12 @@ impl *const T { /// Extension. As such, memory acquired directly from allocators or memory /// mapped files *may* be too large to handle with this function. /// - /// Consider using `wrapping_offset` instead if these constraints are + /// Consider using [`wrapping_offset`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it /// enables more aggressive compiler optimizations. /// + /// [`wrapping_offset`]: #method.wrapping_offset + /// /// # Examples /// /// Basic usage: @@ -1172,15 +1175,26 @@ impl *const T { /// /// The resulting pointer does not need to be in bounds, but it is /// potentially hazardous to dereference (which requires `unsafe`). - /// In particular, the resulting pointer may *not* be used to access a - /// different allocated object than the one `self` points to. In other - /// words, `x.wrapping_offset(y.wrapping_offset_from(x))` is + /// + /// In particular, the resulting pointer remains attached to the same allocated + /// object that `self` points to. It may *not* be used to access a + /// different allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// In other words, `x.wrapping_offset(y.wrapping_offset_from(x))` is /// *not* the same as `y`, and dereferencing it is undefined behavior /// unless `x` and `y` point into the same allocated object. /// - /// Always use `.offset(count)` instead when possible, because `offset` - /// allows the compiler to optimize better. If you need to cross object - /// boundaries, cast the pointer to an integer and do the arithmetic there. + /// Compared to [`offset`], this method basically delays the requirement of staying + /// within the same allocated object: [`offset`] is immediate Undefined Behavior when + /// crossing object boundaries; `wrapping_offset` produces a pointer but still leads + /// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized + /// better and is thus preferrable in performance-sensitive code. + /// + /// If you need to cross object boundaries, cast the pointer to an integer and + /// do the arithmetic there. + /// + /// [`offset`]: #method.offset /// /// # Examples /// @@ -1223,7 +1237,8 @@ impl *const T { /// Behavior: /// /// * Both the starting and other pointer must be either in bounds or one - /// byte past the end of the same allocated object. + /// byte past the end of the same allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. /// /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. /// @@ -1338,7 +1353,8 @@ impl *const T { /// Behavior: /// /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. + /// byte past the end of the same allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. /// /// * The computed offset, **in bytes**, cannot overflow an `isize`. /// @@ -1358,10 +1374,12 @@ impl *const T { /// Extension. As such, memory acquired directly from allocators or memory /// mapped files *may* be too large to handle with this function. /// - /// Consider using `wrapping_offset` instead if these constraints are + /// Consider using [`wrapping_add`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it /// enables more aggressive compiler optimizations. /// + /// [`wrapping_add`]: #method.wrapping_add + /// /// # Examples /// /// Basic usage: @@ -1395,7 +1413,8 @@ impl *const T { /// Behavior: /// /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. + /// byte past the end of the same allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. /// /// * The computed offset cannot exceed `isize::MAX` **bytes**. /// @@ -1415,10 +1434,12 @@ impl *const T { /// Extension. As such, memory acquired directly from allocators or memory /// mapped files *may* be too large to handle with this function. /// - /// Consider using `wrapping_offset` instead if these constraints are + /// Consider using [`wrapping_sub`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it /// enables more aggressive compiler optimizations. /// + /// [`wrapping_sub`]: #method.wrapping_sub + /// /// # Examples /// /// Basic usage: @@ -1451,8 +1472,21 @@ impl *const T { /// The resulting pointer does not need to be in bounds, but it is /// potentially hazardous to dereference (which requires `unsafe`). /// - /// Always use `.add(count)` instead when possible, because `add` - /// allows the compiler to optimize better. + /// In particular, the resulting pointer remains attached to the same allocated + /// object that `self` points to. It may *not* be used to access a + /// different allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// Compared to [`add`], this method basically delays the requirement of staying + /// within the same allocated object: [`add`] is immediate Undefined Behavior when + /// crossing object boundaries; `wrapping_add` produces a pointer but still leads + /// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized + /// better and is thus preferrable in performance-sensitive code. + /// + /// If you need to cross object boundaries, cast the pointer to an integer and + /// do the arithmetic there. + /// + /// [`add`]: #method.add /// /// # Examples /// @@ -1492,8 +1526,21 @@ impl *const T { /// The resulting pointer does not need to be in bounds, but it is /// potentially hazardous to dereference (which requires `unsafe`). /// - /// Always use `.sub(count)` instead when possible, because `sub` - /// allows the compiler to optimize better. + /// In particular, the resulting pointer remains attached to the same allocated + /// object that `self` points to. It may *not* be used to access a + /// different allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// Compared to [`sub`], this method basically delays the requirement of staying + /// within the same allocated object: [`sub`] is immediate Undefined Behavior when + /// crossing object boundaries; `wrapping_sub` produces a pointer but still leads + /// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized + /// better and is thus preferrable in performance-sensitive code. + /// + /// If you need to cross object boundaries, cast the pointer to an integer and + /// do the arithmetic there. + /// + /// [`sub`]: #method.sub /// /// # Examples /// @@ -1679,7 +1726,7 @@ impl *mut T { (self as *mut u8) == null_mut() } - /// Cast to a pointer to a different type + /// Casts to a pointer of another type. #[stable(feature = "ptr_cast", since = "1.38.0")] #[inline] pub const fn cast(self) -> *mut U { @@ -1757,7 +1804,8 @@ impl *mut T { /// Behavior: /// /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. + /// byte past the end of the same allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. /// /// * The computed offset, **in bytes**, cannot overflow an `isize`. /// @@ -1777,10 +1825,12 @@ impl *mut T { /// Extension. As such, memory acquired directly from allocators or memory /// mapped files *may* be too large to handle with this function. /// - /// Consider using `wrapping_offset` instead if these constraints are + /// Consider using [`wrapping_offset`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it /// enables more aggressive compiler optimizations. /// + /// [`wrapping_offset`]: #method.wrapping_offset + /// /// # Examples /// /// Basic usage: @@ -1808,15 +1858,26 @@ impl *mut T { /// /// The resulting pointer does not need to be in bounds, but it is /// potentially hazardous to dereference (which requires `unsafe`). - /// In particular, the resulting pointer may *not* be used to access a - /// different allocated object than the one `self` points to. In other - /// words, `x.wrapping_offset(y.wrapping_offset_from(x))` is + /// + /// In particular, the resulting pointer remains attached to the same allocated + /// object that `self` points to. It may *not* be used to access a + /// different allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// In other words, `x.wrapping_offset(y.wrapping_offset_from(x))` is /// *not* the same as `y`, and dereferencing it is undefined behavior /// unless `x` and `y` point into the same allocated object. /// - /// Always use `.offset(count)` instead when possible, because `offset` - /// allows the compiler to optimize better. If you need to cross object - /// boundaries, cast the pointer to an integer and do the arithmetic there. + /// Compared to [`offset`], this method basically delays the requirement of staying + /// within the same allocated object: [`offset`] is immediate Undefined Behavior when + /// crossing object boundaries; `wrapping_offset` produces a pointer but still leads + /// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized + /// better and is thus preferrable in performance-sensitive code. + /// + /// If you need to cross object boundaries, cast the pointer to an integer and + /// do the arithmetic there. + /// + /// [`offset`]: #method.offset /// /// # Examples /// @@ -1903,7 +1964,8 @@ impl *mut T { /// Behavior: /// /// * Both the starting and other pointer must be either in bounds or one - /// byte past the end of the same allocated object. + /// byte past the end of the same allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. /// /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. /// @@ -2007,7 +2069,8 @@ impl *mut T { /// Behavior: /// /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. + /// byte past the end of the same allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. /// /// * The computed offset, **in bytes**, cannot overflow an `isize`. /// @@ -2027,10 +2090,12 @@ impl *mut T { /// Extension. As such, memory acquired directly from allocators or memory /// mapped files *may* be too large to handle with this function. /// - /// Consider using `wrapping_offset` instead if these constraints are + /// Consider using [`wrapping_add`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it /// enables more aggressive compiler optimizations. /// + /// [`wrapping_add`]: #method.wrapping_add + /// /// # Examples /// /// Basic usage: @@ -2064,7 +2129,8 @@ impl *mut T { /// Behavior: /// /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. + /// byte past the end of the same allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. /// /// * The computed offset cannot exceed `isize::MAX` **bytes**. /// @@ -2084,10 +2150,12 @@ impl *mut T { /// Extension. As such, memory acquired directly from allocators or memory /// mapped files *may* be too large to handle with this function. /// - /// Consider using `wrapping_offset` instead if these constraints are + /// Consider using [`wrapping_sub`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it /// enables more aggressive compiler optimizations. /// + /// [`wrapping_sub`]: #method.wrapping_sub + /// /// # Examples /// /// Basic usage: @@ -2120,8 +2188,21 @@ impl *mut T { /// The resulting pointer does not need to be in bounds, but it is /// potentially hazardous to dereference (which requires `unsafe`). /// - /// Always use `.add(count)` instead when possible, because `add` - /// allows the compiler to optimize better. + /// In particular, the resulting pointer remains attached to the same allocated + /// object that `self` points to. It may *not* be used to access a + /// different allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// Compared to [`add`], this method basically delays the requirement of staying + /// within the same allocated object: [`add`] is immediate Undefined Behavior when + /// crossing object boundaries; `wrapping_add` produces a pointer but still leads + /// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized + /// better and is thus preferrable in performance-sensitive code. + /// + /// If you need to cross object boundaries, cast the pointer to an integer and + /// do the arithmetic there. + /// + /// [`add`]: #method.add /// /// # Examples /// @@ -2161,8 +2242,21 @@ impl *mut T { /// The resulting pointer does not need to be in bounds, but it is /// potentially hazardous to dereference (which requires `unsafe`). /// - /// Always use `.sub(count)` instead when possible, because `sub` - /// allows the compiler to optimize better. + /// In particular, the resulting pointer remains attached to the same allocated + /// object that `self` points to. It may *not* be used to access a + /// different allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// Compared to [`sub`], this method basically delays the requirement of staying + /// within the same allocated object: [`sub`] is immediate Undefined Behavior when + /// crossing object boundaries; `wrapping_sub` produces a pointer but still leads + /// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized + /// better and is thus preferrable in performance-sensitive code. + /// + /// If you need to cross object boundaries, cast the pointer to an integer and + /// do the arithmetic there. + /// + /// [`sub`]: #method.sub /// /// # Examples /// @@ -2638,31 +2732,29 @@ impl Eq for *mut T {} /// impl Trait for Wrapper {} /// impl Trait for i32 {} /// -/// fn main() { -/// let wrapper = Wrapper { member: 10 }; -/// -/// // Pointers have equal addresses. -/// assert!(std::ptr::eq( -/// &wrapper as *const Wrapper as *const u8, -/// &wrapper.member as *const i32 as *const u8 -/// )); -/// -/// // Objects have equal addresses, but `Trait` has different implementations. -/// assert!(!std::ptr::eq( -/// &wrapper as &dyn Trait, -/// &wrapper.member as &dyn Trait, -/// )); -/// assert!(!std::ptr::eq( -/// &wrapper as &dyn Trait as *const dyn Trait, -/// &wrapper.member as &dyn Trait as *const dyn Trait, -/// )); -/// -/// // Converting the reference to a `*const u8` compares by address. -/// assert!(std::ptr::eq( -/// &wrapper as &dyn Trait as *const dyn Trait as *const u8, -/// &wrapper.member as &dyn Trait as *const dyn Trait as *const u8, -/// )); -/// } +/// let wrapper = Wrapper { member: 10 }; +/// +/// // Pointers have equal addresses. +/// assert!(std::ptr::eq( +/// &wrapper as *const Wrapper as *const u8, +/// &wrapper.member as *const i32 as *const u8 +/// )); +/// +/// // Objects have equal addresses, but `Trait` has different implementations. +/// assert!(!std::ptr::eq( +/// &wrapper as &dyn Trait, +/// &wrapper.member as &dyn Trait, +/// )); +/// assert!(!std::ptr::eq( +/// &wrapper as &dyn Trait as *const dyn Trait, +/// &wrapper.member as &dyn Trait as *const dyn Trait, +/// )); +/// +/// // Converting the reference to a `*const u8` compares by address. +/// assert!(std::ptr::eq( +/// &wrapper as &dyn Trait as *const dyn Trait as *const u8, +/// &wrapper.member as &dyn Trait as *const dyn Trait as *const u8, +/// )); /// ``` #[stable(feature = "ptr_eq", since = "1.17.0")] #[inline] diff --git a/src/libcore/ptr/non_null.rs b/src/libcore/ptr/non_null.rs index ad3d1ce396ab7..7dcd57f1f9858 100644 --- a/src/libcore/ptr/non_null.rs +++ b/src/libcore/ptr/non_null.rs @@ -125,7 +125,7 @@ impl NonNull { &mut *self.as_ptr() } - /// Cast to a pointer of another type + /// Casts to a pointer of another type. #[stable(feature = "nonnull_cast", since = "1.27.0")] #[inline] pub const fn cast(self) -> NonNull { diff --git a/src/libcore/ptr/unique.rs b/src/libcore/ptr/unique.rs index f0d011fe6b2c0..3521dd7997956 100644 --- a/src/libcore/ptr/unique.rs +++ b/src/libcore/ptr/unique.rs @@ -122,6 +122,14 @@ impl Unique { pub unsafe fn as_mut(&mut self) -> &mut T { &mut *self.as_ptr() } + + /// Casts to a pointer of another type. + #[inline] + pub const fn cast(self) -> Unique { + unsafe { + Unique::new_unchecked(self.as_ptr() as *mut U) + } + } } #[unstable(feature = "ptr_internals", issue = "0")] diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 8c60a9c1b501d..ed40a5f31d9bd 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -820,6 +820,87 @@ impl Result { } } +impl Result<&T, E> { + /// Maps a `Result<&T, E>` to a `Result` by copying the contents of the + /// `Ok` part. + /// + /// # Examples + /// + /// ``` + /// #![feature(result_copied)] + /// let val = 12; + /// let x: Result<&i32, i32> = Ok(&val); + /// assert_eq!(x, Ok(&12)); + /// let copied = x.copied(); + /// assert_eq!(copied, Ok(12)); + /// ``` + #[unstable(feature = "result_copied", reason = "newly added", issue = "63168")] + pub fn copied(self) -> Result { + self.map(|&t| t) + } +} + +impl Result<&mut T, E> { + /// Maps a `Result<&mut T, E>` to a `Result` by copying the contents of the + /// `Ok` part. + /// + /// # Examples + /// + /// ``` + /// #![feature(result_copied)] + /// let mut val = 12; + /// let x: Result<&mut i32, i32> = Ok(&mut val); + /// assert_eq!(x, Ok(&mut 12)); + /// let copied = x.copied(); + /// assert_eq!(copied, Ok(12)); + /// ``` + #[unstable(feature = "result_copied", reason = "newly added", issue = "63168")] + pub fn copied(self) -> Result { + self.map(|&mut t| t) + } +} + +impl Result<&T, E> { + /// Maps a `Result<&T, E>` to a `Result` by cloning the contents of the + /// `Ok` part. + /// + /// # Examples + /// + /// ``` + /// #![feature(result_cloned)] + /// let val = 12; + /// let x: Result<&i32, i32> = Ok(&val); + /// assert_eq!(x, Ok(&12)); + /// let cloned = x.cloned(); + /// assert_eq!(cloned, Ok(12)); + /// ``` + #[unstable(feature = "result_cloned", reason = "newly added", issue = "63168")] + pub fn cloned(self) -> Result { + self.map(|t| t.clone()) + } +} + +impl Result<&mut T, E> { + /// Maps a `Result<&mut T, E>` to a `Result` by cloning the contents of the + /// `Ok` part. + /// + /// # Examples + /// + /// ``` + /// #![feature(result_cloned)] + /// let mut val = 12; + /// let x: Result<&mut i32, i32> = Ok(&mut val); + /// assert_eq!(x, Ok(&mut 12)); + /// let cloned = x.cloned(); + /// assert_eq!(cloned, Ok(12)); + /// ``` + #[unstable(feature = "result_cloned", reason = "newly added", issue = "63168")] + pub fn cloned(self) -> Result { + self.map(|t| t.clone()) + } +} + + impl Result { /// Unwraps a result, yielding the content of an [`Ok`]. /// diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index d5a34ea2bd5a1..4e79ea812044b 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -28,7 +28,7 @@ use crate::fmt; use crate::intrinsics::{assume, exact_div, unchecked_sub, is_aligned_and_not_null}; use crate::isize; use crate::iter::*; -use crate::ops::{FnMut, Try, self}; +use crate::ops::{FnMut, self}; use crate::option::Option; use crate::option::Option::{None, Some}; use crate::result::Result; @@ -62,7 +62,9 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - #[rustc_const_unstable(feature = "const_slice_len")] + // SAFETY: const sound because we transmute out the length field as a usize (which it must be) + #[allow(unused_attributes)] + #[allow_internal_unstable(const_fn_union)] pub const fn len(&self) -> usize { unsafe { crate::ptr::Repr { rust: self }.raw.len @@ -79,7 +81,6 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - #[rustc_const_unstable(feature = "const_slice_len")] pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -1364,6 +1365,17 @@ impl [T] { /// let r = s.binary_search(&1); /// assert!(match r { Ok(1..=4) => true, _ => false, }); /// ``` + /// + /// If you want to insert an item to a sorted vector, while maintaining + /// sort order: + /// + /// ``` + /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// let num = 42; + /// let idx = s.binary_search(&num).unwrap_or_else(|x| x); + /// s.insert(idx, num); + /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn binary_search(&self, x: &T) -> Result where T: Ord @@ -3015,8 +3027,7 @@ macro_rules! len { if size == 0 { // This _cannot_ use `unchecked_sub` because we depend on wrapping // to represent the length of long ZST slice iterators. - let diff = ($self.end as usize).wrapping_sub(start as usize); - diff + ($self.end as usize).wrapping_sub(start as usize) } else { // We know that `start <= end`, so can do better than `offset_from`, // which needs to deal in signed. By setting appropriate flags here @@ -3170,39 +3181,6 @@ macro_rules! iterator { self.next_back() } - #[inline] - fn try_fold(&mut self, init: B, mut f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try - { - // manual unrolling is needed when there are conditional exits from the loop - let mut accum = init; - unsafe { - while len!(self) >= 4 { - accum = f(accum, next_unchecked!(self))?; - accum = f(accum, next_unchecked!(self))?; - accum = f(accum, next_unchecked!(self))?; - accum = f(accum, next_unchecked!(self))?; - } - while !is_empty!(self) { - accum = f(accum, next_unchecked!(self))?; - } - } - Try::from_ok(accum) - } - - #[inline] - fn fold(mut self, init: Acc, mut f: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - // Let LLVM unroll this, rather than using the default - // impl that would force the manual unrolling above - let mut accum = init; - while let Some(x) = self.next() { - accum = f(accum, x); - } - accum - } - #[inline] #[rustc_inherit_overflow_checks] fn position

(&mut self, mut predicate: P) -> Option where @@ -3273,40 +3251,6 @@ macro_rules! iterator { Some(next_back_unchecked!(self)) } } - - #[inline] - fn try_rfold(&mut self, init: B, mut f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try - { - // manual unrolling is needed when there are conditional exits from the loop - let mut accum = init; - unsafe { - while len!(self) >= 4 { - accum = f(accum, next_back_unchecked!(self))?; - accum = f(accum, next_back_unchecked!(self))?; - accum = f(accum, next_back_unchecked!(self))?; - accum = f(accum, next_back_unchecked!(self))?; - } - // inlining is_empty everywhere makes a huge performance difference - while !is_empty!(self) { - accum = f(accum, next_back_unchecked!(self))?; - } - } - Try::from_ok(accum) - } - - #[inline] - fn rfold(mut self, init: Acc, mut f: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - // Let LLVM unroll this, rather than using the default - // impl that would force the manual unrolling above - let mut accum = init; - while let Some(x) = self.next_back() { - accum = f(accum, x); - } - accum - } } #[stable(feature = "fused", since = "1.26.0")] @@ -4626,6 +4570,22 @@ impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { Some(tail) } } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &mut []; + None + } else { + let start = (len - 1 - n) * self.chunk_size; + let end = start + self.chunk_size; + let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (head, nth_back) = temp.split_at_mut(start); + self.v = head; + Some(nth_back) + } + } } #[stable(feature = "chunks_exact", since = "1.31.0")] diff --git a/src/libcore/slice/rotate.rs b/src/libcore/slice/rotate.rs index 0437937d769b7..f73e14f27e092 100644 --- a/src/libcore/slice/rotate.rs +++ b/src/libcore/slice/rotate.rs @@ -2,32 +2,9 @@ use crate::cmp; use crate::mem::{self, MaybeUninit}; use crate::ptr; -/// Rotation is much faster if it has access to a little bit of memory. This -/// union provides a RawVec-like interface, but to a fixed-size stack buffer. -#[allow(unions_with_drop_fields)] -union RawArray { - /// Ensure this is appropriately aligned for T, and is big - /// enough for two elements even if T is enormous. - typed: [T; 2], - /// For normally-sized types, especially things like u8, having more - /// than 2 in the buffer is necessary for usefulness, so pad it out - /// enough to be helpful, but not so big as to risk overflow. - _extra: [usize; 32], -} - -impl RawArray { - fn capacity() -> usize { - if mem::size_of::() == 0 { - usize::max_value() - } else { - mem::size_of::() / mem::size_of::() - } - } -} - -/// Rotates the range `[mid-left, mid+right)` such that the element at `mid` -/// becomes the first element. Equivalently, rotates the range `left` -/// elements to the left or `right` elements to the right. +/// Rotates the range `[mid-left, mid+right)` such that the element at `mid` becomes the first +/// element. Equivalently, rotates the range `left` elements to the left or `right` elements to the +/// right. /// /// # Safety /// @@ -35,55 +12,161 @@ impl RawArray { /// /// # Algorithm /// -/// For longer rotations, swap the left-most `delta = min(left, right)` -/// elements with the right-most `delta` elements. LLVM vectorizes this, -/// which is profitable as we only reach this step for a "large enough" -/// rotation. Doing this puts `delta` elements on the larger side into the -/// correct position, leaving a smaller rotate problem. Demonstration: -/// +/// Algorithm 1 is used for small values of `left + right` or for large `T`. The elements are moved +/// into their final positions one at a time starting at `mid - left` and advancing by `right` steps +/// modulo `left + right`, such that only one temporary is needed. Eventually, we arrive back at +/// `mid - left`. However, if `gcd(left + right, right)` is not 1, the above steps skipped over +/// elements. For example: /// ```text -/// [ 6 7 8 9 10 11 12 13 . 1 2 3 4 5 ] -/// 1 2 3 4 5 [ 11 12 13 . 6 7 8 9 10 ] -/// 1 2 3 4 5 [ 8 9 10 . 6 7 ] 11 12 13 -/// 1 2 3 4 5 6 7 [ 10 . 8 9 ] 11 12 13 -/// 1 2 3 4 5 6 7 [ 9 . 8 ] 10 11 12 13 -/// 1 2 3 4 5 6 7 8 [ . ] 9 10 11 12 13 +/// left = 10, right = 6 +/// the `^` indicates an element in its final place +/// 6 7 8 9 10 11 12 13 14 15 . 0 1 2 3 4 5 +/// after using one step of the above algorithm (The X will be overwritten at the end of the round, +/// and 12 is stored in a temporary): +/// X 7 8 9 10 11 6 13 14 15 . 0 1 2 3 4 5 +/// ^ +/// after using another step (now 2 is in the temporary): +/// X 7 8 9 10 11 6 13 14 15 . 0 1 12 3 4 5 +/// ^ ^ +/// after the third step (the steps wrap around, and 8 is in the temporary): +/// X 7 2 9 10 11 6 13 14 15 . 0 1 12 3 4 5 +/// ^ ^ ^ +/// after 7 more steps, the round ends with the temporary 0 getting put in the X: +/// 0 7 2 9 4 11 6 13 8 15 . 10 1 12 3 14 5 +/// ^ ^ ^ ^ ^ ^ ^ ^ /// ``` +/// Fortunately, the number of skipped over elements between finalized elements is always equal, so +/// we can just offset our starting position and do more rounds (the total number of rounds is the +/// `gcd(left + right, right)` value). The end result is that all elements are finalized once and +/// only once. +/// +/// Algorithm 2 is used if `left + right` is large but `min(left, right)` is small enough to +/// fit onto a stack buffer. The `min(left, right)` elements are copied onto the buffer, `memmove` +/// is applied to the others, and the ones on the buffer are moved back into the hole on the +/// opposite side of where they originated. +/// +/// Algorithms that can be vectorized outperform the above once `left + right` becomes large enough. +/// Algorithm 1 can be vectorized by chunking and performing many rounds at once, but there are too +/// few rounds on average until `left + right` is enormous, and the worst case of a single +/// round is always there. Instead, algorithm 3 utilizes repeated swapping of +/// `min(left, right)` elements until a smaller rotate problem is left. /// -/// Once the rotation is small enough, copy some elements into a stack -/// buffer, `memmove` the others, and move the ones back from the buffer. -pub unsafe fn ptr_rotate(mut left: usize, mid: *mut T, mut right: usize) { +/// ```text +/// left = 11, right = 4 +/// [4 5 6 7 8 9 10 11 12 13 14 . 0 1 2 3] +/// ^ ^ ^ ^ ^ ^ ^ ^ swapping the right most elements with elements to the left +/// [4 5 6 7 8 9 10 . 0 1 2 3] 11 12 13 14 +/// ^ ^ ^ ^ ^ ^ ^ ^ swapping these +/// [4 5 6 . 0 1 2 3] 7 8 9 10 11 12 13 14 +/// we cannot swap any more, but a smaller rotation problem is left to solve +/// ``` +/// when `left < right` the swapping happens from the left instead. +pub unsafe fn ptr_rotate(mut left: usize, mut mid: *mut T, mut right: usize) { + type BufType = [usize; 32]; + if mem::size_of::() == 0 { + return; + } loop { - let delta = cmp::min(left, right); - if delta <= RawArray::::capacity() { - // We will always hit this immediately for ZST. - break; + // N.B. the below algorithms can fail if these cases are not checked + if (right == 0) || (left == 0) { + return; } - - ptr::swap_nonoverlapping( - mid.sub(left), - mid.add(right - delta), - delta); - - if left <= right { - right -= delta; + if (left + right < 24) || (mem::size_of::() > mem::size_of::<[usize; 4]>()) { + // Algorithm 1 + // Microbenchmarks indicate that the average performance for random shifts is better all + // the way until about `left + right == 32`, but the worst case performance breaks even + // around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4 + // `usize`s, this algorithm also outperforms other algorithms. + let x = mid.sub(left); + // beginning of first round + let mut tmp: T = x.read(); + let mut i = right; + // `gcd` can be found before hand by calculating `gcd(left + right, right)`, + // but it is faster to do one loop which calculates the gcd as a side effect, then + // doing the rest of the chunk + let mut gcd = right; + // benchmarks reveal that it is faster to swap temporaries all the way through instead + // of reading one temporary once, copying backwards, and then writing that temporary at + // the very end. This is possibly due to the fact that swapping or replacing temporaries + // uses only one memory address in the loop instead of needing to manage two. + loop { + tmp = x.add(i).replace(tmp); + // instead of incrementing `i` and then checking if it is outside the bounds, we + // check if `i` will go outside the bounds on the next increment. This prevents + // any wrapping of pointers or `usize`. + if i >= left { + i -= left; + if i == 0 { + // end of first round + x.write(tmp); + break; + } + // this conditional must be here if `left + right >= 15` + if i < gcd { + gcd = i; + } + } else { + i += right; + } + } + // finish the chunk with more rounds + for start in 1..gcd { + tmp = x.add(start).read(); + i = start + right; + loop { + tmp = x.add(i).replace(tmp); + if i >= left { + i -= left; + if i == start { + x.add(start).write(tmp); + break; + } + } else { + i += right; + } + } + } + return; + // `T` is not a zero-sized type, so it's okay to divide by its size. + } else if cmp::min(left, right) <= mem::size_of::() / mem::size_of::() { + // Algorithm 2 + // The `[T; 0]` here is to ensure this is appropriately aligned for T + let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit(); + let buf = rawarray.as_mut_ptr() as *mut T; + let dim = mid.sub(left).add(right); + if left <= right { + ptr::copy_nonoverlapping(mid.sub(left), buf, left); + ptr::copy(mid, mid.sub(left), right); + ptr::copy_nonoverlapping(buf, dim, left); + } else { + ptr::copy_nonoverlapping(mid, buf, right); + ptr::copy(mid.sub(left), dim, left); + ptr::copy_nonoverlapping(buf, mid.sub(left), right); + } + return; + } else if left >= right { + // Algorithm 3 + // There is an alternate way of swapping that involves finding where the last swap + // of this algorithm would be, and swapping using that last chunk instead of swapping + // adjacent chunks like this algorithm is doing, but this way is still faster. + loop { + ptr::swap_nonoverlapping(mid.sub(right), mid, right); + mid = mid.sub(right); + left -= right; + if left < right { + break; + } + } } else { - left -= delta; + // Algorithm 3, `left < right` + loop { + ptr::swap_nonoverlapping(mid.sub(left), mid, left); + mid = mid.add(left); + right -= left; + if right < left { + break; + } + } } } - - let mut rawarray = MaybeUninit::>::uninit(); - let buf = &mut (*rawarray.as_mut_ptr()).typed as *mut [T; 2] as *mut T; - - let dim = mid.sub(left).add(right); - if left <= right { - ptr::copy_nonoverlapping(mid.sub(left), buf, left); - ptr::copy(mid, mid.sub(left), right); - ptr::copy_nonoverlapping(buf, dim, left); - } - else { - ptr::copy_nonoverlapping(mid, buf, right); - ptr::copy(mid.sub(left), dim, left); - ptr::copy_nonoverlapping(buf, mid.sub(left), right); - } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 4faf9ff4d2ee2..885696e5acf49 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -851,8 +851,9 @@ unsafe impl TrustedRandomAccess for Bytes<'_> { /// wrapper types of the form X<'a, P> macro_rules! derive_pattern_clone { (clone $t:ident with |$s:ident| $e:expr) => { - impl<'a, P: Pattern<'a>> Clone for $t<'a, P> - where P::Searcher: Clone + impl<'a, P> Clone for $t<'a, P> + where + P: Pattern<'a, Searcher: Clone>, { fn clone(&self) -> Self { let $s = self; @@ -928,8 +929,9 @@ macro_rules! generate_pattern_iterators { pub struct $forward_iterator<'a, P: Pattern<'a>>($internal_iterator<'a, P>); $(#[$common_stability_attribute])* - impl<'a, P: Pattern<'a>> fmt::Debug for $forward_iterator<'a, P> - where P::Searcher: fmt::Debug + impl<'a, P> fmt::Debug for $forward_iterator<'a, P> + where + P: Pattern<'a, Searcher: fmt::Debug>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple(stringify!($forward_iterator)) @@ -949,8 +951,9 @@ macro_rules! generate_pattern_iterators { } $(#[$common_stability_attribute])* - impl<'a, P: Pattern<'a>> Clone for $forward_iterator<'a, P> - where P::Searcher: Clone + impl<'a, P> Clone for $forward_iterator<'a, P> + where + P: Pattern<'a, Searcher: Clone>, { fn clone(&self) -> Self { $forward_iterator(self.0.clone()) @@ -962,8 +965,9 @@ macro_rules! generate_pattern_iterators { pub struct $reverse_iterator<'a, P: Pattern<'a>>($internal_iterator<'a, P>); $(#[$common_stability_attribute])* - impl<'a, P: Pattern<'a>> fmt::Debug for $reverse_iterator<'a, P> - where P::Searcher: fmt::Debug + impl<'a, P> fmt::Debug for $reverse_iterator<'a, P> + where + P: Pattern<'a, Searcher: fmt::Debug>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple(stringify!($reverse_iterator)) @@ -973,8 +977,9 @@ macro_rules! generate_pattern_iterators { } $(#[$common_stability_attribute])* - impl<'a, P: Pattern<'a>> Iterator for $reverse_iterator<'a, P> - where P::Searcher: ReverseSearcher<'a> + impl<'a, P> Iterator for $reverse_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { type Item = $iterty; @@ -985,8 +990,9 @@ macro_rules! generate_pattern_iterators { } $(#[$common_stability_attribute])* - impl<'a, P: Pattern<'a>> Clone for $reverse_iterator<'a, P> - where P::Searcher: Clone + impl<'a, P> Clone for $reverse_iterator<'a, P> + where + P: Pattern<'a, Searcher: Clone>, { fn clone(&self) -> Self { $reverse_iterator(self.0.clone()) @@ -997,8 +1003,10 @@ macro_rules! generate_pattern_iterators { impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} #[stable(feature = "fused", since = "1.26.0")] - impl<'a, P: Pattern<'a>> FusedIterator for $reverse_iterator<'a, P> - where P::Searcher: ReverseSearcher<'a> {} + impl<'a, P> FusedIterator for $reverse_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + {} generate_pattern_iterators!($($t)* with $(#[$common_stability_attribute])*, $forward_iterator, @@ -1010,8 +1018,9 @@ macro_rules! generate_pattern_iterators { $reverse_iterator:ident, $iterty:ty } => { $(#[$common_stability_attribute])* - impl<'a, P: Pattern<'a>> DoubleEndedIterator for $forward_iterator<'a, P> - where P::Searcher: DoubleEndedSearcher<'a> + impl<'a, P> DoubleEndedIterator for $forward_iterator<'a, P> + where + P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, { #[inline] fn next_back(&mut self) -> Option<$iterty> { @@ -1020,8 +1029,9 @@ macro_rules! generate_pattern_iterators { } $(#[$common_stability_attribute])* - impl<'a, P: Pattern<'a>> DoubleEndedIterator for $reverse_iterator<'a, P> - where P::Searcher: DoubleEndedSearcher<'a> + impl<'a, P> DoubleEndedIterator for $reverse_iterator<'a, P> + where + P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, { #[inline] fn next_back(&mut self) -> Option<$iterty> { @@ -1049,7 +1059,10 @@ struct SplitInternal<'a, P: Pattern<'a>> { finished: bool, } -impl<'a, P: Pattern<'a>> fmt::Debug for SplitInternal<'a, P> where P::Searcher: fmt::Debug { +impl<'a, P> fmt::Debug for SplitInternal<'a, P> +where + P: Pattern<'a, Searcher: fmt::Debug>, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SplitInternal") .field("start", &self.start) @@ -1166,7 +1179,10 @@ struct SplitNInternal<'a, P: Pattern<'a>> { count: usize, } -impl<'a, P: Pattern<'a>> fmt::Debug for SplitNInternal<'a, P> where P::Searcher: fmt::Debug { +impl<'a, P> fmt::Debug for SplitNInternal<'a, P> +where + P: Pattern<'a, Searcher: fmt::Debug>, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SplitNInternal") .field("iter", &self.iter) @@ -1222,7 +1238,10 @@ derive_pattern_clone!{ struct MatchIndicesInternal<'a, P: Pattern<'a>>(P::Searcher); -impl<'a, P: Pattern<'a>> fmt::Debug for MatchIndicesInternal<'a, P> where P::Searcher: fmt::Debug { +impl<'a, P> fmt::Debug for MatchIndicesInternal<'a, P> +where + P: Pattern<'a, Searcher: fmt::Debug>, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("MatchIndicesInternal") .field(&self.0) @@ -1273,7 +1292,10 @@ derive_pattern_clone!{ struct MatchesInternal<'a, P: Pattern<'a>>(P::Searcher); -impl<'a, P: Pattern<'a>> fmt::Debug for MatchesInternal<'a, P> where P::Searcher: fmt::Debug { +impl<'a, P> fmt::Debug for MatchesInternal<'a, P> +where + P: Pattern<'a, Searcher: fmt::Debug>, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("MatchesInternal") .field(&self.0) @@ -2068,7 +2090,6 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - #[rustc_const_unstable(feature = "const_str_len")] pub const fn len(&self) -> usize { self.as_bytes().len() } @@ -2088,7 +2109,6 @@ impl str { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_str_len")] pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -2146,8 +2166,11 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline(always)] - #[rustc_const_unstable(feature="const_str_as_bytes")] + // SAFETY: const sound because we transmute two types with the same layout + #[allow(unused_attributes)] + #[allow_internal_unstable(const_fn_union)] pub const fn as_bytes(&self) -> &[u8] { + #[repr(C)] union Slices<'a> { str: &'a str, slice: &'a [u8], @@ -2882,8 +2905,9 @@ impl str { /// assert!(!bananas.ends_with("nana")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool - where P::Searcher: ReverseSearcher<'a> + pub fn ends_with<'a, P>(&'a self, pat: P) -> bool + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { pat.is_suffix_of(self) } @@ -2975,8 +2999,9 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option - where P::Searcher: ReverseSearcher<'a> + pub fn rfind<'a, P>(&'a self, pat: P) -> Option + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { pat.into_searcher(self).next_match_back().map(|(i, _)| i) } @@ -3142,8 +3167,9 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> - where P::Searcher: ReverseSearcher<'a> + pub fn rsplit<'a, P>(&'a self, pat: P) -> RSplit<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { RSplit(self.split(pat).0) } @@ -3233,8 +3259,9 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> - where P::Searcher: ReverseSearcher<'a> + pub fn rsplit_terminator<'a, P>(&'a self, pat: P) -> RSplitTerminator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { RSplitTerminator(self.split_terminator(pat).0) } @@ -3333,8 +3360,9 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P> - where P::Searcher: ReverseSearcher<'a> + pub fn rsplitn<'a, P>(&'a self, n: usize, pat: P) -> RSplitN<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { RSplitN(self.splitn(n, pat).0) } @@ -3406,8 +3434,9 @@ impl str { /// ``` #[stable(feature = "str_matches", since = "1.2.0")] #[inline] - pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> - where P::Searcher: ReverseSearcher<'a> + pub fn rmatches<'a, P>(&'a self, pat: P) -> RMatches<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { RMatches(self.matches(pat).0) } @@ -3491,8 +3520,9 @@ impl str { /// ``` #[stable(feature = "str_match_indices", since = "1.5.0")] #[inline] - pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> - where P::Searcher: ReverseSearcher<'a> + pub fn rmatch_indices<'a, P>(&'a self, pat: P) -> RMatchIndices<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { RMatchIndices(self.match_indices(pat).0) } @@ -3528,7 +3558,7 @@ impl str { /// A string is a sequence of bytes. `start` in this context means the first /// position of that byte string; for a left-to-right language like English or /// Russian, this will be left side, and for right-to-left languages like - /// like Arabic or Hebrew, this will be the right side. + /// Arabic or Hebrew, this will be the right side. /// /// # Examples /// @@ -3565,7 +3595,7 @@ impl str { /// A string is a sequence of bytes. `end` in this context means the last /// position of that byte string; for a left-to-right language like English or /// Russian, this will be right side, and for right-to-left languages like - /// like Arabic or Hebrew, this will be the left side. + /// Arabic or Hebrew, this will be the left side. /// /// # Examples /// @@ -3700,8 +3730,9 @@ impl str { #[must_use = "this returns the trimmed string as a new slice, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: DoubleEndedSearcher<'a> + pub fn trim_matches<'a, P>(&'a self, pat: P) -> &'a str + where + P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, { let mut i = 0; let mut j = 0; @@ -3731,7 +3762,7 @@ impl str { /// A string is a sequence of bytes. `start` in this context means the first /// position of that byte string; for a left-to-right language like English or /// Russian, this will be left side, and for right-to-left languages like - /// like Arabic or Hebrew, this will be the right side. + /// Arabic or Hebrew, this will be the right side. /// /// # Examples /// @@ -3770,7 +3801,7 @@ impl str { /// A string is a sequence of bytes. `end` in this context means the last /// position of that byte string; for a left-to-right language like English or /// Russian, this will be right side, and for right-to-left languages like - /// like Arabic or Hebrew, this will be the left side. + /// Arabic or Hebrew, this will be the left side. /// /// # Examples /// @@ -3792,8 +3823,9 @@ impl str { #[must_use = "this returns the trimmed string as a new slice, \ without modifying the original"] #[stable(feature = "trim_direction", since = "1.30.0")] - pub fn trim_end_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: ReverseSearcher<'a> + pub fn trim_end_matches<'a, P>(&'a self, pat: P) -> &'a str + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { let mut j = 0; let mut matcher = pat.into_searcher(self); @@ -3880,8 +3912,9 @@ impl str { reason = "superseded by `trim_end_matches`", suggestion = "trim_end_matches", )] - pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: ReverseSearcher<'a> + pub fn trim_right_matches<'a, P>(&'a self, pat: P) -> &'a str + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { self.trim_end_matches(pat) } diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 8dfb19fa03296..c9ccef972c2b5 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -124,28 +124,31 @@ use crate::fmt; use crate::hint::spin_loop; -/// Signals the processor that it is entering a busy-wait spin-loop. +/// Signals the processor that it is inside a busy-wait spin-loop ("spin lock"). /// /// Upon receiving spin-loop signal the processor can optimize its behavior by, for example, saving /// power or switching hyper-threads. /// -/// This function is different than [`std::thread::yield_now`] which directly yields to the -/// system's scheduler, whereas `spin_loop_hint` only signals the processor that it is entering a -/// busy-wait spin-loop without yielding control to the system's scheduler. +/// This function is different from [`std::thread::yield_now`] which directly yields to the +/// system's scheduler, whereas `spin_loop_hint` does not interact with the operating system. /// -/// Using a busy-wait spin-loop with `spin_loop_hint` is ideally used in situations where a -/// contended lock is held by another thread executed on a different CPU and where the waiting -/// times are relatively small. Because entering busy-wait spin-loop does not trigger the system's -/// scheduler, no overhead for switching threads occurs. However, if the thread holding the -/// contended lock is running on the same CPU, the spin-loop is likely to occupy an entire CPU slice -/// before switching to the thread that holds the lock. If the contending lock is held by a thread -/// on the same CPU or if the waiting times for acquiring the lock are longer, it is often better to -/// use [`std::thread::yield_now`]. +/// Spin locks can be very efficient for short lock durations because they do not involve context +/// switches or interaction with the operating system. For long lock durations they become wasteful +/// however because they use CPU cycles for the entire lock duration, and using a +/// [`std::sync::Mutex`] is likely the better approach. If actively spinning for a long time is +/// required, e.g. because code polls a non-blocking API, calling [`std::thread::yield_now`] +/// or [`std::thread::sleep`] may be the best option. +/// +/// **Note**: Spin locks are based on the underlying assumption that another thread will release +/// the lock 'soon'. In order for this to work, that other thread must run on a different CPU or +/// core (at least potentially). Spin locks do not work efficiently on single CPU / core platforms. /// /// **Note**: On platforms that do not support receiving spin-loop hints this function does not /// do anything at all. /// /// [`std::thread::yield_now`]: ../../../std/thread/fn.yield_now.html +/// [`std::thread::sleep`]: ../../../std/thread/fn.sleep.html +/// [`std::sync::Mutex`]: ../../../std/sync/struct.Mutex.html #[inline] #[stable(feature = "spin_loop_hint", since = "1.24.0")] pub fn spin_loop_hint() { @@ -979,9 +982,8 @@ impl AtomicPtr { /// let some_ptr = AtomicPtr::new(ptr); /// /// let other_ptr = &mut 10; - /// let another_ptr = &mut 10; /// - /// let value = some_ptr.compare_and_swap(other_ptr, another_ptr, Ordering::Relaxed); + /// let value = some_ptr.compare_and_swap(ptr, other_ptr, Ordering::Relaxed); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -1021,9 +1023,8 @@ impl AtomicPtr { /// let some_ptr = AtomicPtr::new(ptr); /// /// let other_ptr = &mut 10; - /// let another_ptr = &mut 10; /// - /// let value = some_ptr.compare_exchange(other_ptr, another_ptr, + /// let value = some_ptr.compare_exchange(ptr, other_ptr, /// Ordering::SeqCst, Ordering::Relaxed); /// ``` #[inline] diff --git a/src/libcore/task/poll.rs b/src/libcore/task/poll.rs index 3db70d5e7645f..fec17c4d1a4df 100644 --- a/src/libcore/task/poll.rs +++ b/src/libcore/task/poll.rs @@ -81,6 +81,34 @@ impl Poll> { } } +impl Poll>> { + /// Changes the success value of this `Poll` with the closure provided. + #[unstable(feature = "poll_map", issue = "63514")] + pub fn map_ok(self, f: F) -> Poll>> + where F: FnOnce(T) -> U + { + match self { + Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(f(t)))), + Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))), + Poll::Ready(None) => Poll::Ready(None), + Poll::Pending => Poll::Pending, + } + } + + /// Changes the error value of this `Poll` with the closure provided. + #[unstable(feature = "poll_map", issue = "63514")] + pub fn map_err(self, f: F) -> Poll>> + where F: FnOnce(E) -> U + { + match self { + Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(t))), + Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(f(e)))), + Poll::Ready(None) => Poll::Ready(None), + Poll::Pending => Poll::Pending, + } + } +} + #[stable(feature = "futures_api", since = "1.36.0")] impl From for Poll { fn from(t: T) -> Poll { diff --git a/src/libcore/tests/bool.rs b/src/libcore/tests/bool.rs new file mode 100644 index 0000000000000..0f1e6e89451e9 --- /dev/null +++ b/src/libcore/tests/bool.rs @@ -0,0 +1,7 @@ +#[test] +fn test_bool_to_option() { + assert_eq!(false.then(0), None); + assert_eq!(true.then(0), Some(0)); + assert_eq!(false.then_with(|| 0), None); + assert_eq!(true.then_with(|| 0), Some(0)); +} diff --git a/src/libcore/tests/cmp.rs b/src/libcore/tests/cmp.rs index 4e624e5eb126e..5e6778e222a29 100644 --- a/src/libcore/tests/cmp.rs +++ b/src/libcore/tests/cmp.rs @@ -1,4 +1,4 @@ -use core::cmp::Ordering::{Less, Greater, Equal}; +use core::cmp::{self, Ordering::*}; #[test] fn test_int_totalord() { @@ -28,6 +28,28 @@ fn test_ord_max_min() { assert_eq!(1.min(1), 1); } +#[test] +fn test_ord_min_max_by() { + let f = |x: &i32, y: &i32| x.abs().cmp(&y.abs()); + assert_eq!(cmp::min_by(1, -1, f), 1); + assert_eq!(cmp::min_by(1, -2, f), 1); + assert_eq!(cmp::min_by(2, -1, f), -1); + assert_eq!(cmp::max_by(1, -1, f), -1); + assert_eq!(cmp::max_by(1, -2, f), -2); + assert_eq!(cmp::max_by(2, -1, f), 2); +} + +#[test] +fn test_ord_min_max_by_key() { + let f = |x: &i32| x.abs(); + assert_eq!(cmp::min_by_key(1, -1, f), 1); + assert_eq!(cmp::min_by_key(1, -2, f), 1); + assert_eq!(cmp::min_by_key(2, -1, f), -1); + assert_eq!(cmp::max_by_key(1, -1, f), -1); + assert_eq!(cmp::max_by_key(1, -2, f), -2); + assert_eq!(cmp::max_by_key(2, -1, f), 2); +} + #[test] fn test_ordering_reverse() { assert_eq!(Less.reverse(), Greater); diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 3615fab791505..c9096b713f20e 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -57,6 +57,62 @@ fn test_multi_iter() { assert!(xs.iter().lt(xs.iter().skip(2))); } +#[test] +fn test_cmp_by() { + use core::cmp::Ordering; + + let f = |x: i32, y: i32| (x * x).cmp(&y); + let xs = || [1, 2, 3, 4].iter().copied(); + let ys = || [1, 4, 16].iter().copied(); + + assert_eq!(xs().cmp_by(ys(), f), Ordering::Less); + assert_eq!(ys().cmp_by(xs(), f), Ordering::Greater); + assert_eq!(xs().cmp_by(xs().map(|x| x * x), f), Ordering::Equal); + assert_eq!(xs().rev().cmp_by(ys().rev(), f), Ordering::Greater); + assert_eq!(xs().cmp_by(ys().rev(), f), Ordering::Less); + assert_eq!(xs().cmp_by(ys().take(2), f), Ordering::Greater); +} + +#[test] +fn test_partial_cmp_by() { + use core::cmp::Ordering; + use core::f64; + + let f = |x: i32, y: i32| (x * x).partial_cmp(&y); + let xs = || [1, 2, 3, 4].iter().copied(); + let ys = || [1, 4, 16].iter().copied(); + + assert_eq!(xs().partial_cmp_by(ys(), f), Some(Ordering::Less)); + assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater)); + assert_eq!(xs().partial_cmp_by(xs().map(|x| x * x), f), Some(Ordering::Equal)); + assert_eq!(xs().rev().partial_cmp_by(ys().rev(), f), Some(Ordering::Greater)); + assert_eq!(xs().partial_cmp_by(xs().rev(), f), Some(Ordering::Less)); + assert_eq!(xs().partial_cmp_by(ys().take(2), f), Some(Ordering::Greater)); + + let f = |x: f64, y: f64| (x * x).partial_cmp(&y); + let xs = || [1.0, 2.0, 3.0, 4.0].iter().copied(); + let ys = || [1.0, 4.0, f64::NAN, 16.0].iter().copied(); + + assert_eq!(xs().partial_cmp_by(ys(), f), None); + assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater)); +} + +#[test] +fn test_eq_by() { + let f = |x: i32, y: i32| x * x == y; + let xs = || [1, 2, 3, 4].iter().copied(); + let ys = || [1, 4, 9, 16].iter().copied(); + + assert!(xs().eq_by(ys(), f)); + assert!(!ys().eq_by(xs(), f)); + assert!(!xs().eq_by(xs(), f)); + assert!(!ys().eq_by(ys(), f)); + + assert!(!xs().take(3).eq_by(ys(), f)); + assert!(!xs().eq_by(ys().take(3), f)); + assert!(xs().take(3).eq_by(ys().take(3), f)); +} + #[test] fn test_counter_from_iter() { let it = (0..).step_by(5).take(10); @@ -103,6 +159,22 @@ fn test_iterator_chain_nth() { assert_eq!(it.next(), None); } +#[test] +fn test_iterator_chain_nth_back() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let zs = []; + let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; + for (i, x) in expected.iter().rev().enumerate() { + assert_eq!(Some(x), xs.iter().chain(&ys).nth_back(i)); + } + assert_eq!(zs.iter().chain(&xs).nth_back(0), Some(&5)); + + let mut it = xs.iter().chain(&zs); + assert_eq!(it.nth_back(5), Some(&0)); + assert_eq!(it.next(), None); +} + #[test] fn test_iterator_chain_last() { let xs = [0, 1, 2, 3, 4, 5]; @@ -136,6 +208,54 @@ fn test_iterator_chain_find() { assert_eq!(iter.next(), None); } +#[test] +fn test_iterator_chain_size_hint() { + struct Iter { + is_empty: bool, + } + + impl Iterator for Iter { + type Item = (); + + // alternates between `None` and `Some(())` + fn next(&mut self) -> Option { + if self.is_empty { + self.is_empty = false; + None + } else { + self.is_empty = true; + Some(()) + } + } + + fn size_hint(&self) -> (usize, Option) { + if self.is_empty { + (0, Some(0)) + } else { + (1, Some(1)) + } + } + } + + impl DoubleEndedIterator for Iter { + fn next_back(&mut self) -> Option { + self.next() + } + } + + // this chains an iterator of length 0 with an iterator of length 1, + // so after calling `.next()` once, the iterator is empty and the + // state is `ChainState::Back`. `.size_hint()` should now disregard + // the size hint of the left iterator + let mut iter = Iter { is_empty: true }.chain(once(())); + assert_eq!(iter.next(), Some(())); + assert_eq!(iter.size_hint(), (0, Some(0))); + + let mut iter = once(()).chain(Iter { is_empty: true }); + assert_eq!(iter.next_back(), Some(())); + assert_eq!(iter.size_hint(), (0, Some(0))); +} + #[test] fn test_zip_nth() { let xs = [0, 1, 2, 4, 5]; @@ -265,6 +385,23 @@ fn test_iterator_step_by_nth_overflow() { assert_eq!(it.0, (usize::MAX as Bigger) * 1); } +#[test] +fn test_iterator_step_by_nth_try_fold() { + let mut it = (0..).step_by(10); + assert_eq!(it.try_fold(0, i8::checked_add), None); + assert_eq!(it.next(), Some(60)); + assert_eq!(it.try_fold(0, i8::checked_add), None); + assert_eq!(it.next(), Some(90)); + + let mut it = (100..).step_by(10); + assert_eq!(it.try_fold(50, i8::checked_add), None); + assert_eq!(it.next(), Some(110)); + + let mut it = (100..=100).step_by(10); + assert_eq!(it.next(), Some(100)); + assert_eq!(it.try_fold(0, i8::checked_add), Some(0)); +} + #[test] fn test_iterator_step_by_nth_back() { let mut it = (0..16).step_by(5); @@ -290,6 +427,24 @@ fn test_iterator_step_by_nth_back() { assert_eq!(it().nth_back(42), None); } +#[test] +fn test_iterator_step_by_nth_try_rfold() { + let mut it = (0..100).step_by(10); + assert_eq!(it.try_rfold(0, i8::checked_add), None); + assert_eq!(it.next_back(), Some(70)); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.try_rfold(0, i8::checked_add), None); + assert_eq!(it.next_back(), Some(30)); + + let mut it = (0..100).step_by(10); + assert_eq!(it.try_rfold(50, i8::checked_add), None); + assert_eq!(it.next_back(), Some(80)); + + let mut it = (100..=100).step_by(10); + assert_eq!(it.next_back(), Some(100)); + assert_eq!(it.try_fold(0, i8::checked_add), Some(0)); +} + #[test] #[should_panic] fn test_iterator_step_by_zero() { @@ -1136,6 +1291,18 @@ fn test_cycle() { assert_eq!(empty::().cycle().fold(0, |acc, x| acc + x), 0); assert_eq!(once(1).cycle().skip(1).take(4).fold(0, |acc, x| acc + x), 4); + + assert_eq!((0..10).cycle().take(5).sum::(), 10); + assert_eq!((0..10).cycle().take(15).sum::(), 55); + assert_eq!((0..10).cycle().take(25).sum::(), 100); + + let mut iter = (0..10).cycle(); + iter.nth(14); + assert_eq!(iter.take(8).sum::(), 38); + + let mut iter = (0..10).cycle(); + iter.nth(9); + assert_eq!(iter.take(3).sum::(), 3); } #[test] @@ -1612,6 +1779,12 @@ fn test_rposition() { assert!(v.iter().rposition(g).is_none()); } +#[test] +fn test_rev_rposition() { + let v = [0, 0, 1, 1]; + assert_eq!(v.iter().rev().rposition(|&x| x == 1), Some(1)); +} + #[test] #[should_panic] fn test_rposition_panic() { diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index a3b108b2e9cea..35661356028cb 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -1,3 +1,4 @@ +#![feature(bool_to_option)] #![feature(bound_cloned)] #![feature(box_syntax)] #![feature(cell_update)] @@ -32,6 +33,8 @@ #![feature(const_fn)] #![feature(iter_partition_in_place)] #![feature(iter_is_partitioned)] +#![feature(iter_order_by)] +#![feature(cmp_min_max_by)] extern crate test; @@ -40,6 +43,7 @@ mod any; mod array; mod ascii; mod atomic; +mod bool; mod cell; mod char; mod clone; diff --git a/src/libcore/tests/num/dec2flt/mod.rs b/src/libcore/tests/num/dec2flt/mod.rs index 0e71426c64108..46eacb4200acc 100644 --- a/src/libcore/tests/num/dec2flt/mod.rs +++ b/src/libcore/tests/num/dec2flt/mod.rs @@ -77,6 +77,7 @@ fn infinity() { fn zero() { test_literal!(0.0); test_literal!(1e-325); + #[cfg(not(miri))] // Miri is too slow test_literal!(1e-326); #[cfg(not(miri))] // Miri is too slow test_literal!(1e-500); diff --git a/src/libcore/tests/num/flt2dec/estimator.rs b/src/libcore/tests/num/flt2dec/estimator.rs index 2dbb8e3a5f06e..c51451708f3ce 100644 --- a/src/libcore/tests/num/flt2dec/estimator.rs +++ b/src/libcore/tests/num/flt2dec/estimator.rs @@ -42,7 +42,12 @@ fn test_estimate_scaling_factor() { assert_almost_eq!(estimate_scaling_factor(1, -1074), -323); assert_almost_eq!(estimate_scaling_factor(0x1fffffffffffff, 971), 309); - for i in -1074..972 { + #[cfg(not(miri))] // Miri is too slow + let iter = -1074..972; + #[cfg(miri)] + let iter = (-1074..972).step_by(37); + + for i in iter { let expected = super::ldexp_f64(1.0, i).log10().ceil(); assert_almost_eq!(estimate_scaling_factor(1, i as i16), expected as i16); } diff --git a/src/libcore/tests/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs index f42f500c2df1d..c41d35efced6c 100644 --- a/src/libcore/tests/num/flt2dec/mod.rs +++ b/src/libcore/tests/num/flt2dec/mod.rs @@ -1,5 +1,3 @@ -#![cfg(not(miri))] // Miri does not implement ldexp, which most tests here need - use std::prelude::v1::*; use std::{str, i16, f32, f64, fmt}; @@ -257,6 +255,7 @@ pub fn f32_shortest_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8]) check_shortest!(f(minf32) => b"1", -44); } +#[cfg(not(miri))] // Miri is too slow pub fn f32_exact_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { let minf32 = ldexp_f32(1.0, -149); @@ -362,6 +361,7 @@ pub fn f64_shortest_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8]) check_shortest!(f(minf64) => b"5", -323); } +#[cfg(not(miri))] // Miri is too slow pub fn f64_exact_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { let minf64 = ldexp_f64(1.0, -1074); @@ -553,6 +553,10 @@ pub fn to_shortest_str_test(mut f_: F) assert_eq!(to_string(f, minf64, Minus, 324, false), format!("0.{:0>323}5", "")); assert_eq!(to_string(f, minf64, Minus, 325, false), format!("0.{:0>323}50", "")); + if cfg!(miri) { // Miri is too slow + return; + } + // very large output assert_eq!(to_string(f, 1.1, Minus, 80000, false), format!("1.1{:0>79999}", "")); } @@ -807,6 +811,10 @@ pub fn to_exact_exp_str_test(mut f_: F) "1.401298464324817070923729583289916131280261941876515771757068283\ 8897910826858606014866381883621215820312500000000000000000000000e-45"); + if cfg!(miri) { // Miri is too slow + return; + } + assert_eq!(to_string(f, f64::MAX, Minus, 1, false), "2e308"); assert_eq!(to_string(f, f64::MAX, Minus, 2, false), "1.8e308"); assert_eq!(to_string(f, f64::MAX, Minus, 4, false), "1.798e308"); @@ -1040,6 +1048,10 @@ pub fn to_exact_fixed_str_test(mut f_: F) assert_eq!(to_string(f, f32::MAX, Minus, 2, false), "340282346638528859811704183484516925440.00"); + if cfg!(miri) { // Miri is too slow + return; + } + let minf32 = ldexp_f32(1.0, -149); assert_eq!(to_string(f, minf32, Minus, 0, false), "0"); assert_eq!(to_string(f, minf32, Minus, 1, false), "0.0"); diff --git a/src/libcore/tests/num/flt2dec/random.rs b/src/libcore/tests/num/flt2dec/random.rs index d56787b2819a7..d9543793397bf 100644 --- a/src/libcore/tests/num/flt2dec/random.rs +++ b/src/libcore/tests/num/flt2dec/random.rs @@ -109,8 +109,13 @@ pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) #[test] fn shortest_random_equivalence_test() { use core::num::flt2dec::strategy::dragon::format_shortest as fallback; - f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); - f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); + #[cfg(not(miri))] // Miri is too slow + const N: usize = 10_000; + #[cfg(miri)] + const N: usize = 10; + + f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, N); + f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, N); } #[test] #[ignore] // it is too expensive @@ -138,17 +143,27 @@ fn shortest_f64_hard_random_equivalence_test() { #[test] fn exact_f32_random_equivalence_test() { use core::num::flt2dec::strategy::dragon::format_exact as fallback; + #[cfg(not(miri))] // Miri is too slow + const N: usize = 1_000; + #[cfg(miri)] + const N: usize = 3; + for k in 1..21 { f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), - |d, buf| fallback(d, buf, i16::MIN), k, 1_000); + |d, buf| fallback(d, buf, i16::MIN), k, N); } } #[test] fn exact_f64_random_equivalence_test() { use core::num::flt2dec::strategy::dragon::format_exact as fallback; + #[cfg(not(miri))] // Miri is too slow + const N: usize = 1_000; + #[cfg(miri)] + const N: usize = 3; + for k in 1..21 { f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), - |d, buf| fallback(d, buf, i16::MIN), k, 1_000); + |d, buf| fallback(d, buf, i16::MIN), k, N); } } diff --git a/src/libcore/tests/num/flt2dec/strategy/dragon.rs b/src/libcore/tests/num/flt2dec/strategy/dragon.rs index 5e4cc23d33c8c..dc4d78bfae109 100644 --- a/src/libcore/tests/num/flt2dec/strategy/dragon.rs +++ b/src/libcore/tests/num/flt2dec/strategy/dragon.rs @@ -23,6 +23,7 @@ fn shortest_sanity_test() { } #[test] +#[cfg(not(miri))] // Miri is too slow fn exact_sanity_test() { // This test ends up running what I can only assume is some corner-ish case // of the `exp2` library function, defined in whatever C runtime we're diff --git a/src/libcore/tests/num/flt2dec/strategy/grisu.rs b/src/libcore/tests/num/flt2dec/strategy/grisu.rs index f1afd7d4bf86f..f8bdddfe2e410 100644 --- a/src/libcore/tests/num/flt2dec/strategy/grisu.rs +++ b/src/libcore/tests/num/flt2dec/strategy/grisu.rs @@ -36,6 +36,7 @@ fn shortest_sanity_test() { } #[test] +#[cfg(not(miri))] // Miri is too slow fn exact_sanity_test() { // See comments in dragon.rs's exact_sanity_test for why this test is // ignored on MSVC diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 496e9ab76bc53..6609bc3135ae0 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -374,6 +374,25 @@ fn test_chunks_exact_mut_nth() { assert_eq!(c2.next(), None); } +#[test] +fn test_chunks_exact_mut_nth_back() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.chunks_exact_mut(2); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + assert_eq!(c.next(), None); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c2 = v2.chunks_exact_mut(3); + assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]); + assert_eq!(c2.next(), None); + assert_eq!(c2.next_back(), None); + + let v3: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c3 = v3.chunks_exact_mut(10); + assert_eq!(c3.nth_back(0), None); +} + #[test] fn test_chunks_exact_mut_last() { let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; @@ -1152,6 +1171,44 @@ fn test_rotate_right() { } } +#[test] +#[cfg(not(miri))] // Miri is too slow +fn brute_force_rotate_test_0() { + // In case of edge cases involving multiple algorithms + let n = 300; + for len in 0..n { + for s in 0..len { + let mut v = Vec::with_capacity(len); + for i in 0..len { + v.push(i); + } + v[..].rotate_right(s); + for i in 0..v.len() { + assert_eq!(v[i], v.len().wrapping_add(i.wrapping_sub(s)) % v.len()); + } + } + } +} + +#[test] +fn brute_force_rotate_test_1() { + // `ptr_rotate` covers so many kinds of pointer usage, that this is just a good test for + // pointers in general. This uses a `[usize; 4]` to hit all algorithms without overwhelming miri + let n = 30; + for len in 0..n { + for s in 0..len { + let mut v: Vec<[usize; 4]> = Vec::with_capacity(len); + for i in 0..len { + v.push([i, 0, 0, 0]); + } + v[..].rotate_right(s); + for i in 0..v.len() { + assert_eq!(v[i][0], v.len().wrapping_add(i.wrapping_sub(s)) % v.len()); + } + } + } +} + #[test] #[cfg(not(target_arch = "wasm32"))] fn sort_unstable() { diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 0f5f91f41a8cd..5a0e4388e0325 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -505,15 +505,14 @@ impl Duration { /// /// # Examples /// ``` - /// #![feature(duration_float)] /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); /// assert_eq!(dur.as_secs_f64(), 2.7); /// ``` - #[unstable(feature = "duration_float", issue = "54361")] + #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub const fn as_secs_f64(&self) -> f64 { + pub fn as_secs_f64(&self) -> f64 { (self.secs as f64) + (self.nanos as f64) / (NANOS_PER_SEC as f64) } @@ -523,15 +522,14 @@ impl Duration { /// /// # Examples /// ``` - /// #![feature(duration_float)] /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); /// assert_eq!(dur.as_secs_f32(), 2.7); /// ``` - #[unstable(feature = "duration_float", issue = "54361")] + #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub const fn as_secs_f32(&self) -> f32 { + pub fn as_secs_f32(&self) -> f32 { (self.secs as f32) + (self.nanos as f32) / (NANOS_PER_SEC as f32) } @@ -543,13 +541,12 @@ impl Duration { /// /// # Examples /// ``` - /// #![feature(duration_float)] /// use std::time::Duration; /// /// let dur = Duration::from_secs_f64(2.7); /// assert_eq!(dur, Duration::new(2, 700_000_000)); /// ``` - #[unstable(feature = "duration_float", issue = "54361")] + #[stable(feature = "duration_float", since = "1.38.0")] #[inline] pub fn from_secs_f64(secs: f64) -> Duration { const MAX_NANOS_F64: f64 = @@ -579,13 +576,12 @@ impl Duration { /// /// # Examples /// ``` - /// #![feature(duration_float)] /// use std::time::Duration; /// /// let dur = Duration::from_secs_f32(2.7); /// assert_eq!(dur, Duration::new(2, 700_000_000)); /// ``` - #[unstable(feature = "duration_float", issue = "54361")] + #[stable(feature = "duration_float", since = "1.38.0")] #[inline] pub fn from_secs_f32(secs: f32) -> Duration { const MAX_NANOS_F32: f32 = @@ -614,14 +610,13 @@ impl Duration { /// /// # Examples /// ``` - /// #![feature(duration_float)] /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); /// assert_eq!(dur.mul_f64(3.14), Duration::new(8, 478_000_000)); /// assert_eq!(dur.mul_f64(3.14e5), Duration::new(847_800, 0)); /// ``` - #[unstable(feature = "duration_float", issue = "54361")] + #[stable(feature = "duration_float", since = "1.38.0")] #[inline] pub fn mul_f64(self, rhs: f64) -> Duration { Duration::from_secs_f64(rhs * self.as_secs_f64()) @@ -634,7 +629,6 @@ impl Duration { /// /// # Examples /// ``` - /// #![feature(duration_float)] /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); @@ -643,7 +637,7 @@ impl Duration { /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_640)); /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847799, 969_120_256)); /// ``` - #[unstable(feature = "duration_float", issue = "54361")] + #[stable(feature = "duration_float", since = "1.38.0")] #[inline] pub fn mul_f32(self, rhs: f32) -> Duration { Duration::from_secs_f32(rhs * self.as_secs_f32()) @@ -656,7 +650,6 @@ impl Duration { /// /// # Examples /// ``` - /// #![feature(duration_float)] /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); @@ -664,7 +657,7 @@ impl Duration { /// // note that truncation is used, not rounding /// assert_eq!(dur.div_f64(3.14e5), Duration::new(0, 8_598)); /// ``` - #[unstable(feature = "duration_float", issue = "54361")] + #[stable(feature = "duration_float", since = "1.38.0")] #[inline] pub fn div_f64(self, rhs: f64) -> Duration { Duration::from_secs_f64(self.as_secs_f64() / rhs) @@ -677,7 +670,6 @@ impl Duration { /// /// # Examples /// ``` - /// #![feature(duration_float)] /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); @@ -687,7 +679,7 @@ impl Duration { /// // note that truncation is used, not rounding /// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_598)); /// ``` - #[unstable(feature = "duration_float", issue = "54361")] + #[stable(feature = "duration_float", since = "1.38.0")] #[inline] pub fn div_f32(self, rhs: f32) -> Duration { Duration::from_secs_f32(self.as_secs_f32() / rhs) @@ -697,14 +689,14 @@ impl Duration { /// /// # Examples /// ``` - /// #![feature(duration_float)] + /// #![feature(div_duration)] /// use std::time::Duration; /// /// let dur1 = Duration::new(2, 700_000_000); /// let dur2 = Duration::new(5, 400_000_000); /// assert_eq!(dur1.div_duration_f64(dur2), 0.5); /// ``` - #[unstable(feature = "duration_float", issue = "54361")] + #[unstable(feature = "div_duration", issue = "63139")] #[inline] pub fn div_duration_f64(self, rhs: Duration) -> f64 { self.as_secs_f64() / rhs.as_secs_f64() @@ -714,14 +706,14 @@ impl Duration { /// /// # Examples /// ``` - /// #![feature(duration_float)] + /// #![feature(div_duration)] /// use std::time::Duration; /// /// let dur1 = Duration::new(2, 700_000_000); /// let dur2 = Duration::new(5, 400_000_000); /// assert_eq!(dur1.div_duration_f32(dur2), 0.5); /// ``` - #[unstable(feature = "duration_float", issue = "54361")] + #[unstable(feature = "div_duration", issue = "63139")] #[inline] pub fn div_duration_f32(self, rhs: Duration) -> f32 { self.as_secs_f32() / rhs.as_secs_f32() diff --git a/src/libcore/unicode/mod.rs b/src/libcore/unicode/mod.rs index 272727def61d6..a3ec9fd51f064 100644 --- a/src/libcore/unicode/mod.rs +++ b/src/libcore/unicode/mod.rs @@ -13,8 +13,3 @@ pub mod derived_property { pub mod conversions { pub use crate::unicode::tables::conversions::{to_lower, to_upper}; } - -// For use in libsyntax -pub mod property { - pub use crate::unicode::tables::property::Pattern_White_Space; -} diff --git a/src/libcore/unicode/printable.py b/src/libcore/unicode/printable.py index 748917f1d3420..4e8b4ecad0200 100644 --- a/src/libcore/unicode/printable.py +++ b/src/libcore/unicode/printable.py @@ -60,7 +60,7 @@ def get_codepoints(f): yield Codepoint(codepoint, class_) prev_codepoint = codepoint - if class_first != None: + if class_first is not None: raise ValueError("Missing Last after First") for c in range(prev_codepoint + 1, NUM_CODEPOINTS): diff --git a/src/libcore/unicode/tables.rs b/src/libcore/unicode/tables.rs index bfe784afaa47d..5b5be48543121 100644 --- a/src/libcore/unicode/tables.rs +++ b/src/libcore/unicode/tables.rs @@ -14,8 +14,8 @@ pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { micro: 0, _priv: (), }; -pub mod general_category { - pub const Cc_table: &super::SmallBoolTrie = &super::SmallBoolTrie { +pub(crate) mod general_category { + const Cc_table: &super::SmallBoolTrie = &super::SmallBoolTrie { r1: &[ 0, 1, 0 ], @@ -28,7 +28,7 @@ pub mod general_category { Cc_table.lookup(c) } - pub const N_table: &super::BoolTrie = &super::BoolTrie { + const N_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x03ff000000000000, 0x0000000000000000, 0x720c000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, @@ -141,8 +141,8 @@ pub mod general_category { } -pub mod derived_property { - pub const Alphabetic_table: &super::BoolTrie = &super::BoolTrie { +pub(crate) mod derived_property { + const Alphabetic_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, @@ -327,7 +327,7 @@ pub mod derived_property { Alphabetic_table.lookup(c) } - pub const Case_Ignorable_table: &super::BoolTrie = &super::BoolTrie { + const Case_Ignorable_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x0400408000000000, 0x0000000140000000, 0x0190a10000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, @@ -464,7 +464,7 @@ pub mod derived_property { Case_Ignorable_table.lookup(c) } - pub const Cased_table: &super::BoolTrie = &super::BoolTrie { + const Cased_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xf7ffffffffffffff, 0xfffffffffffffff0, @@ -565,7 +565,7 @@ pub mod derived_property { Cased_table.lookup(c) } - pub const Grapheme_Extend_table: &super::BoolTrie = &super::BoolTrie { + const Grapheme_Extend_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, @@ -689,7 +689,7 @@ pub mod derived_property { Grapheme_Extend_table.lookup(c) } - pub const Lowercase_table: &super::BoolTrie = &super::BoolTrie { + const Lowercase_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x0000000000000000, 0x07fffffe00000000, 0x0420040000000000, 0xff7fffff80000000, 0x55aaaaaaaaaaaaaa, 0xd4aaaaaaaaaaab55, 0xe6512d2a4e243129, 0xaa29aaaab5555240, @@ -789,7 +789,7 @@ pub mod derived_property { Lowercase_table.lookup(c) } - pub const Uppercase_table: &super::BoolTrie = &super::BoolTrie { + const Uppercase_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x0000000000000000, 0x0000000007fffffe, 0x0000000000000000, 0x000000007f7fffff, 0xaa55555555555555, 0x2b555555555554aa, 0x11aed2d5b1dbced6, 0x55d255554aaaa490, @@ -890,385 +890,10 @@ pub mod derived_property { Uppercase_table.lookup(c) } - pub const XID_Continue_table: &super::BoolTrie = &super::BoolTrie { - r1: [ - 0x03ff000000000000, 0x07fffffe87fffffe, 0x04a0040000000000, 0xff7fffffff7fffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000501f0003ffc3, - 0xffffffffffffffff, 0xb8dfffffffffffff, 0xfffffffbffffd7c0, 0xffbfffffffffffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffcfb, 0xffffffffffffffff, - 0xfffeffffffffffff, 0xffffffff027fffff, 0xbffffffffffe01ff, 0x000787ffffff00b6, - 0xffffffff07ff0000, 0xffffc3ffffffffff, 0xffffffffffffffff, 0x9ffffdff9fefffff, - 0xffffffffffff0000, 0xffffffffffffe7ff, 0x0003ffffffffffff, 0x243fffffffffffff - ], - r2: [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 4, 32, 33, 34, 4, 4, 4, 4, 4, 35, 36, 37, 38, 39, 40, - 41, 42, 4, 4, 4, 4, 4, 4, 4, 4, 43, 44, 45, 46, 47, 4, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 4, 61, 4, 62, 63, 64, 65, 66, 4, 4, 4, 67, 4, 4, 4, 4, 68, 69, 70, - 71, 72, 73, 74, 75, 76, 77, 78, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 79, 80, 4, 81, 82, 83, 84, 85, 60, 60, 60, 60, 60, 60, 60, 60, 86, - 42, 87, 88, 89, 4, 90, 91, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 52, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 93, 94, 4, 4, 4, 4, 95, 96, 4, 97, 98, 4, 99, 100, 101, 62, 4, 102, 103, - 104, 4, 105, 106, 107, 4, 108, 109, 110, 4, 111, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 112, 113, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 103, 4, 114, - 115, 116, 97, 117, 4, 118, 4, 4, 119, 120, 121, 122, 123, 124, 4, 125, 126, 127, 128, - 129 - ], - r3: &[ - 0x00003fffffffffff, 0x000007ff0fffffff, 0x3fdfffff00000000, 0xfffffffbfff80000, - 0xffffffffffffffff, 0xfffeffcfffffffff, 0xf3c5fdfffff99fef, 0x5003ffcfb080799f, - 0xd36dfdfffff987ee, 0x003fffc05e023987, 0xf3edfdfffffbbfee, 0xfe00ffcf00013bbf, - 0xf3edfdfffff99fee, 0x0002ffcfb0c0399f, 0xc3ffc718d63dc7ec, 0x0000ffc000813dc7, - 0xe3fffdfffffddfff, 0x0000ffcf07603ddf, 0xf3effdfffffddfef, 0x0006ffcf40603ddf, - 0xfffffffffffddfef, 0xfc00ffcf80f07ddf, 0x2ffbfffffc7fffec, 0x000cffc0ff5f847f, - 0x07fffffffffffffe, 0x0000000003ff7fff, 0x3fffffaffffff7d6, 0x00000000f3ff3f5f, - 0xc2a003ff03000001, 0xfffe1ffffffffeff, 0x1ffffffffeffffdf, 0x0000000000000040, - 0xffffffffffff03ff, 0xffffffff3fffffff, 0xf7ffffffffff20bf, 0xffffffff3d7f3dff, - 0x7f3dffffffff3dff, 0xffffffffff7fff3d, 0xffffffffff3dffff, 0x0003fe00e7ffffff, - 0xffffffff0000ffff, 0x3f3fffffffffffff, 0xfffffffffffffffe, 0xffff9fffffffffff, - 0xffffffff07fffffe, 0x01ffc7ffffffffff, 0x001fffff001fdfff, 0x000ddfff000fffff, - 0x000003ff308fffff, 0xffffffff03ff3800, 0x01ffffffffffffff, 0xffff07ffffffffff, - 0x003fffffffffffff, 0x0fff0fff7fffffff, 0x001f3fffffffffc0, 0xffff0fffffffffff, - 0x0000000007ff03ff, 0xffffffff0fffffff, 0x9fffffff7fffffff, 0x3fff008003ff03ff, - 0x0000000000000000, 0x000ff80003ff0fff, 0x000fffffffffffff, 0x00ffffffffffffff, - 0x3fffffffffffe3ff, 0xe7ffffffffff01ff, 0x07fffffffff70000, 0xfbffffffffffffff, - 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, - 0x8000000000000000, 0x8002000000100001, 0x000000001fff0000, 0x0001ffe21fff0000, - 0xf3fffd503f2ffc84, 0xffffffff000043e0, 0x00000000000001ff, 0xffff7fffffffffff, - 0xffffffff7fffffff, 0x000ff81fffffffff, 0xffff20bfffffffff, 0x800080ffffffffff, - 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f, 0x1f3efffe000000e0, 0xfffffffee67fffff, - 0xf7ffffffffffffff, 0xfffeffffffffffe0, 0x07ffffff00007fff, 0xffff000000000000, - 0x0000ffffffffffff, 0x0000000000001fff, 0x3fffffffffff0000, 0x00000fffffff1fff, - 0xbff0ffffffffffff, 0x0003ffffffffffff, 0xfffffffcff800000, 0xfffffffffffff9ff, - 0xff8000000000007c, 0x000000ffffffffff, 0xe8ffffff03ff003f, 0xffff3fffffffffff, - 0x1fffffff000fffff, 0x7fffffff03ff8001, 0x007fffffffffffff, 0xfc7fffff03ff3fff, - 0x007cffff38000007, 0xffff7f7f007e7e7e, 0xffff00fff7ffffff, 0x03ff37ffffffffff, - 0xffff000fffffffff, 0x0ffffffffffff87f, 0x0000000003ffffff, 0x5f7ffdffe0f8007f, - 0xffffffffffffffdb, 0xfffffffffff80000, 0xfffffff03fffffff, 0x3fffffffffffffff, - 0xffffffffffff0000, 0xfffffffffffcffff, 0x03ff0000000000ff, 0x0018ffff0000ffff, - 0xaa8a00000000e000, 0x1fffffffffffffff, 0x87fffffe03ff0000, 0xffffffc007fffffe, - 0x7fffffffffffffff, 0x000000001cfcfcfc - ], - r4: [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 13, - 14, 7, 15, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 17, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - ], - r5: &[ - 0, 1, 2, 3, 4, 5, 4, 6, 4, 4, 7, 8, 9, 10, 11, 12, 2, 2, 13, 14, 15, 16, 4, 4, 2, 2, 2, - 2, 17, 18, 4, 4, 19, 20, 21, 22, 23, 4, 24, 4, 25, 26, 27, 28, 29, 30, 31, 4, 2, 32, 33, - 33, 34, 4, 4, 4, 4, 4, 4, 4, 35, 36, 4, 37, 2, 38, 3, 39, 40, 41, 2, 42, 43, 4, 44, 45, - 46, 47, 4, 4, 2, 48, 2, 49, 4, 4, 50, 51, 2, 52, 53, 54, 55, 4, 4, 4, 3, 4, 56, 57, 4, - 4, 58, 59, 60, 61, 62, 53, 4, 4, 4, 4, 63, 64, 65, 4, 66, 67, 68, 4, 4, 4, 4, 37, 4, 4, - 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 4, 2, 70, 2, 2, 2, 71, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 70, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 72, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 2, 2, 2, 2, 2, 2, 2, 2, 53, 73, 4, 74, 17, 75, 76, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 4, 4, 2, 77, 78, 79, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 80, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 21, 81, 2, 2, 2, 2, - 2, 82, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 83, 84, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 85, 86, 4, 4, 87, 4, 4, 4, 4, 4, 4, 2, 88, 89, 90, 91, 92, 2, 2, 2, 2, 93, 94, 95, - 96, 97, 98, 4, 4, 4, 4, 4, 4, 4, 4, 99, 100, 101, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 102, 4, 4, 4, 103, 104, 4, 4, 4, 4, 4, 105, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 106, 2, 107, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 108, 109, 110, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 111, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 11, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 112, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 113, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 114, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 115, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 - ], - r6: &[ - 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, - 0x0000000000000000, 0x001fffffffffffff, 0x2000000000000000, 0xffffffff1fffffff, - 0x000000010001ffff, 0xffffe000ffffffff, 0x07ffffffffff07ff, 0xffffffff3fffffff, - 0x00000000003eff0f, 0xffff03ff3fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, - 0x0000000fffffffff, 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, - 0x007fffff003fffff, 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, - 0xc0ffffffffffffff, 0x873ffffffeeff06f, 0x1fffffff00000000, 0x000000001fffffff, - 0x0000007ffffffeff, 0x003fffffffffffff, 0x0007ffff003fffff, 0x000000000003ffff, - 0x00000000000001ff, 0x0007ffffffffffff, 0x03ff00ffffffffff, 0xffff00801fffffff, - 0x000000000001ffff, 0x007fffff00000000, 0x8000ffc00000007f, 0x03ff01ffffff0000, - 0xffdfffffffffffff, 0x004fffffffff0070, 0x0000000017ff1e1f, 0x40fffffffffbffff, - 0xffff01ffbfffbd7f, 0x03ff07ffffffffff, 0xfbedfdfffff99fef, 0x001f1fcfe081399f, - 0x00000000c3ff07ff, 0x0000000003ff00bf, 0xff3fffffffffffff, 0x000000003f000001, - 0x0000000003ff0011, 0x01ffffffffffffff, 0x00000000000003ff, 0x03ff0fffe7ffffff, - 0xffffffff00000000, 0x800003ffffffffff, 0xfffffcff00000000, 0x0000001bfcffffff, - 0x7fffffffffffffff, 0xffffffffffff0080, 0x0000000023ffffff, 0xff7ffffffffffdff, - 0xfffc000003ff0001, 0x007ffefffffcffff, 0xb47ffffffffffb7f, 0xfffffdbf03ff00ff, - 0x000003ff01fb7fff, 0x0000000003ffffff, 0x00007fffffffffff, 0x000000000000000f, - 0x000000000000007f, 0x000003ff7fffffff, 0x001f3fffffff0000, 0xe0fffff803ff000f, - 0x000000000000ffff, 0xffffffffffff87ff, 0x00000000ffff80ff, 0x0000000b00000000, - 0x00ffffffffffffff, 0xffff00f000070000, 0x0fffffffffffffff, 0x1fff07ffffffffff, - 0x0000000063ff01ff, 0xf807e3e000000000, 0x00003c0000000fe7, 0x000000000000001c, - 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, - 0xfffffffffffdfc5f, 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, - 0xffff7fffffff7fff, 0xfffffdfffffffdff, 0xffffffffffffcff7, 0xf87fffffffffffff, - 0x00201fffffffffff, 0x0000fffef8000010, 0x000007dbf9ffff7f, 0x3fff1fffffffffff, - 0x00000000000043ff, 0x03ffffffffffffff, 0x00000000007f001f, 0x0000000003ff0fff, - 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, 0x00000000007fffff, - 0xffff0003ffffffff, 0x00000001ffffffff, 0x000000003fffffff, 0x0000ffffffffffff - ], - }; - - pub fn XID_Continue(c: char) -> bool { - XID_Continue_table.lookup(c) - } - - pub const XID_Start_table: &super::BoolTrie = &super::BoolTrie { - r1: [ - 0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000501f0003ffc3, - 0x0000000000000000, 0xb8df000000000000, 0xfffffffbffffd740, 0xffbfffffffffffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffc03, 0xffffffffffffffff, - 0xfffeffffffffffff, 0xffffffff027fffff, 0x00000000000001ff, 0x000787ffffff0000, - 0xffffffff00000000, 0xfffec000000007ff, 0xffffffffffffffff, 0x9c00c060002fffff, - 0x0000fffffffd0000, 0xffffffffffffe000, 0x0002003fffffffff, 0x043007fffffffc00 - ], - r2: [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 23, 25, 26, 27, 28, 29, 3, 30, 31, 32, 33, 34, 34, 34, 34, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 34, 34, 34, 34, 34, 34, 34, 34, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 3, 61, 62, 63, 64, 65, 66, 67, 68, 34, 34, 34, 3, 34, 34, - 34, 34, 69, 70, 71, 72, 3, 73, 74, 3, 75, 76, 77, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 78, - 79, 34, 80, 81, 82, 83, 84, 3, 3, 3, 3, 3, 3, 3, 3, 85, 42, 86, 87, 88, 34, 89, 90, 3, - 3, 3, 3, 3, 3, 3, 3, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 53, 3, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 91, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 92, 93, 34, 34, 34, 34, 94, - 95, 96, 91, 97, 34, 98, 99, 100, 48, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 34, 113, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 114, 115, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 34, 34, 34, 34, 34, - 116, 34, 117, 118, 119, 120, 121, 34, 122, 34, 34, 123, 124, 125, 126, 3, 127, 34, 128, - 129, 130, 131, 132 - ], - r3: &[ - 0x00000110043fffff, 0x000007ff01ffffff, 0x3fdfffff00000000, 0x0000000000000000, - 0x23fffffffffffff0, 0xfffe0003ff010000, 0x23c5fdfffff99fe1, 0x10030003b0004000, - 0x036dfdfffff987e0, 0x001c00005e000000, 0x23edfdfffffbbfe0, 0x0200000300010000, - 0x23edfdfffff99fe0, 0x00020003b0000000, 0x03ffc718d63dc7e8, 0x0000000000010000, - 0x23fffdfffffddfe0, 0x0000000307000000, 0x23effdfffffddfe1, 0x0006000340000000, - 0x27fffffffffddfe0, 0xfc00000380704000, 0x2ffbfffffc7fffe0, 0x000000000000007f, - 0x0005fffffffffffe, 0x2005ffaffffff7d6, 0x00000000f000005f, 0x0000000000000001, - 0x00001ffffffffeff, 0x0000000000001f00, 0x800007ffffffffff, 0xffe1c0623c3f0000, - 0xffffffff00004003, 0xf7ffffffffff20bf, 0xffffffffffffffff, 0xffffffff3d7f3dff, - 0x7f3dffffffff3dff, 0xffffffffff7fff3d, 0xffffffffff3dffff, 0x0000000007ffffff, - 0xffffffff0000ffff, 0x3f3fffffffffffff, 0xfffffffffffffffe, 0xffff9fffffffffff, - 0xffffffff07fffffe, 0x01ffc7ffffffffff, 0x0003ffff0003dfff, 0x0001dfff0003ffff, - 0x000fffffffffffff, 0x0000000010800000, 0xffffffff00000000, 0x01ffffffffffffff, - 0xffff05ffffffffff, 0x003fffffffffffff, 0x000000007fffffff, 0x001f3fffffff0000, - 0xffff0fffffffffff, 0x00000000000003ff, 0xffffffff007fffff, 0x00000000001fffff, - 0x0000008000000000, 0x000fffffffffffe0, 0x0000000000000fe0, 0xfc00c001fffffff8, - 0x0000003fffffffff, 0x0000000fffffffff, 0x3ffffffffc00e000, 0xe7ffffffffff01ff, - 0x046fde0000000000, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, - 0x1fdc1fff0fcf1fdc, 0x8002000000000000, 0x000000001fff0000, 0xf3fffd503f2ffc84, - 0xffffffff000043e0, 0x00000000000001ff, 0xffff7fffffffffff, 0xffffffff7fffffff, - 0x000c781fffffffff, 0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, - 0x000000007f7f7f7f, 0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, - 0xfffeffffffffffe0, 0x07ffffff00007fff, 0xffff000000000000, 0x0000ffffffffffff, - 0x0000000000001fff, 0x3fffffffffff0000, 0x00000c00ffff1fff, 0x80007fffffffffff, - 0xffffffff3fffffff, 0xfffffffcff800000, 0xfffffffffffff9ff, 0xff8000000000007c, - 0x00000007fffff7bb, 0x000ffffffffffffc, 0x68fc000000000000, 0xffff003ffffffc00, - 0x1fffffff0000007f, 0x0007fffffffffff0, 0x7c00ffdf00008000, 0x000001ffffffffff, - 0xc47fffff00000ff7, 0x3e62ffffffffffff, 0x001c07ff38000005, 0xffff7f7f007e7e7e, - 0xffff00fff7ffffff, 0x00000007ffffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, - 0xffff3fffffffffff, 0x0000000003ffffff, 0x5f7ffdffa0f8007f, 0xffffffffffffffdb, - 0x0003ffffffffffff, 0xfffffffffff80000, 0xfffffff03fffffff, 0x3fffffffffffffff, - 0xffffffffffff0000, 0xfffffffffffcffff, 0x03ff0000000000ff, 0xaa8a000000000000, - 0x1fffffffffffffff, 0x07fffffe00000000, 0xffffffc007fffffe, 0x7fffffff3fffffff, - 0x000000001cfcfcfc - ], - r4: [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 13, - 14, 7, 15, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - ], - r5: &[ - 0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 13, 14, 15, 4, 4, 2, 2, 2, - 2, 16, 17, 4, 4, 18, 19, 20, 21, 22, 4, 23, 4, 24, 25, 26, 27, 28, 29, 30, 4, 2, 31, 32, - 32, 15, 4, 4, 4, 4, 4, 4, 4, 33, 34, 4, 35, 36, 4, 37, 38, 39, 40, 41, 42, 43, 4, 44, - 20, 45, 46, 4, 4, 5, 47, 48, 49, 4, 4, 50, 51, 48, 52, 53, 4, 54, 4, 4, 4, 55, 4, 56, - 57, 4, 4, 58, 59, 60, 61, 62, 63, 4, 4, 4, 4, 64, 65, 66, 4, 67, 68, 69, 4, 4, 4, 4, 70, - 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 71, 4, 2, 50, 2, 2, 2, 72, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 50, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 73, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 63, 20, 4, 74, 48, 75, 66, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 2, 4, 4, 2, 76, 77, 78, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 79, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 32, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 20, 80, 2, - 2, 2, 2, 2, 81, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 82, 83, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 84, 85, 86, 87, 88, 2, 2, 2, 2, 89, 90, - 91, 92, 93, 94, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 95, 96, 4, 4, 4, 4, 4, 55, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 97, 2, 98, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 99, 100, 101, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 102, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 103, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 104, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 105, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 - ], - r6: &[ - 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, - 0x0000000000000000, 0x001fffffffffffff, 0xffffffff1fffffff, 0x000000000001ffff, - 0xffffe000ffffffff, 0x003fffffffff07ff, 0xffffffff3fffffff, 0x00000000003eff0f, - 0xffff00003fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, 0x0000000fffffffff, - 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff, - 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, 0xc0ffffffffffffff, - 0x003ffffffeef0001, 0x1fffffff00000000, 0x000000001fffffff, 0x0000001ffffffeff, - 0x003fffffffffffff, 0x0007ffff003fffff, 0x000000000003ffff, 0x00000000000001ff, - 0x0007ffffffffffff, 0xffff00801fffffff, 0x000000000000003f, 0x007fffff00000000, - 0x00fffffffffffff8, 0x0000fffffffffff8, 0x000001ffffff0000, 0x0000007ffffffff8, - 0x0047ffffffff0010, 0x0007fffffffffff8, 0x000000001400001e, 0x00000ffffffbffff, - 0xffff01ffbfffbd7f, 0x23edfdfffff99fe0, 0x00000003e0010000, 0x0000000080000780, - 0x0000ffffffffffff, 0x00000000000000b0, 0x00007fffffffffff, 0x000000000f000000, - 0x0000000000000010, 0x010007ffffffffff, 0x0000000007ffffff, 0x00000fffffffffff, - 0xffffffff00000000, 0x80000000ffffffff, 0xfffffcff00000000, 0x0000000a0001ffff, - 0x0407fffffffff801, 0xfffffffff0010000, 0x00000000200003ff, 0x01ffffffffffffff, - 0x00007ffffffffdff, 0xfffc000000000001, 0x000000000000ffff, 0x0001fffffffffb7f, - 0xfffffdbf00000040, 0x00000000010003ff, 0x0007ffff00000000, 0x0000000003ffffff, - 0x000000000000000f, 0x000000000000007f, 0x00003fffffff0000, 0xe0fffff80000000f, - 0x00000000000107ff, 0x00000000fff80000, 0x0000000b00000000, 0x00ffffffffffffff, - 0xffff00f000070000, 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000003ff01ff, - 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, - 0xfffffffffffdfc5f, 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, - 0xffff7fffffff7fff, 0xfffffdfffffffdff, 0x0000000000000ff7, 0x3f801fffffffffff, - 0x0000000000004000, 0x000000000000001f, 0x000000000000080f, 0x0af7fe96ffffffef, - 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, 0x00000000007fffff, 0xffff0003ffffffff, - 0x00000001ffffffff, 0x000000003fffffff - ], - }; - - pub fn XID_Start(c: char) -> bool { - XID_Start_table.lookup(c) - } - } -pub mod property { - pub const Pattern_White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie { - r1: &[ - 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 - ], - r2: &[ - 0x0000000100003e00, 0x0000000000000000, 0x0000000000000020, 0x000003000000c000 - ], - }; - - pub fn Pattern_White_Space(c: char) -> bool { - Pattern_White_Space_table.lookup(c) - } - - pub const White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie { +pub(crate) mod property { + const White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie { r1: &[ 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -1290,7 +915,7 @@ pub mod property { } -pub mod conversions { +pub(crate) mod conversions { pub fn to_lower(c: char) -> [char; 3] { match bsearch_case_table(c, to_lowercase_table) { None => [c, '\0', '\0'], diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py index 5389d1cf80383..89894f7932d79 100755 --- a/src/libcore/unicode/unicode.py +++ b/src/libcore/unicode/unicode.py @@ -606,7 +606,7 @@ def compute_trie(raw_data, chunk_size): return root, child_data -def generate_bool_trie(name, codepoint_ranges, is_pub=True): +def generate_bool_trie(name, codepoint_ranges, is_pub=False): # type: (str, List[Tuple[int, int]], bool) -> Iterator[str] """ Generate Rust code for BoolTrie struct. @@ -681,7 +681,7 @@ def generate_bool_trie(name, codepoint_ranges, is_pub=True): yield " };\n\n" -def generate_small_bool_trie(name, codepoint_ranges, is_pub=True): +def generate_small_bool_trie(name, codepoint_ranges, is_pub=False): # type: (str, List[Tuple[int, int]], bool) -> Iterator[str] """ Generate Rust code for `SmallBoolTrie` struct. @@ -726,9 +726,9 @@ def generate_property_module(mod, grouped_categories, category_subset): Generate Rust code for module defining properties. """ - yield "pub mod %s {\n" % mod + yield "pub(crate) mod %s {\n" % mod for cat in sorted(category_subset): - if cat in ("Cc", "White_Space", "Pattern_White_Space"): + if cat in ("Cc", "White_Space"): generator = generate_small_bool_trie("%s_table" % cat, grouped_categories[cat]) else: generator = generate_bool_trie("%s_table" % cat, grouped_categories[cat]) @@ -749,7 +749,7 @@ def generate_conversions_module(unicode_data): Generate Rust code for module defining conversions. """ - yield "pub mod conversions {" + yield "pub(crate) mod conversions {" yield """ pub fn to_lower(c: char) -> [char; 3] { match bsearch_case_table(c, to_lowercase_table) { @@ -841,19 +841,18 @@ def main(): unicode_data = load_unicode_data(get_path(UnicodeFiles.UNICODE_DATA)) load_special_casing(get_path(UnicodeFiles.SPECIAL_CASING), unicode_data) - want_derived = {"XID_Start", "XID_Continue", "Alphabetic", "Lowercase", "Uppercase", + want_derived = {"Alphabetic", "Lowercase", "Uppercase", "Cased", "Case_Ignorable", "Grapheme_Extend"} derived = load_properties(get_path(UnicodeFiles.DERIVED_CORE_PROPERTIES), want_derived) props = load_properties(get_path(UnicodeFiles.PROPS), - {"White_Space", "Join_Control", "Noncharacter_Code_Point", - "Pattern_White_Space"}) + {"White_Space", "Join_Control", "Noncharacter_Code_Point"}) # Category tables for (name, categories, category_subset) in ( ("general_category", unicode_data.general_categories, ["N", "Cc"]), ("derived_property", derived, want_derived), - ("property", props, ["White_Space", "Pattern_White_Space"]) + ("property", props, ["White_Space"]) ): for fragment in generate_property_module(name, categories, category_subset): buf.write(fragment) diff --git a/src/libfmt_macros/Cargo.toml b/src/libfmt_macros/Cargo.toml index 82a9e34c065b1..fff4ec716dfda 100644 --- a/src/libfmt_macros/Cargo.toml +++ b/src/libfmt_macros/Cargo.toml @@ -10,4 +10,4 @@ path = "lib.rs" [dependencies] syntax_pos = { path = "../libsyntax_pos" } - +rustc_lexer = { path = "../librustc_lexer" } diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 985abaf2c1bd5..d22420e76dcd4 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -410,7 +410,7 @@ impl<'a> Parser<'a> { &self.input[start..self.input.len()] } - /// Parses an Argument structure, or what's contained within braces inside the format string + /// Parses an `Argument` structure, or what's contained within braces inside the format string. fn argument(&mut self) -> Argument<'a> { let pos = self.position(); let format = self.format(); @@ -464,7 +464,7 @@ impl<'a> Parser<'a> { } /// Parses a format specifier at the current position, returning all of the - /// relevant information in the FormatSpec struct. + /// relevant information in the `FormatSpec` struct. fn format(&mut self) -> FormatSpec<'a> { let mut spec = FormatSpec { fill: None, @@ -571,7 +571,7 @@ impl<'a> Parser<'a> { spec } - /// Parses a Count parameter at the current position. This does not check + /// Parses a `Count` parameter at the current position. This does not check /// for 'CountIsNextParam' because that is only used in precision, not /// width. fn count(&mut self, start: usize) -> (Count, Option) { @@ -597,12 +597,11 @@ impl<'a> Parser<'a> { } } - /// Parses a word starting at the current position. A word is considered to - /// be an alphabetic character followed by any number of alphanumeric - /// characters. + /// Parses a word starting at the current position. A word is the same as + /// Rust identifier, except that it can't start with `_` character. fn word(&mut self) -> &'a str { let start = match self.cur.peek() { - Some(&(pos, c)) if c.is_xid_start() => { + Some(&(pos, c)) if c != '_' && rustc_lexer::is_id_start(c) => { self.cur.next(); pos } @@ -611,7 +610,7 @@ impl<'a> Parser<'a> { } }; while let Some(&(pos, c)) = self.cur.peek() { - if c.is_xid_continue() { + if rustc_lexer::is_id_continue(c) { self.cur.next(); } else { return &self.input[start..pos]; diff --git a/src/libproc_macro/Cargo.toml b/src/libproc_macro/Cargo.toml index b3d0ee94f0e12..187bdac80019d 100644 --- a/src/libproc_macro/Cargo.toml +++ b/src/libproc_macro/Cargo.toml @@ -6,3 +6,6 @@ edition = "2018" [lib] path = "lib.rs" + +[dependencies] +std = { path = "../libstd" } diff --git a/src/libproc_macro/bridge/client.rs b/src/libproc_macro/bridge/client.rs index 6052b4a4d43f4..5c543165bc2b1 100644 --- a/src/libproc_macro/bridge/client.rs +++ b/src/libproc_macro/bridge/client.rs @@ -468,6 +468,14 @@ pub enum ProcMacro { } impl ProcMacro { + pub fn name(&self) -> &'static str { + match self { + ProcMacro::CustomDerive { trait_name, .. } => trait_name, + ProcMacro::Attr { name, .. } => name, + ProcMacro::Bang { name, ..} => name + } + } + pub const fn custom_derive( trait_name: &'static str, attributes: &'static [&'static str], diff --git a/src/libproc_macro/bridge/mod.rs b/src/libproc_macro/bridge/mod.rs index 3c48466fffa28..c26b59f473c36 100644 --- a/src/libproc_macro/bridge/mod.rs +++ b/src/libproc_macro/bridge/mod.rs @@ -148,6 +148,7 @@ macro_rules! with_api { fn debug($self: $S::Span) -> String; fn def_site() -> $S::Span; fn call_site() -> $S::Span; + fn mixed_site() -> $S::Span; fn source_file($self: $S::Span) -> $S::SourceFile; fn parent($self: $S::Span) -> Option<$S::Span>; fn source($self: $S::Span) -> $S::Span; diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index c0f7714ca211a..f612c52d39835 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -19,12 +19,14 @@ #![feature(nll)] #![feature(staged_api)] +#![feature(allow_internal_unstable)] #![feature(const_fn)] +#![feature(decl_macro)] #![feature(extern_types)] #![feature(in_band_lifetimes)] #![feature(optin_builtin_traits)] -#![feature(mem_take)] #![feature(non_exhaustive)] +#![feature(rustc_attrs)] #![feature(specialization)] #![recursion_limit="256"] @@ -222,11 +224,10 @@ pub mod token_stream { /// /// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term. /// To quote `$` itself, use `$$`. -/// -/// This is a dummy macro, the actual implementation is in `quote::quote`.` #[unstable(feature = "proc_macro_quote", issue = "54722")] -#[macro_export] -macro_rules! quote { () => {} } +#[allow_internal_unstable(proc_macro_def_site)] +#[rustc_builtin_macro] +pub macro quote ($($t:tt)*) { /* compiler built-in */ } #[unstable(feature = "proc_macro_internals", issue = "27812")] #[doc(hidden)] @@ -269,6 +270,15 @@ impl Span { Span(bridge::client::Span::call_site()) } + /// A span that represents `macro_rules` hygiene, and sometimes resolves at the macro + /// definition site (local variables, labels, `$crate`) and sometimes at the macro + /// call site (everything else). + /// The span location is taken from the call-site. + #[unstable(feature = "proc_macro_mixed_site", issue = "65049")] + pub fn mixed_site() -> Span { + Span(bridge::client::Span::mixed_site()) + } + /// The original source file into which this span points. #[unstable(feature = "proc_macro_span", issue = "54725")] pub fn source_file(&self) -> SourceFile { diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs index e3d31b78f4a09..144e2d6bac43b 100644 --- a/src/libproc_macro/quote.rs +++ b/src/libproc_macro/quote.rs @@ -57,9 +57,9 @@ macro_rules! quote { } /// Quote a `TokenStream` into a `TokenStream`. -/// This is the actual `quote!()` proc macro. +/// This is the actual implementation of the `quote!()` proc macro. /// -/// It is manually loaded in `CStore::load_macro_untracked`. +/// It is loaded by the compiler in `register_builtin_macros`. #[unstable(feature = "proc_macro_quote", issue = "54722")] pub fn quote(stream: TokenStream) -> TokenStream { if stream.is_empty() { diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 0222a3dde7ab9..9b3609eca3e62 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -15,24 +15,24 @@ bitflags = "1.0" fmt_macros = { path = "../libfmt_macros" } graphviz = { path = "../libgraphviz" } jobserver = "0.1" -lazy_static = "1.0.0" num_cpus = "1.0" scoped-tls = "1.0" log = { version = "0.4", features = ["release_max_level_info", "std"] } -rustc-rayon = "0.2.0" -rustc-rayon-core = "0.2.0" -polonius-engine = "0.9.0" +rustc-rayon = "0.3.0" +rustc-rayon-core = "0.3.0" +polonius-engine = "0.10.0" rustc_apfloat = { path = "../librustc_apfloat" } rustc_target = { path = "../librustc_target" } rustc_macros = { path = "../librustc_macros" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_index = { path = "../librustc_index" } errors = { path = "../librustc_errors", package = "rustc_errors" } rustc_serialize = { path = "../libserialize", package = "serialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } backtrace = "0.3.3" -parking_lot = "0.7" -byteorder = { version = "1.1", features = ["i128"]} +parking_lot = "0.9" +byteorder = { version = "1.3" } chalk-engine = { version = "0.9.0", default-features=false } rustc_fs_util = { path = "../librustc_fs_util" } smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs index e8c3914e695ad..5a5919d786638 100644 --- a/src/librustc/arena.rs +++ b/src/librustc/arena.rs @@ -25,6 +25,16 @@ macro_rules! arena_types { [] adt_def: rustc::ty::AdtDef, [] steal_mir: rustc::ty::steal::Steal>, [] mir: rustc::mir::Body<$tcx>, + [] steal_promoted: rustc::ty::steal::Steal< + rustc_index::vec::IndexVec< + rustc::mir::Promoted, + rustc::mir::Body<$tcx> + > + >, + [] promoted: rustc_index::vec::IndexVec< + rustc::mir::Promoted, + rustc::mir::Body<$tcx> + >, [] tables: rustc::ty::TypeckTables<$tcx>, [] const_allocs: rustc::mir::interpret::Allocation, [] vtable_method: Option<( @@ -35,7 +45,7 @@ macro_rules! arena_types { [decode] specialization_graph: rustc::traits::specialization_graph::Graph, [] region_scope_tree: rustc::middle::region::ScopeTree, [] item_local_set: rustc::util::nodemap::ItemLocalSet, - [decode] mir_const_qualif: rustc_data_structures::bit_set::BitSet, + [decode] mir_const_qualif: rustc_index::bit_set::BitSet, [] trait_impls_of: rustc::ty::trait_def::TraitImpls, [] dropck_outlives: rustc::infer::canonical::Canonical<'tcx, @@ -76,7 +86,6 @@ macro_rules! arena_types { rustc::infer::canonical::QueryResponse<'tcx, rustc::ty::Ty<'tcx>> >, [few] crate_inherent_impls: rustc::ty::CrateInherentImpls, - [decode] borrowck: rustc::middle::borrowck::BorrowCheckResult, [few] upstream_monomorphizations: rustc::util::nodemap::DefIdMap< rustc_data_structures::fx::FxHashMap< @@ -84,6 +93,10 @@ macro_rules! arena_types { rustc::hir::def_id::CrateNum > >, + [few] diagnostic_items: rustc_data_structures::fx::FxHashMap< + syntax::symbol::Symbol, + rustc::hir::def_id::DefId, + >, [few] resolve_lifetimes: rustc::middle::resolve_lifetime::ResolveLifetimes, [decode] generic_predicates: rustc::ty::GenericPredicates<'tcx>, [few] lint_levels: rustc::lint::LintLevelMap, @@ -173,7 +186,7 @@ impl ArenaAllocatable for T {} unsafe trait ArenaField<'tcx>: Sized { /// Returns a specific arena to allocate from. - /// If None is returned, the DropArena will be used. + /// If `None` is returned, the `DropArena` will be used. fn arena<'a>(arena: &'a Arena<'tcx>) -> Option<&'a TypedArena>; } diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs deleted file mode 100644 index ca852fe7622cc..0000000000000 --- a/src/librustc/cfg/construct.rs +++ /dev/null @@ -1,528 +0,0 @@ -use crate::cfg::*; -use crate::middle::region; -use rustc_data_structures::graph::implementation as graph; -use crate::ty::{self, TyCtxt}; - -use crate::hir::{self, PatKind}; -use crate::hir::def_id::DefId; -use crate::hir::ptr::P; - -struct CFGBuilder<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - owner_def_id: DefId, - tables: &'a ty::TypeckTables<'tcx>, - graph: CFGGraph, - fn_exit: CFGIndex, - loop_scopes: Vec, - breakable_block_scopes: Vec, -} - -#[derive(Copy, Clone)] -struct BlockScope { - block_expr_id: hir::ItemLocalId, // id of breakable block expr node - break_index: CFGIndex, // where to go on `break` -} - -#[derive(Copy, Clone)] -struct LoopScope { - loop_id: hir::ItemLocalId, // id of loop/while node - continue_index: CFGIndex, // where to go on a `loop` - break_index: CFGIndex, // where to go on a `break` -} - -pub fn construct(tcx: TyCtxt<'_>, body: &hir::Body) -> CFG { - let mut graph = graph::Graph::new(); - let entry = graph.add_node(CFGNodeData::Entry); - - // `fn_exit` is target of return exprs, which lies somewhere - // outside input `body`. (Distinguishing `fn_exit` and `body_exit` - // also resolves chicken-and-egg problem that arises if you try to - // have return exprs jump to `body_exit` during construction.) - let fn_exit = graph.add_node(CFGNodeData::Exit); - let body_exit; - - // Find the tables for this body. - let owner_def_id = tcx.hir().body_owner_def_id(body.id()); - let tables = tcx.typeck_tables_of(owner_def_id); - - let mut cfg_builder = CFGBuilder { - tcx, - owner_def_id, - tables, - graph, - fn_exit, - loop_scopes: Vec::new(), - breakable_block_scopes: Vec::new(), - }; - body_exit = cfg_builder.expr(&body.value, entry); - cfg_builder.add_contained_edge(body_exit, fn_exit); - let CFGBuilder { graph, .. } = cfg_builder; - CFG { - owner_def_id, - graph, - entry, - exit: fn_exit, - } -} - -impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { - fn block(&mut self, blk: &hir::Block, pred: CFGIndex) -> CFGIndex { - if blk.targeted_by_break { - let expr_exit = self.add_ast_node(blk.hir_id.local_id, &[]); - - self.breakable_block_scopes.push(BlockScope { - block_expr_id: blk.hir_id.local_id, - break_index: expr_exit, - }); - - let mut stmts_exit = pred; - for stmt in &blk.stmts { - stmts_exit = self.stmt(stmt, stmts_exit); - } - let blk_expr_exit = self.opt_expr(&blk.expr, stmts_exit); - self.add_contained_edge(blk_expr_exit, expr_exit); - - self.breakable_block_scopes.pop(); - - expr_exit - } else { - let mut stmts_exit = pred; - for stmt in &blk.stmts { - stmts_exit = self.stmt(stmt, stmts_exit); - } - - let expr_exit = self.opt_expr(&blk.expr, stmts_exit); - - self.add_ast_node(blk.hir_id.local_id, &[expr_exit]) - } - } - - fn stmt(&mut self, stmt: &hir::Stmt, pred: CFGIndex) -> CFGIndex { - let exit = match stmt.node { - hir::StmtKind::Local(ref local) => { - let init_exit = self.opt_expr(&local.init, pred); - self.pat(&local.pat, init_exit) - } - hir::StmtKind::Item(_) => { - pred - } - hir::StmtKind::Expr(ref expr) | - hir::StmtKind::Semi(ref expr) => { - self.expr(&expr, pred) - } - }; - self.add_ast_node(stmt.hir_id.local_id, &[exit]) - } - - fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex { - match pat.node { - PatKind::Binding(.., None) | - PatKind::Path(_) | - PatKind::Lit(..) | - PatKind::Range(..) | - PatKind::Wild => self.add_ast_node(pat.hir_id.local_id, &[pred]), - - PatKind::Box(ref subpat) | - PatKind::Ref(ref subpat, _) | - PatKind::Binding(.., Some(ref subpat)) => { - let subpat_exit = self.pat(&subpat, pred); - self.add_ast_node(pat.hir_id.local_id, &[subpat_exit]) - } - - PatKind::TupleStruct(_, ref subpats, _) | - PatKind::Tuple(ref subpats, _) => { - let pats_exit = self.pats_all(subpats.iter(), pred); - self.add_ast_node(pat.hir_id.local_id, &[pats_exit]) - } - - PatKind::Struct(_, ref subpats, _) => { - let pats_exit = self.pats_all(subpats.iter().map(|f| &f.node.pat), pred); - self.add_ast_node(pat.hir_id.local_id, &[pats_exit]) - } - - PatKind::Slice(ref pre, ref vec, ref post) => { - let pre_exit = self.pats_all(pre.iter(), pred); - let vec_exit = self.pats_all(vec.iter(), pre_exit); - let post_exit = self.pats_all(post.iter(), vec_exit); - self.add_ast_node(pat.hir_id.local_id, &[post_exit]) - } - } - } - - fn pats_all<'b, I: Iterator>>( - &mut self, - pats: I, - pred: CFGIndex - ) -> CFGIndex { - //! Handles case where all of the patterns must match. - pats.fold(pred, |pred, pat| self.pat(&pat, pred)) - } - - fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex { - match expr.node { - hir::ExprKind::Block(ref blk, _) => { - let blk_exit = self.block(&blk, pred); - self.add_ast_node(expr.hir_id.local_id, &[blk_exit]) - } - - hir::ExprKind::Loop(ref body, _, _) => { - // - // [pred] - // | - // v 1 - // [loopback] <---+ - // | 4 | - // v 3 | - // [body] ------+ - // - // [expr] 2 - // - // Note that `break` and `loop` statements - // may cause additional edges. - - let loopback = self.add_dummy_node(&[pred]); // 1 - let expr_exit = self.add_ast_node(expr.hir_id.local_id, &[]); // 2 - self.loop_scopes.push(LoopScope { - loop_id: expr.hir_id.local_id, - continue_index: loopback, - break_index: expr_exit, - }); - let body_exit = self.block(&body, loopback); // 3 - self.add_contained_edge(body_exit, loopback); // 4 - self.loop_scopes.pop(); - expr_exit - } - - hir::ExprKind::Match(ref discr, ref arms, _) => { - self.match_(expr.hir_id.local_id, &discr, &arms, pred) - } - - hir::ExprKind::Binary(op, ref l, ref r) if op.node.is_lazy() => { - // - // [pred] - // | - // v 1 - // [l] - // | - // / \ - // / \ - // v 2 * - // [r] | - // | | - // v 3 v 4 - // [..exit..] - // - let l_exit = self.expr(&l, pred); // 1 - let r_exit = self.expr(&r, l_exit); // 2 - self.add_ast_node(expr.hir_id.local_id, &[l_exit, r_exit]) // 3,4 - } - - hir::ExprKind::Ret(ref v) => { - let v_exit = self.opt_expr(v, pred); - let b = self.add_ast_node(expr.hir_id.local_id, &[v_exit]); - self.add_returning_edge(expr, b); - self.add_unreachable_node() - } - - hir::ExprKind::Break(destination, ref opt_expr) => { - let v = self.opt_expr(opt_expr, pred); - let (target_scope, break_dest) = - self.find_scope_edge(expr, destination, ScopeCfKind::Break); - let b = self.add_ast_node(expr.hir_id.local_id, &[v]); - self.add_exiting_edge(expr, b, target_scope, break_dest); - self.add_unreachable_node() - } - - hir::ExprKind::Continue(destination) => { - let (target_scope, cont_dest) = - self.find_scope_edge(expr, destination, ScopeCfKind::Continue); - let a = self.add_ast_node(expr.hir_id.local_id, &[pred]); - self.add_exiting_edge(expr, a, target_scope, cont_dest); - self.add_unreachable_node() - } - - hir::ExprKind::Array(ref elems) => { - self.straightline(expr, pred, elems.iter().map(|e| &*e)) - } - - hir::ExprKind::Call(ref func, ref args) => { - self.call(expr, pred, &func, args.iter().map(|e| &*e)) - } - - hir::ExprKind::MethodCall(.., ref args) => { - self.call(expr, pred, &args[0], args[1..].iter().map(|e| &*e)) - } - - hir::ExprKind::Index(ref l, ref r) | - hir::ExprKind::Binary(_, ref l, ref r) if self.tables.is_method_call(expr) => { - self.call(expr, pred, &l, Some(&**r).into_iter()) - } - - hir::ExprKind::Unary(_, ref e) if self.tables.is_method_call(expr) => { - self.call(expr, pred, &e, None::.iter()) - } - - hir::ExprKind::Tup(ref exprs) => { - self.straightline(expr, pred, exprs.iter().map(|e| &*e)) - } - - hir::ExprKind::Struct(_, ref fields, ref base) => { - let field_cfg = self.straightline(expr, pred, fields.iter().map(|f| &*f.expr)); - self.opt_expr(base, field_cfg) - } - - hir::ExprKind::Assign(ref l, ref r) | - hir::ExprKind::AssignOp(_, ref l, ref r) => { - self.straightline(expr, pred, [r, l].iter().map(|&e| &**e)) - } - - hir::ExprKind::Index(ref l, ref r) | - hir::ExprKind::Binary(_, ref l, ref r) => { // N.B., && and || handled earlier - self.straightline(expr, pred, [l, r].iter().map(|&e| &**e)) - } - - hir::ExprKind::Box(ref e) | - hir::ExprKind::AddrOf(_, ref e) | - hir::ExprKind::Cast(ref e, _) | - hir::ExprKind::Type(ref e, _) | - hir::ExprKind::DropTemps(ref e) | - hir::ExprKind::Unary(_, ref e) | - hir::ExprKind::Field(ref e, _) | - hir::ExprKind::Yield(ref e, _) | - hir::ExprKind::Repeat(ref e, _) => { - self.straightline(expr, pred, Some(&**e).into_iter()) - } - - hir::ExprKind::InlineAsm(_, ref outputs, ref inputs) => { - let post_outputs = self.exprs(outputs.iter().map(|e| &*e), pred); - let post_inputs = self.exprs(inputs.iter().map(|e| &*e), post_outputs); - self.add_ast_node(expr.hir_id.local_id, &[post_inputs]) - } - - hir::ExprKind::Closure(..) | - hir::ExprKind::Lit(..) | - hir::ExprKind::Path(_) | - hir::ExprKind::Err => { - self.straightline(expr, pred, None::.iter()) - } - } - } - - fn call<'b, I: Iterator>(&mut self, - call_expr: &hir::Expr, - pred: CFGIndex, - func_or_rcvr: &hir::Expr, - args: I) -> CFGIndex { - let func_or_rcvr_exit = self.expr(func_or_rcvr, pred); - let ret = self.straightline(call_expr, func_or_rcvr_exit, args); - let m = self.tcx.hir().get_module_parent(call_expr.hir_id); - if self.tcx.is_ty_uninhabited_from(m, self.tables.expr_ty(call_expr)) { - self.add_unreachable_node() - } else { - ret - } - } - - fn exprs<'b, I: Iterator>(&mut self, - exprs: I, - pred: CFGIndex) -> CFGIndex { - //! Constructs graph for `exprs` evaluated in order - exprs.fold(pred, |p, e| self.expr(e, p)) - } - - fn opt_expr(&mut self, - opt_expr: &Option>, - pred: CFGIndex) -> CFGIndex { - //! Constructs graph for `opt_expr` evaluated, if Some - opt_expr.iter().fold(pred, |p, e| self.expr(&e, p)) - } - - fn straightline<'b, I: Iterator>(&mut self, - expr: &hir::Expr, - pred: CFGIndex, - subexprs: I) -> CFGIndex { - //! Handles case of an expression that evaluates `subexprs` in order - - let subexprs_exit = self.exprs(subexprs, pred); - self.add_ast_node(expr.hir_id.local_id, &[subexprs_exit]) - } - - fn match_(&mut self, id: hir::ItemLocalId, discr: &hir::Expr, - arms: &[hir::Arm], pred: CFGIndex) -> CFGIndex { - // The CFG for match expression is quite complex, so no ASCII - // art for it (yet). - // - // The CFG generated below matches roughly what MIR contains. - // Each pattern and guard is visited in parallel, with - // arms containing multiple patterns generating multiple nodes - // for the same guard expression. The guard expressions chain - // into each other from top to bottom, with a specific - // exception to allow some additional valid programs - // (explained below). MIR differs slightly in that the - // pattern matching may continue after a guard but the visible - // behaviour should be the same. - // - // What is going on is explained in further comments. - - // Visit the discriminant expression - let discr_exit = self.expr(discr, pred); - - // Add a node for the exit of the match expression as a whole. - let expr_exit = self.add_ast_node(id, &[]); - - // Keep track of the previous guard expressions - let mut prev_guard = None; - let match_scope = region::Scope { id, data: region::ScopeData::Node }; - - for arm in arms { - // Add an exit node for when we've visited all the - // patterns and the guard (if there is one) in the arm. - let bindings_exit = self.add_dummy_node(&[]); - - for pat in &arm.pats { - // Visit the pattern, coming from the discriminant exit - let mut pat_exit = self.pat(&pat, discr_exit); - - // If there is a guard expression, handle it here - if let Some(ref guard) = arm.guard { - // Add a dummy node for the previous guard - // expression to target - let guard_start = self.add_dummy_node(&[pat_exit]); - // Visit the guard expression - let guard_exit = match guard { - hir::Guard::If(ref e) => (&**e, self.expr(e, guard_start)), - }; - // #47295: We used to have very special case code - // here for when a pair of arms are both formed - // solely from constants, and if so, not add these - // edges. But this was not actually sound without - // other constraints that we stopped enforcing at - // some point. - if let Some((prev_guard, prev_index)) = prev_guard.take() { - self.add_exiting_edge(prev_guard, prev_index, match_scope, guard_start); - } - - // Push the guard onto the list of previous guards - prev_guard = Some(guard_exit); - - // Update the exit node for the pattern - pat_exit = guard_exit.1; - } - - // Add an edge from the exit of this pattern to the - // exit of the arm - self.add_contained_edge(pat_exit, bindings_exit); - } - - // Visit the body of this arm - let body_exit = self.expr(&arm.body, bindings_exit); - - let arm_exit = self.add_ast_node(arm.hir_id.local_id, &[body_exit]); - - // Link the body to the exit of the expression - self.add_contained_edge(arm_exit, expr_exit); - } - - expr_exit - } - - fn add_dummy_node(&mut self, preds: &[CFGIndex]) -> CFGIndex { - self.add_node(CFGNodeData::Dummy, preds) - } - - fn add_ast_node(&mut self, id: hir::ItemLocalId, preds: &[CFGIndex]) -> CFGIndex { - self.add_node(CFGNodeData::AST(id), preds) - } - - fn add_unreachable_node(&mut self) -> CFGIndex { - self.add_node(CFGNodeData::Unreachable, &[]) - } - - fn add_node(&mut self, data: CFGNodeData, preds: &[CFGIndex]) -> CFGIndex { - let node = self.graph.add_node(data); - for &pred in preds { - self.add_contained_edge(pred, node); - } - node - } - - fn add_contained_edge(&mut self, - source: CFGIndex, - target: CFGIndex) { - let data = CFGEdgeData {exiting_scopes: vec![] }; - self.graph.add_edge(source, target, data); - } - - fn add_exiting_edge(&mut self, - from_expr: &hir::Expr, - from_index: CFGIndex, - target_scope: region::Scope, - to_index: CFGIndex) { - let mut data = CFGEdgeData { exiting_scopes: vec![] }; - let mut scope = region::Scope { - id: from_expr.hir_id.local_id, - data: region::ScopeData::Node - }; - let region_scope_tree = self.tcx.region_scope_tree(self.owner_def_id); - while scope != target_scope { - data.exiting_scopes.push(scope.item_local_id()); - scope = region_scope_tree.encl_scope(scope); - } - self.graph.add_edge(from_index, to_index, data); - } - - fn add_returning_edge(&mut self, - _from_expr: &hir::Expr, - from_index: CFGIndex) { - let data = CFGEdgeData { - exiting_scopes: self.loop_scopes.iter() - .rev() - .map(|&LoopScope { loop_id: id, .. }| id) - .collect() - }; - self.graph.add_edge(from_index, self.fn_exit, data); - } - - fn find_scope_edge(&self, - expr: &hir::Expr, - destination: hir::Destination, - scope_cf_kind: ScopeCfKind) -> (region::Scope, CFGIndex) { - - match destination.target_id { - Ok(loop_id) => { - for b in &self.breakable_block_scopes { - if b.block_expr_id == loop_id.local_id { - let scope = region::Scope { - id: loop_id.local_id, - data: region::ScopeData::Node - }; - return (scope, match scope_cf_kind { - ScopeCfKind::Break => b.break_index, - ScopeCfKind::Continue => bug!("can't continue to block"), - }); - } - } - for l in &self.loop_scopes { - if l.loop_id == loop_id.local_id { - let scope = region::Scope { - id: loop_id.local_id, - data: region::ScopeData::Node - }; - return (scope, match scope_cf_kind { - ScopeCfKind::Break => l.break_index, - ScopeCfKind::Continue => l.continue_index, - }); - } - } - span_bug!(expr.span, "no scope for id {}", loop_id); - } - Err(err) => span_bug!(expr.span, "scope error: {}", err), - } - } -} - -#[derive(Copy, Clone, Eq, PartialEq)] -enum ScopeCfKind { - Break, - Continue, -} diff --git a/src/librustc/cfg/graphviz.rs b/src/librustc/cfg/graphviz.rs deleted file mode 100644 index 918120057d4d3..0000000000000 --- a/src/librustc/cfg/graphviz.rs +++ /dev/null @@ -1,123 +0,0 @@ -/// This module provides linkage between rustc::middle::graph and -/// libgraphviz traits. - -// For clarity, rename the graphviz crate locally to dot. -use graphviz as dot; - -use crate::cfg; -use crate::hir; -use crate::ty::TyCtxt; - -pub type Node<'a> = (cfg::CFGIndex, &'a cfg::CFGNode); -pub type Edge<'a> = &'a cfg::CFGEdge; - -pub struct LabelledCFG<'a, 'tcx> { - pub tcx: TyCtxt<'tcx>, - pub cfg: &'a cfg::CFG, - pub name: String, - /// `labelled_edges` controls whether we emit labels on the edges - pub labelled_edges: bool, -} - -impl<'a, 'tcx> LabelledCFG<'a, 'tcx> { - fn local_id_to_string(&self, local_id: hir::ItemLocalId) -> String { - assert!(self.cfg.owner_def_id.is_local()); - let hir_id = hir::HirId { - owner: self.tcx.hir().def_index_to_hir_id(self.cfg.owner_def_id.index).owner, - local_id - }; - let s = self.tcx.hir().node_to_string(hir_id); - - // Replacing newlines with \\l causes each line to be left-aligned, - // improving presentation of (long) pretty-printed expressions. - if s.contains("\n") { - let mut s = s.replace("\n", "\\l"); - // Apparently left-alignment applies to the line that precedes - // \l, not the line that follows; so, add \l at end of string - // if not already present, ensuring last line gets left-aligned - // as well. - let mut last_two: Vec<_> = - s.chars().rev().take(2).collect(); - last_two.reverse(); - if last_two != ['\\', 'l'] { - s.push_str("\\l"); - } - s - } else { - s - } - } -} - -impl<'a, 'hir> dot::Labeller<'a> for LabelledCFG<'a, 'hir> { - type Node = Node<'a>; - type Edge = Edge<'a>; - fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new(&self.name[..]).unwrap() } - - fn node_id(&'a self, &(i,_): &Node<'a>) -> dot::Id<'a> { - dot::Id::new(format!("N{}", i.node_id())).unwrap() - } - - fn node_label(&'a self, &(i, n): &Node<'a>) -> dot::LabelText<'a> { - if i == self.cfg.entry { - dot::LabelText::LabelStr("entry".into()) - } else if i == self.cfg.exit { - dot::LabelText::LabelStr("exit".into()) - } else if n.data.id() == hir::DUMMY_ITEM_LOCAL_ID { - dot::LabelText::LabelStr("(dummy_node)".into()) - } else { - let s = self.local_id_to_string(n.data.id()); - dot::LabelText::EscStr(s.into()) - } - } - - fn edge_label(&self, e: &Edge<'a>) -> dot::LabelText<'a> { - let mut label = String::new(); - if !self.labelled_edges { - return dot::LabelText::EscStr(label.into()); - } - let mut put_one = false; - for (i, &id) in e.data.exiting_scopes.iter().enumerate() { - if put_one { - label.push_str(",\\l"); - } else { - put_one = true; - } - let s = self.local_id_to_string(id); - label.push_str(&format!("exiting scope_{} {}", - i, - &s[..])); - } - dot::LabelText::EscStr(label.into()) - } -} - -impl<'a> dot::GraphWalk<'a> for &'a cfg::CFG { - type Node = Node<'a>; - type Edge = Edge<'a>; - fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { - let v: Vec<_> = self.graph.enumerated_nodes().collect(); - v.into() - } - fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { - self.graph.all_edges().iter().collect() - } - fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { - let i = edge.source(); - (i, self.graph.node(i)) - } - fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { - let i = edge.target(); - (i, self.graph.node(i)) - } -} - -impl<'a, 'hir> dot::GraphWalk<'a> for LabelledCFG<'a, 'hir> -{ - type Node = Node<'a>; - type Edge = Edge<'a>; - fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { self.cfg.nodes() } - fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { self.cfg.edges() } - fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { self.cfg.source(edge) } - fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { self.cfg.target(edge) } -} diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs deleted file mode 100644 index 88fc7fbfad51f..0000000000000 --- a/src/librustc/cfg/mod.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! Module that constructs a control-flow graph representing an item. -//! Uses `Graph` as the underlying representation. - -use rustc_data_structures::graph::implementation as graph; -use crate::ty::TyCtxt; -use crate::hir; -use crate::hir::def_id::DefId; - -mod construct; -pub mod graphviz; - -pub struct CFG { - pub owner_def_id: DefId, - pub graph: CFGGraph, - pub entry: CFGIndex, - pub exit: CFGIndex, -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum CFGNodeData { - AST(hir::ItemLocalId), - Entry, - Exit, - Dummy, - Unreachable, -} - -impl CFGNodeData { - pub fn id(&self) -> hir::ItemLocalId { - if let CFGNodeData::AST(id) = *self { - id - } else { - hir::DUMMY_ITEM_LOCAL_ID - } - } -} - -#[derive(Debug)] -pub struct CFGEdgeData { - pub exiting_scopes: Vec -} - -pub type CFGIndex = graph::NodeIndex; - -pub type CFGGraph = graph::Graph; - -pub type CFGNode = graph::Node; - -pub type CFGEdge = graph::Edge; - -impl CFG { - pub fn new(tcx: TyCtxt<'_>, body: &hir::Body) -> CFG { - construct::construct(tcx, body) - } - - pub fn node_is_reachable(&self, id: hir::ItemLocalId) -> bool { - self.graph.depth_traverse(self.entry, graph::OUTGOING) - .any(|idx| self.graph.node_data(idx).id() == id) - } -} diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 3d5e7dd0af121..0686bec0621f4 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -114,7 +114,6 @@ macro_rules! define_dep_nodes { impl DepKind { #[allow(unreachable_code)] - #[inline] pub fn can_reconstruct_query_key<$tcx>(&self) -> bool { match *self { $( @@ -150,7 +149,6 @@ macro_rules! define_dep_nodes { } } - #[inline(always)] pub fn is_eval_always(&self) -> bool { match *self { $( @@ -199,7 +197,6 @@ macro_rules! define_dep_nodes { impl DepNode { #[allow(unreachable_code, non_snake_case)] - #[inline(always)] pub fn new<'tcx>(tcx: TyCtxt<'tcx>, dep: DepConstructor<'tcx>) -> DepNode @@ -219,14 +216,16 @@ macro_rules! define_dep_nodes { hash }; - if cfg!(debug_assertions) && - !dep_node.kind.can_reconstruct_query_key() && - (tcx.sess.opts.debugging_opts.incremental_info || - tcx.sess.opts.debugging_opts.query_dep_graph) + #[cfg(debug_assertions)] { - tcx.dep_graph.register_dep_node_debug_str(dep_node, || { - arg.to_debug_str(tcx) - }); + if !dep_node.kind.can_reconstruct_query_key() && + (tcx.sess.opts.debugging_opts.incremental_info || + tcx.sess.opts.debugging_opts.query_dep_graph) + { + tcx.dep_graph.register_dep_node_debug_str(dep_node, || { + arg.to_debug_str(tcx) + }); + } } return dep_node; @@ -242,14 +241,16 @@ macro_rules! define_dep_nodes { hash }; - if cfg!(debug_assertions) && - !dep_node.kind.can_reconstruct_query_key() && - (tcx.sess.opts.debugging_opts.incremental_info || - tcx.sess.opts.debugging_opts.query_dep_graph) + #[cfg(debug_assertions)] { - tcx.dep_graph.register_dep_node_debug_str(dep_node, || { - tupled_args.to_debug_str(tcx) - }); + if !dep_node.kind.can_reconstruct_query_key() && + (tcx.sess.opts.debugging_opts.incremental_info || + tcx.sess.opts.debugging_opts.query_dep_graph) + { + tcx.dep_graph.register_dep_node_debug_str(dep_node, || { + tupled_args.to_debug_str(tcx) + }); + } } return dep_node; @@ -267,7 +268,6 @@ macro_rules! define_dep_nodes { /// Construct a DepNode from the given DepKind and DefPathHash. This /// method will assert that the given DepKind actually requires a /// single DefId/DefPathHash parameter. - #[inline(always)] pub fn from_def_path_hash(kind: DepKind, def_path_hash: DefPathHash) -> DepNode { @@ -281,7 +281,6 @@ macro_rules! define_dep_nodes { /// Creates a new, parameterless DepNode. This method will assert /// that the DepNode corresponding to the given DepKind actually /// does not require any parameters. - #[inline(always)] pub fn new_no_params(kind: DepKind) -> DepNode { debug_assert!(!kind.has_params()); DepNode { @@ -300,7 +299,6 @@ macro_rules! define_dep_nodes { /// DepNode. Condition (2) might not be fulfilled if a DepNode /// refers to something from the previous compilation session that /// has been removed. - #[inline] pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option { if self.kind.can_reconstruct_query_key() { let def_path_hash = DefPathHash(self.hash); @@ -386,14 +384,12 @@ impl fmt::Debug for DepNode { impl DefPathHash { - #[inline(always)] pub fn to_dep_node(self, kind: DepKind) -> DepNode { DepNode::from_def_path_hash(kind, self) } } impl DefId { - #[inline(always)] pub fn to_dep_node(self, tcx: TyCtxt<'_>, kind: DepKind) -> DepNode { DepNode::from_def_path_hash(kind, tcx.def_path_hash(self)) } diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs deleted file mode 100644 index ee22d0b755a09..0000000000000 --- a/src/librustc/dep_graph/dep_tracking_map.rs +++ /dev/null @@ -1,87 +0,0 @@ -use rustc_data_structures::fx::FxHashMap; -use std::cell::RefCell; -use std::hash::Hash; -use std::marker::PhantomData; -use crate::util::common::MemoizationMap; - -use super::{DepKind, DepNodeIndex, DepGraph}; - -/// A DepTrackingMap offers a subset of the `Map` API and ensures that -/// we make calls to `read` and `write` as appropriate. We key the -/// maps with a unique type for brevity. -pub struct DepTrackingMap { - phantom: PhantomData, - graph: DepGraph, - map: FxHashMap, -} - -pub trait DepTrackingMapConfig { - type Key: Eq + Hash + Clone; - type Value: Clone; - fn to_dep_kind() -> DepKind; -} - -impl DepTrackingMap { - pub fn new(graph: DepGraph) -> DepTrackingMap { - DepTrackingMap { - phantom: PhantomData, - graph, - map: Default::default(), - } - } -} - -impl MemoizationMap for RefCell> { - type Key = M::Key; - type Value = M::Value; - - /// Memoizes an entry in the dep-tracking-map. If the entry is not - /// already present, then `op` will be executed to compute its value. - /// The resulting dependency graph looks like this: - /// - /// [op] -> Map(key) -> CurrentTask - /// - /// Here, `[op]` represents whatever nodes `op` reads in the - /// course of execution; `Map(key)` represents the node for this - /// map, and `CurrentTask` represents the current task when - /// `memoize` is invoked. - /// - /// **Important:** when `op` is invoked, the current task will be - /// switched to `Map(key)`. Therefore, if `op` makes use of any - /// HIR nodes or shared state accessed through its closure - /// environment, it must explicitly register a read of that - /// state. As an example, see `type_of_item` in `collect`, - /// which looks something like this: - /// - /// ``` - /// fn type_of_item(..., item: &hir::Item) -> Ty<'tcx> { - /// let item_def_id = ccx.tcx.hir().local_def_id(it.hir_id); - /// ccx.tcx.item_types.memoized(item_def_id, || { - /// ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); // (*) - /// compute_type_of_item(ccx, item) - /// }); - /// } - /// ``` - /// - /// The key is the line marked `(*)`: the closure implicitly - /// accesses the body of the item `item`, so we register a read - /// from `Hir(item_def_id)`. - fn memoize(&self, key: M::Key, op: OP) -> M::Value - where OP: FnOnce() -> M::Value - { - let graph; - { - let this = self.borrow(); - if let Some(&(ref result, dep_node)) = this.map.get(&key) { - this.graph.read_index(dep_node); - return result.clone(); - } - graph = this.graph.clone(); - } - - let (result, dep_node) = graph.with_anon_task(M::to_dep_kind(), op); - self.borrow_mut().map.insert(key, (result.clone(), dep_node)); - graph.read_index(dep_node); - result - } -} diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 7eea336cbbfa1..8f18e0312862f 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -1,7 +1,7 @@ -use errors::{Diagnostic, DiagnosticBuilder}; +use errors::Diagnostic; 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_index::vec::{Idx, IndexVec}; use smallvec::SmallVec; use rustc_data_structures::sync::{Lrc, Lock, AtomicU32, Ordering}; use std::env; @@ -9,7 +9,6 @@ use std::hash::Hash; use std::collections::hash_map::Entry; use std::mem; use crate::ty::{self, TyCtxt}; -use crate::util::common::{ProfileQueriesMsg, profq_msg}; use parking_lot::{Mutex, Condvar}; use crate::ich::{StableHashingContext, StableHashingContextProvider, Fingerprint}; @@ -26,7 +25,7 @@ pub struct DepGraph { data: Option>, } -newtype_index! { +rustc_index::newtype_index! { pub struct DepNodeIndex { .. } } @@ -75,9 +74,6 @@ struct DepGraphData { previous_work_products: FxHashMap, dep_node_debug: Lock>, - - // Used for testing, only populated when -Zquery-dep-graph is specified. - loaded_from_cache: Lock>, } pub fn hash_result(hcx: &mut StableHashingContext<'_>, result: &R) -> Option @@ -104,7 +100,6 @@ impl DepGraph { emitting_diagnostics_cond_var: Condvar::new(), previous: prev_graph, colors: DepNodeColorMap::new(prev_graph_node_count), - loaded_from_cache: Default::default(), })), } } @@ -260,10 +255,6 @@ impl DepGraph { // - we can get an idea of the runtime cost. let mut hcx = cx.get_stable_hashing_context(); - if cfg!(debug_assertions) { - profq_msg(hcx.sess(), ProfileQueriesMsg::TaskBegin(key.clone())) - }; - let result = if no_tcx { task(cx, arg) } else { @@ -279,10 +270,6 @@ impl DepGraph { }) }; - if cfg!(debug_assertions) { - profq_msg(hcx.sess(), ProfileQueriesMsg::TaskEnd) - }; - let current_fingerprint = hash_result(&mut hcx, &result); let dep_node_index = finish_task_and_alloc_depnode( @@ -590,7 +577,7 @@ impl DepGraph { // mark it as green by recursively marking all of its // dependencies green. self.try_mark_previous_green( - tcx.global_tcx(), + tcx, data, prev_index, &dep_node @@ -819,7 +806,7 @@ impl DepGraph { let handle = tcx.sess.diagnostic(); for diagnostic in diagnostics { - DiagnosticBuilder::new_diagnostic(handle, diagnostic).emit(); + handle.emit_diagnostic(&diagnostic); } // Mark the node as green now that diagnostics are emitted @@ -858,6 +845,8 @@ impl DepGraph { // This method will only load queries that will end up in the disk cache. // Other queries will not be executed. pub fn exec_cache_promotions(&self, tcx: TyCtxt<'_>) { + let _prof_timer = tcx.prof.generic_activity("incr_comp_query_cache_promotion"); + let data = self.data.as_ref().unwrap(); for prev_index in data.colors.values.indices() { match data.colors.get(prev_index) { @@ -874,25 +863,6 @@ impl DepGraph { } } } - - pub fn mark_loaded_from_cache(&self, dep_node_index: DepNodeIndex, state: bool) { - debug!("mark_loaded_from_cache({:?}, {})", - self.data.as_ref().unwrap().current.borrow().data[dep_node_index].node, - state); - - self.data - .as_ref() - .unwrap() - .loaded_from_cache - .borrow_mut() - .insert(dep_node_index, state); - } - - pub fn was_loaded_from_cache(&self, dep_node: &DepNode) -> Option { - let data = self.data.as_ref().unwrap(); - let dep_node_index = data.current.borrow().node_to_node_index[dep_node]; - data.loaded_from_cache.borrow().get(&dep_node_index).cloned() - } } /// A "work product" is an intermediate result that we save into the diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 1535e6d349cf1..43f3d7e89cd5c 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -1,6 +1,5 @@ pub mod debug; mod dep_node; -mod dep_tracking_map; mod graph; mod prev; mod query; @@ -8,7 +7,6 @@ mod safe; mod serialized; pub mod cgu_reuse_tracker; -pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig}; pub use self::dep_node::{DepNode, DepKind, DepConstructor, WorkProductId, RecoverKey, label_strs}; pub use self::graph::{DepGraph, WorkProduct, DepNodeIndex, DepNodeColor, TaskDeps, hash_result}; pub use self::graph::WorkProductFileKind; diff --git a/src/librustc/dep_graph/serialized.rs b/src/librustc/dep_graph/serialized.rs index b64f71ed908d8..4302195755ea5 100644 --- a/src/librustc/dep_graph/serialized.rs +++ b/src/librustc/dep_graph/serialized.rs @@ -2,9 +2,9 @@ use crate::dep_graph::DepNode; use crate::ich::Fingerprint; -use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use rustc_index::vec::{IndexVec, Idx}; -newtype_index! { +rustc_index::newtype_index! { pub struct SerializedDepNodeIndex { .. } } diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index b3eee7c346489..50b6ef57b550c 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -1,7 +1,8 @@ // Error messages for EXXXX errors. -// Each message should start and end with a new line, and be wrapped to 80 characters. -// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable. -register_long_diagnostics! { +// Each message should start and end with a new line, and be wrapped to 80 +// characters. In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use +// `:set tw=0` to disable. +syntax::register_diagnostics! { E0038: r##" Trait objects like `Box` can only be constructed when certain requirements are satisfied by the trait in question. @@ -39,7 +40,7 @@ Generally, `Self: Sized` is used to indicate that the trait should not be used as a trait object. If the trait comes from your own crate, consider removing this restriction. -### Method references the `Self` type in its arguments or return type +### Method references the `Self` type in its parameters or return type This happens when a trait has a method like the following: @@ -258,8 +259,8 @@ trait Foo { This is similar to the second sub-error, but subtler. It happens in situations like the following: -```compile_fail -trait Super {} +```compile_fail,E0038 +trait Super {} trait Trait: Super { } @@ -269,17 +270,21 @@ struct Foo; impl Super for Foo{} impl Trait for Foo {} + +fn main() { + let x: Box; +} ``` Here, the supertrait might have methods as follows: ``` -trait Super { - fn get_a(&self) -> A; // note that this is object safe! +trait Super { + fn get_a(&self) -> &A; // note that this is object safe! } ``` -If the trait `Foo` was deriving from something like `Super` or +If the trait `Trait` was deriving from something like `Super` or `Super` (where `Foo` itself is `Foo`), this is okay, because given a type `get_a()` will definitely return an object of that type. @@ -465,67 +470,6 @@ fn main() { ``` "##, -// This shouldn't really ever trigger since the repeated value error comes first -E0136: r##" -A binary can only have one entry point, and by default that entry point is the -function `main()`. If there are multiple such functions, please rename one. -"##, - -E0137: r##" -More than one function was declared with the `#[main]` attribute. - -Erroneous code example: - -```compile_fail,E0137 -#![feature(main)] - -#[main] -fn foo() {} - -#[main] -fn f() {} // error: multiple functions with a `#[main]` attribute -``` - -This error indicates that the compiler found multiple functions with the -`#[main]` attribute. This is an error because there must be a unique entry -point into a Rust program. Example: - -``` -#![feature(main)] - -#[main] -fn f() {} // ok! -``` -"##, - -E0138: r##" -More than one function was declared with the `#[start]` attribute. - -Erroneous code example: - -```compile_fail,E0138 -#![feature(start)] - -#[start] -fn foo(argc: isize, argv: *const *const u8) -> isize {} - -#[start] -fn f(argc: isize, argv: *const *const u8) -> isize {} -// error: multiple 'start' functions -``` - -This error indicates that the compiler found multiple functions with the -`#[start]` attribute. This is an error because there must be a unique entry -point into a Rust program. Example: - -``` -#![feature(start)] - -#[start] -fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } // ok! -``` -"##, - E0139: r##" #### Note: this error code is no longer emitted by the compiler. @@ -1346,6 +1290,39 @@ struct Foo { ``` "##, +E0312: r##" +Reference's lifetime of borrowed content doesn't match the expected lifetime. + +Erroneous code example: + +```compile_fail,E0312 +pub fn opt_str<'a>(maybestr: &'a Option) -> &'static str { + if maybestr.is_none() { + "(none)" + } else { + let s: &'a str = maybestr.as_ref().unwrap(); + s // Invalid lifetime! + } +} +``` + +To fix this error, either lessen the expected lifetime or find a way to not have +to use this reference outside of its current scope (by running the code directly +in the same block for example?): + +``` +// In this case, we can fix the issue by switching from "static" lifetime to 'a +pub fn opt_str<'a>(maybestr: &'a Option) -> &'a str { + if maybestr.is_none() { + "(none)" + } else { + let s: &'a str = maybestr.as_ref().unwrap(); + s // Ok! + } +} +``` +"##, + E0317: r##" This error occurs when an `if` expression without an `else` block is used in a context where a type other than `()` is expected, for example a `let` @@ -1546,8 +1523,51 @@ where ``` "##, +E0495: r##" +A lifetime cannot be determined in the given situation. + +Erroneous code example: + +```compile_fail,E0495 +fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T { + match (&t,) { // error! + ((u,),) => u, + } +} + +let y = Box::new((42,)); +let x = transmute_lifetime(&y); +``` + +In this code, you have two ways to solve this issue: + 1. Enforce that `'a` lives at least as long as `'b`. + 2. Use the same lifetime requirement for both input and output values. + +So for the first solution, you can do it by replacing `'a` with `'a: 'b`: + +``` +fn transmute_lifetime<'a: 'b, 'b, T>(t: &'a (T,)) -> &'b T { + match (&t,) { // ok! + ((u,),) => u, + } +} +``` + +In the second you can do it by simply removing `'b` so they both use `'a`: + +``` +fn transmute_lifetime<'a, T>(t: &'a (T,)) -> &'a T { + match (&t,) { // ok! + ((u,),) => u, + } +} +``` +"##, + E0496: r##" -A lifetime name is shadowing another lifetime name. Erroneous code example: +A lifetime name is shadowing another lifetime name. + +Erroneous code example: ```compile_fail,E0496 struct Foo<'a> { @@ -1579,8 +1599,11 @@ fn main() { "##, E0497: r##" -A stability attribute was used outside of the standard library. Erroneous code -example: +#### Note: this error code is no longer emitted by the compiler. + +A stability attribute was used outside of the standard library. + +Erroneous code example: ```compile_fail #[stable] // error: stability attributes may not be used outside of the @@ -1592,33 +1615,6 @@ It is not possible to use stability attributes outside of the standard library. Also, for now, it is not possible to write deprecation messages either. "##, -E0512: r##" -Transmute with two differently sized types was attempted. Erroneous code -example: - -```compile_fail,E0512 -fn takes_u8(_: u8) {} - -fn main() { - unsafe { takes_u8(::std::mem::transmute(0u16)); } - // error: cannot transmute between types of different sizes, - // or dependently-sized types -} -``` - -Please use types with same size or use the expected type directly. Example: - -``` -fn takes_u8(_: u8) {} - -fn main() { - unsafe { takes_u8(::std::mem::transmute(0i8)); } // ok! - // or: - unsafe { takes_u8(0u8); } // ok! -} -``` -"##, - E0517: r##" This error indicates that a `#[repr(..)]` attribute was placed on an unsupported item. @@ -1753,6 +1749,27 @@ To understand better how closures work in Rust, read: https://doc.rust-lang.org/book/ch13-01-closures.html "##, +E0566: r##" +Conflicting representation hints have been used on a same item. + +Erroneous code example: + +``` +#[repr(u32, u64)] // warning! +enum Repr { A } +``` + +In most cases (if not all), using just one representation hint is more than +enough. If you want to have a representation hint depending on the current +architecture, use `cfg_attr`. Example: + +``` +#[cfg_attr(linux, repr(u32))] +#[cfg_attr(not(linux), repr(u64))] +enum Repr { A } +``` +"##, + E0580: r##" The `main` function was incorrectly declared. @@ -1813,84 +1830,6 @@ See [RFC 1522] for more details. [RFC 1522]: https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md "##, -E0591: r##" -Per [RFC 401][rfc401], if you have a function declaration `foo`: - -``` -// For the purposes of this explanation, all of these -// different kinds of `fn` declarations are equivalent: -struct S; -fn foo(x: S) { /* ... */ } -# #[cfg(for_demonstration_only)] -extern "C" { fn foo(x: S); } -# #[cfg(for_demonstration_only)] -impl S { fn foo(self) { /* ... */ } } -``` - -the type of `foo` is **not** `fn(S)`, as one might expect. -Rather, it is a unique, zero-sized marker type written here as `typeof(foo)`. -However, `typeof(foo)` can be _coerced_ to a function pointer `fn(S)`, -so you rarely notice this: - -``` -# struct S; -# fn foo(_: S) {} -let x: fn(S) = foo; // OK, coerces -``` - -The reason that this matter is that the type `fn(S)` is not specific to -any particular function: it's a function _pointer_. So calling `x()` results -in a virtual call, whereas `foo()` is statically dispatched, because the type -of `foo` tells us precisely what function is being called. - -As noted above, coercions mean that most code doesn't have to be -concerned with this distinction. However, you can tell the difference -when using **transmute** to convert a fn item into a fn pointer. - -This is sometimes done as part of an FFI: - -```compile_fail,E0591 -extern "C" fn foo(userdata: Box) { - /* ... */ -} - -# fn callback(_: extern "C" fn(*mut i32)) {} -# use std::mem::transmute; -# unsafe { -let f: extern "C" fn(*mut i32) = transmute(foo); -callback(f); -# } -``` - -Here, transmute is being used to convert the types of the fn arguments. -This pattern is incorrect because, because the type of `foo` is a function -**item** (`typeof(foo)`), which is zero-sized, and the target type (`fn()`) -is a function pointer, which is not zero-sized. -This pattern should be rewritten. There are a few possible ways to do this: - -- change the original fn declaration to match the expected signature, - and do the cast in the fn body (the preferred option) -- cast the fn item fo a fn pointer before calling transmute, as shown here: - - ``` - # extern "C" fn foo(_: Box) {} - # use std::mem::transmute; - # unsafe { - let f: extern "C" fn(*mut i32) = transmute(foo as extern "C" fn(_)); - let f: extern "C" fn(*mut i32) = transmute(foo as usize); // works too - # } - ``` - -The same applies to transmutes to `*mut fn()`, which were observed in practice. -Note though that use of this type is generally incorrect. -The intention is typically to describe a function pointer, but just `fn()` -alone suffices for that. `*mut fn()` is a pointer to a fn pointer. -(Since these values are typically just passed to C code, however, this rarely -makes a difference in practice.) - -[rfc401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md -"##, - E0593: r##" You tried to supply an `Fn`-based type with an incorrect number of arguments than what was expected. @@ -1907,21 +1846,6 @@ fn main() { ``` "##, -E0601: r##" -No `main` function was found in a binary crate. To fix this error, add a -`main` function. For example: - -``` -fn main() { - // Your program will start here. - println!("Hello world!"); -} -``` - -If you don't know the basics of Rust, you can go look to the Rust Book to get -started: https://doc.rust-lang.org/book/ -"##, - E0602: r##" An unknown lint was used on the command line. @@ -2088,7 +2012,6 @@ generator can be constructed. Erroneous code example: ```edition2018,compile-fail,E0698 -#![feature(async_await)] async fn bar() -> () {} async fn foo() { @@ -2101,7 +2024,6 @@ To fix this you must bind `T` to a concrete type such as `String` so that a generator can then be constructed: ```edition2018 -#![feature(async_await)] async fn bar() -> () {} async fn foo() { @@ -2186,10 +2108,42 @@ static X: u32 = 42; ``` "##, -} +E0734: r##" +A stability attribute has been used outside of the standard library. + +Erroneous code examples: + +```compile_fail,E0734 +#[rustc_deprecated(since = "b", reason = "text")] // invalid +#[stable(feature = "a", since = "b")] // invalid +#[unstable(feature = "b", issue = "0")] // invalid +fn foo(){} +``` + +These attributes are meant to only be used by the standard library and are +rejected in your own crates. +"##, +E0736: r##" +#[track_caller] and #[naked] cannot be applied to the same function. + +Erroneous code example: + +```compile_fail,E0736 +#![feature(track_caller)] + +#[naked] +#[track_caller] +fn foo() {} +``` + +This is primarily due to ABI incompatibilities between the two attributes. +See [RFC 2091] for details on this and other limitations. + +[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md +"##, -register_diagnostics! { +; // E0006, // merged with E0005 // E0101, // replaced with E0282 // E0102, // replaced with E0282 @@ -2198,7 +2152,7 @@ register_diagnostics! { // E0272, // on_unimplemented #0 // E0273, // on_unimplemented #1 // E0274, // on_unimplemented #2 - E0278, // requirement is not satisfied +// E0278, // requirement is not satisfied E0279, // requirement is not satisfied E0280, // requirement is not satisfied // E0285, // overflow evaluation builtin bounds @@ -2207,8 +2161,8 @@ register_diagnostics! { // E0304, // expected signed integer constant // E0305, // expected constant E0311, // thing may not live long enough - E0312, // lifetime of reference outlives lifetime of borrowed content - E0313, // lifetime of borrowed pointer outlives lifetime of captured variable + E0313, // lifetime of borrowed pointer outlives lifetime of captured + // variable E0314, // closure outlives stack frame E0315, // cannot invoke closure outside of its lifetime E0316, // nested quantification of lifetimes @@ -2225,28 +2179,28 @@ register_diagnostics! { E0483, // lifetime of operand does not outlive the operation E0484, // reference is not valid at the time of borrow E0485, // automatically reference is not valid at the time of borrow - E0486, // type of expression contains references that are not valid during... + E0486, // type of expression contains references that are not valid during.. E0487, // unsafe use of destructor: destructor might be called while... E0488, // lifetime of variable does not enclose its declaration E0489, // type/lifetime parameter not in scope here E0490, // a value of type `..` is borrowed for too long - E0495, // cannot infer an appropriate lifetime due to conflicting requirements - E0566, // conflicting representation hints E0623, // lifetime mismatch where both parameters are anonymous regions - E0628, // generators cannot have explicit arguments + E0628, // generators cannot have explicit parameters E0631, // type mismatch in closure arguments E0637, // "'_" is not a valid lifetime bound E0657, // `impl Trait` can only capture lifetimes bound at the fn level E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders E0697, // closures cannot be static - E0707, // multiple elided lifetimes used in arguments of `async fn` - E0708, // `async` non-`move` closures with arguments are not currently supported - E0709, // multiple different lifetimes used in arguments of `async fn` +// E0707, // multiple elided lifetimes used in arguments of `async fn` + E0708, // `async` non-`move` closures with parameters are not currently + // supported +// E0709, // multiple different lifetimes used in arguments of `async fn` E0710, // an unknown tool name found in scoped lint E0711, // a feature has been declared with conflicting stability attributes // E0702, // replaced with a generic attribute input check E0726, // non-explicit (not `'_`) elided lifetime in unsupported position E0727, // `async` generators are not yet supported E0728, // `await` must be in an `async` function or block + E0739, // invalid track_caller application/syntax } diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 22124d4ee4120..c37fec982b116 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -4,15 +4,14 @@ //! conflicts between multiple such attributes attached to the same //! item. - -use crate::ty::TyCtxt; -use crate::ty::query::Providers; - use crate::hir; use crate::hir::def_id::DefId; use crate::hir::intravisit::{self, Visitor, NestedVisitorMap}; +use crate::ty::TyCtxt; +use crate::ty::query::Providers; + use std::fmt::{self, Display}; -use syntax::symbol::sym; +use syntax::{attr, symbol::sym}; use syntax_pos::Span; #[derive(Copy, Clone, PartialEq)] @@ -66,7 +65,7 @@ impl Display for Target { impl Target { pub(crate) fn from_item(item: &hir::Item) -> Target { - match item.node { + match item.kind { hir::ItemKind::ExternCrate(..) => Target::ExternCrate, hir::ItemKind::Use(..) => Target::Use, hir::ItemKind::Static(..) => Target::Static, @@ -94,30 +93,37 @@ struct CheckAttrVisitor<'tcx> { impl CheckAttrVisitor<'tcx> { /// Checks any attribute. fn check_attributes(&self, item: &hir::Item, target: Target) { - if target == Target::Fn || target == Target::Const { - self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id(item.hir_id)); - } else if let Some(a) = item.attrs.iter().find(|a| a.check_name(sym::target_feature)) { - self.tcx.sess.struct_span_err(a.span, "attribute should be applied to a function") - .span_label(item.span, "not a function") - .emit(); - } - + let mut is_valid = true; for attr in &item.attrs { - if attr.check_name(sym::inline) { + is_valid &= if attr.check_name(sym::inline) { self.check_inline(attr, &item.span, target) } else if attr.check_name(sym::non_exhaustive) { self.check_non_exhaustive(attr, item, target) } else if attr.check_name(sym::marker) { self.check_marker(attr, item, target) - } + } else if attr.check_name(sym::target_feature) { + self.check_target_feature(attr, item, target) + } else if attr.check_name(sym::track_caller) { + self.check_track_caller(attr, &item, target) + } else { + true + }; + } + + if !is_valid { + return; + } + + if target == Target::Fn { + self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id(item.hir_id)); } self.check_repr(item, target); self.check_used(item, target); } - /// Checks if an `#[inline]` is applied to a function or a closure. - fn check_inline(&self, attr: &hir::Attribute, span: &Span, target: Target) { + /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid. + fn check_inline(&self, attr: &hir::Attribute, span: &Span, target: Target) -> bool { if target != Target::Fn && target != Target::Closure { struct_span_err!(self.tcx.sess, attr.span, @@ -125,13 +131,47 @@ impl CheckAttrVisitor<'tcx> { "attribute should be applied to function or closure") .span_label(*span, "not a function or closure") .emit(); + false + } else { + true } } - /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. - fn check_non_exhaustive(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) { + /// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid. + fn check_track_caller(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) -> bool { + if target != Target::Fn { + struct_span_err!( + self.tcx.sess, + attr.span, + E0739, + "attribute should be applied to function" + ) + .span_label(item.span, "not a function") + .emit(); + false + } else if attr::contains_name(&item.attrs, sym::naked) { + struct_span_err!( + self.tcx.sess, + attr.span, + E0736, + "cannot use `#[track_caller]` with `#[naked]`", + ) + .emit(); + false + } else { + true + } + } + + /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid. + fn check_non_exhaustive( + &self, + attr: &hir::Attribute, + item: &hir::Item, + target: Target, + ) -> bool { match target { - Target::Struct | Target::Enum => { /* Valid */ }, + Target::Struct | Target::Enum => true, _ => { struct_span_err!(self.tcx.sess, attr.span, @@ -139,25 +179,44 @@ impl CheckAttrVisitor<'tcx> { "attribute can only be applied to a struct or enum") .span_label(item.span, "not a struct or enum") .emit(); - return; + false } } } - /// Checks if the `#[marker]` attribute on an `item` is valid. - fn check_marker(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) { + /// Checks if the `#[marker]` attribute on an `item` is valid. Returns `true` if valid. + fn check_marker(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) -> bool { match target { - Target::Trait => { /* Valid */ }, + Target::Trait => true, _ => { self.tcx.sess .struct_span_err(attr.span, "attribute can only be applied to a trait") .span_label(item.span, "not a trait") .emit(); - return; + false } } } + /// Checks if the `#[target_feature]` attribute on `item` is valid. Returns `true` if valid. + fn check_target_feature( + &self, + attr: &hir::Attribute, + item: &hir::Item, + target: Target, + ) -> bool { + match target { + Target::Fn => true, + _ => { + self.tcx.sess + .struct_span_err(attr.span, "attribute should be applied to a function") + .span_label(item.span, "not a function") + .emit(); + false + }, + } + } + /// Checks if the `#[repr]` attributes on `item` are valid. fn check_repr(&self, item: &hir::Item, target: Target) { // Extract the names of all repr hints, e.g., [foo, bar, align] for: @@ -263,7 +322,7 @@ impl CheckAttrVisitor<'tcx> { fn check_stmt_attributes(&self, stmt: &hir::Stmt) { // When checking statements ignore expressions, they will be checked later - if let hir::StmtKind::Local(ref l) = stmt.node { + if let hir::StmtKind::Local(ref l) = stmt.kind { for attr in l.attrs.iter() { if attr.check_name(sym::inline) { self.check_inline(attr, &stmt.span, Target::Statement); @@ -281,7 +340,7 @@ impl CheckAttrVisitor<'tcx> { } fn check_expr_attributes(&self, expr: &hir::Expr) { - let target = match expr.node { + let target = match expr.kind { hir::ExprKind::Closure(..) => Target::Closure, _ => Target::Expression, }; @@ -334,9 +393,9 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> { } fn is_c_like_enum(item: &hir::Item) -> bool { - if let hir::ItemKind::Enum(ref def, _) = item.node { + if let hir::ItemKind::Enum(ref def, _) = item.kind { for variant in &def.variants { - match variant.node.data { + match variant.data { hir::VariantData::Unit(..) => { /* continue */ } _ => { return false; } } diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 40992e927444b..f7d31ca06ee56 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -1,15 +1,17 @@ -use crate::hir::def_id::DefId; +use self::Namespace::*; + +use crate::hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use crate::hir; +use crate::ty; use crate::util::nodemap::DefIdMap; + use syntax::ast; use syntax::ext::base::MacroKind; use syntax::ast::NodeId; use syntax_pos::Span; use rustc_macros::HashStable; -use crate::hir; -use crate::ty; -use std::fmt::Debug; -use self::Namespace::*; +use std::fmt::Debug; /// Encodes if a `DefKind::Ctor` is the constructor of an enum variant or a struct. #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, HashStable)] @@ -81,9 +83,11 @@ pub enum DefKind { } impl DefKind { - pub fn descr(self) -> &'static str { + pub fn descr(self, def_id: DefId) -> &'static str { match self { DefKind::Fn => "function", + DefKind::Mod if def_id.index == CRATE_DEF_INDEX && def_id.krate != LOCAL_CRATE => + "crate", DefKind::Mod => "module", DefKind::Static => "static", DefKind::Enum => "enum", @@ -113,7 +117,7 @@ impl DefKind { } } - /// An English article for the def. + /// Gets an English article for the definition. pub fn article(&self) -> &'static str { match *self { DefKind::AssocTy @@ -132,18 +136,22 @@ pub enum Res { Def(DefKind, DefId), // Type namespace + PrimTy(hir::PrimTy), SelfTy(Option /* trait */, Option /* impl */), ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]` // Value namespace + SelfCtor(DefId /* impl */), // `DefId` refers to the impl Local(Id), // Macro namespace + NonMacroAttr(NonMacroAttrKind), // e.g., `#[inline]` or `#[rustfmt::skip]` // All namespaces + Err, } @@ -328,7 +336,7 @@ impl NonMacroAttrKind { } impl Res { - /// Return the `DefId` of this `Def` if it has an id, else panic. + /// Return the `DefId` of this `Def` if it has an ID, else panic. pub fn def_id(&self) -> DefId where Id: Debug, @@ -338,7 +346,7 @@ impl Res { }) } - /// Return `Some(..)` with the `DefId` of this `Res` if it has a id, else `None`. + /// Return `Some(..)` with the `DefId` of this `Res` if it has a ID, else `None`. pub fn opt_def_id(&self) -> Option { match *self { Res::Def(_, id) => Some(id), @@ -366,7 +374,7 @@ impl Res { /// A human readable name for the res kind ("function", "module", etc.). pub fn descr(&self) -> &'static str { match *self { - Res::Def(kind, _) => kind.descr(), + Res::Def(kind, def_id) => kind.descr(def_id), Res::SelfCtor(..) => "self constructor", Res::PrimTy(..) => "builtin type", Res::Local(..) => "local variable", @@ -377,7 +385,7 @@ impl Res { } } - /// An English article for the res. + /// Gets an English article for the `Res`. pub fn article(&self) -> &'static str { match *self { Res::Def(kind, _) => kind.article(), diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index c0a661908a654..13200b38f2cda 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -1,10 +1,9 @@ use crate::ty::{self, TyCtxt}; -use crate::hir::map::definitions::FIRST_FREE_DEF_INDEX; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use std::fmt; use std::u32; -newtype_index! { +rustc_index::newtype_index! { pub struct CrateId { ENCODABLE = custom } @@ -12,7 +11,7 @@ newtype_index! { #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum CrateNum { - /// A special CrateNum that we use for the tcx.rcache when decoding from + /// A special `CrateNum` that we use for the `tcx.rcache` when decoding from /// the incr. comp. cache. ReservedForIncrCompCache, Index(CrateId), @@ -27,11 +26,10 @@ impl ::std::fmt::Debug for CrateNum { } } -/// Item definitions in the currently-compiled crate would have the CrateNum -/// LOCAL_CRATE in their DefId. +/// Item definitions in the currently-compiled crate would have the `CrateNum` +/// `LOCAL_CRATE` in their `DefId`. pub const LOCAL_CRATE: CrateNum = CrateNum::Index(CrateId::from_u32_const(0)); - impl Idx for CrateNum { #[inline] fn new(value: usize) -> Self { @@ -89,7 +87,7 @@ impl fmt::Display for CrateNum { impl rustc_serialize::UseSpecializedEncodable for CrateNum {} impl rustc_serialize::UseSpecializedDecodable for CrateNum {} -newtype_index! { +rustc_index::newtype_index! { /// A DefIndex is an index into the hir-map for a crate, identifying a /// particular definition. It should really be considered an interned /// shorthand for a particular DefPath. @@ -102,31 +100,6 @@ newtype_index! { } } -impl DefIndex { - // Proc macros from a proc-macro crate have a kind of virtual DefIndex. This - // function maps the index of the macro within the crate (which is also the - // index of the macro in the CrateMetadata::proc_macros array) to the - // corresponding DefIndex. - pub fn from_proc_macro_index(proc_macro_index: usize) -> DefIndex { - // DefIndex for proc macros start from FIRST_FREE_DEF_INDEX, - // because the first FIRST_FREE_DEF_INDEX indexes are reserved - // for internal use. - let def_index = DefIndex::from( - proc_macro_index.checked_add(FIRST_FREE_DEF_INDEX) - .expect("integer overflow adding `proc_macro_index`")); - assert!(def_index != CRATE_DEF_INDEX); - def_index - } - - // This function is the reverse of from_proc_macro_index() above. - pub fn to_proc_macro_index(self: DefIndex) -> usize { - self.index().checked_sub(FIRST_FREE_DEF_INDEX) - .unwrap_or_else(|| { - bug!("using local index {:?} as proc-macro index", self) - }) - } -} - impl rustc_serialize::UseSpecializedEncodable for DefIndex {} impl rustc_serialize::UseSpecializedDecodable for DefIndex {} diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index b5c760bc9a08e..05bdd0887f0f6 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -31,11 +31,13 @@ //! This order consistency is required in a few places in rustc, for //! example generator inference, and possibly also HIR borrowck. -use syntax::ast::{Ident, Name, Attribute}; -use syntax_pos::Span; +use super::itemlikevisit::DeepVisitor; + use crate::hir::*; use crate::hir::map::Map; -use super::itemlikevisit::DeepVisitor; + +use syntax::ast::{Ident, Name, Attribute}; +use syntax_pos::Span; #[derive(Copy, Clone)] pub enum FnKind<'a> { @@ -139,7 +141,7 @@ impl<'this, 'tcx> NestedVisitorMap<'this, 'tcx> { /// explicitly, you need to override each method. (And you also need /// to monitor future changes to `Visitor` in case a new method with a /// new default implementation gets introduced.) -pub trait Visitor<'v> : Sized { +pub trait Visitor<'v>: Sized { /////////////////////////////////////////////////////////////////////////// // Nested items. @@ -162,8 +164,8 @@ pub trait Visitor<'v> : Sized { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v>; /// Invoked when a nested item is encountered. By default does - /// nothing unless you override `nested_visit_map` to return - /// `Some(_)`, in which case it will walk the item. **You probably + /// nothing unless you override `nested_visit_map` to return other than + /// `None`, in which case it will walk the item. **You probably /// don't want to override this method** -- instead, override /// `nested_visit_map` or use the "shallow" or "deep" visit /// patterns described on `itemlikevisit::ItemLikeVisitor`. The only @@ -201,8 +203,8 @@ pub trait Visitor<'v> : Sized { /// Invoked to visit the body of a function, method or closure. Like /// visit_nested_item, does nothing by default unless you override - /// `nested_visit_map` to return `Some(_)`, in which case it will walk the - /// body. + /// `nested_visit_map` to return other htan `None`, in which case it will walk + /// the body. fn visit_nested_body(&mut self, id: BodyId) { let opt_body = self.nested_visit_map().intra().map(|map| map.body(id)); if let Some(body) = opt_body { @@ -210,8 +212,8 @@ pub trait Visitor<'v> : Sized { } } - fn visit_arg(&mut self, arg: &'v Arg) { - walk_arg(self, arg) + fn visit_param(&mut self, param: &'v Param) { + walk_param(self, param) } /// Visits the top-level item and (optionally) nested items / impl items. See @@ -400,7 +402,7 @@ pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod, mod_hir_id } pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) { - walk_list!(visitor, visit_arg, &body.arguments); + walk_list!(visitor, visit_param, &body.params); visitor.visit_expr(&body.value); } @@ -433,6 +435,7 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime LifetimeName::Static | LifetimeName::Error | LifetimeName::Implicit | + LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Underscore => {} } } @@ -453,16 +456,16 @@ pub fn walk_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v TraitRef) visitor.visit_path(&trait_ref.path, trait_ref.hir_ref_id) } -pub fn walk_arg<'v, V: Visitor<'v>>(visitor: &mut V, arg: &'v Arg) { - visitor.visit_id(arg.hir_id); - visitor.visit_pat(&arg.pat); - walk_list!(visitor, visit_attribute, &arg.attrs); +pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param) { + visitor.visit_id(param.hir_id); + visitor.visit_pat(¶m.pat); + walk_list!(visitor, visit_attribute, ¶m.attrs); } pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_vis(&item.vis); visitor.visit_ident(item.ident); - match item.node { + match item.kind { ItemKind::ExternCrate(orig_name) => { visitor.visit_id(item.hir_id); if let Some(orig_name) = orig_name { @@ -577,21 +580,21 @@ pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant, generics: &'v Generics, parent_item_id: HirId) { - visitor.visit_ident(variant.node.ident); - visitor.visit_id(variant.node.id); - visitor.visit_variant_data(&variant.node.data, - variant.node.ident.name, + visitor.visit_ident(variant.ident); + visitor.visit_id(variant.id); + visitor.visit_variant_data(&variant.data, + variant.ident.name, generics, parent_item_id, variant.span); - walk_list!(visitor, visit_anon_const, &variant.node.disr_expr); - walk_list!(visitor, visit_attribute, &variant.node.attrs); + walk_list!(visitor, visit_anon_const, &variant.disr_expr); + walk_list!(visitor, visit_attribute, &variant.attrs); } pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { visitor.visit_id(typ.hir_id); - match typ.node { + match typ.kind { TyKind::Slice(ref ty) => { visitor.visit_ty(ty) } @@ -602,7 +605,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { visitor.visit_lifetime(lifetime); visitor.visit_ty(&mutable_type.ty) } - TyKind::Never => {}, + TyKind::Never => {} TyKind::Tup(ref tuple_element_types) => { walk_list!(visitor, visit_ty, tuple_element_types); } @@ -630,9 +633,6 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { TyKind::Typeof(ref expression) => { visitor.visit_anon_const(expression) } - TyKind::CVarArgs(ref lt) => { - visitor.visit_lifetime(lt) - } TyKind::Infer | TyKind::Err => {} } } @@ -693,7 +693,7 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V, pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { visitor.visit_id(pattern.hir_id); - match pattern.node { + match pattern.kind { PatKind::TupleStruct(ref qpath, ref children, _) => { visitor.visit_qpath(qpath, pattern.hir_id, pattern.span); walk_list!(visitor, visit_pat, children); @@ -704,11 +704,12 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { PatKind::Struct(ref qpath, ref fields, _) => { visitor.visit_qpath(qpath, pattern.hir_id, pattern.span); for field in fields { - visitor.visit_id(field.node.hir_id); - visitor.visit_ident(field.node.ident); - visitor.visit_pat(&field.node.pat) + visitor.visit_id(field.hir_id); + visitor.visit_ident(field.ident); + visitor.visit_pat(&field.pat) } } + PatKind::Or(ref pats) => walk_list!(visitor, visit_pat, pats), PatKind::Tuple(ref tuple_elements, _) => { walk_list!(visitor, visit_pat, tuple_elements); } @@ -739,7 +740,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v visitor.visit_vis(&foreign_item.vis); visitor.visit_ident(foreign_item.ident); - match foreign_item.node { + match foreign_item.kind { ForeignItemKind::Fn(ref function_declaration, ref param_names, ref generics) => { visitor.visit_generics(generics); visitor.visit_fn_decl(function_declaration); @@ -852,7 +853,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai visitor.visit_ident(trait_item.ident); walk_list!(visitor, visit_attribute, &trait_item.attrs); visitor.visit_generics(&trait_item.generics); - match trait_item.node { + match trait_item.kind { TraitItemKind::Const(ref ty, default) => { visitor.visit_id(trait_item.hir_id); visitor.visit_ty(ty); @@ -901,7 +902,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt ref defaultness, ref attrs, ref generics, - ref node, + ref kind, span: _, } = *impl_item; @@ -910,7 +911,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt visitor.visit_defaultness(defaultness); walk_list!(visitor, visit_attribute, attrs); visitor.visit_generics(generics); - match *node { + match *kind { ImplItemKind::Const(ref ty, body) => { visitor.visit_id(impl_item.hir_id); visitor.visit_ty(ty); @@ -970,7 +971,7 @@ pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) { pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) { visitor.visit_id(statement.hir_id); - match statement.node { + match statement.kind { StmtKind::Local(ref local) => visitor.visit_local(local), StmtKind::Item(item) => visitor.visit_nested_item(item), StmtKind::Expr(ref expression) | @@ -988,7 +989,7 @@ pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonCo pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_id(expression.hir_id); walk_list!(visitor, visit_attribute, expression.attrs.iter()); - match expression.node { + match expression.kind { ExprKind::Box(ref subexpression) => { visitor.visit_expr(subexpression) } @@ -1099,7 +1100,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) { visitor.visit_id(arm.hir_id); - walk_list!(visitor, visit_pat, &arm.pats); + visitor.visit_pat(&arm.pat); if let Some(ref g) = arm.guard { match g { Guard::If(ref e) => visitor.visit_expr(e), diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs index 35b181245837f..39dd46c2d2903 100644 --- a/src/librustc/hir/itemlikevisit.rs +++ b/src/librustc/hir/itemlikevisit.rs @@ -1,7 +1,7 @@ use super::{Item, ImplItem, TraitItem}; use super::intravisit::Visitor; -/// The "item-like visitor" visitor defines only the top-level methods +/// The "item-like visitor" defines only the top-level methods /// that can be invoked by `Crate::visit_all_item_likes()`. Whether /// this trait is the right one to implement will depend on the /// overall pattern you need. Here are the three available patterns, @@ -18,11 +18,11 @@ use super::intravisit::Visitor; /// an item, but don't care about how item-like things are nested /// within one another. /// - Example: Examine each expression to look for its type and do some check or other. -/// - How: Implement `intravisit::Visitor` and use -/// `tcx.hir().krate().visit_all_item_likes(visitor.as_deep_visitor())`. Within -/// your `intravisit::Visitor` impl, implement methods like -/// `visit_expr()`; don't forget to invoke -/// `intravisit::walk_visit_expr()` to keep walking the subparts. +/// - How: Implement `intravisit::Visitor` and override the `nested_visit_map()` method +/// to return `NestedVisitorMap::OnlyBodies` and use +/// `tcx.hir().krate().visit_all_item_likes(&mut visitor.as_deep_visitor())`. Within +/// your `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget +/// to invoke `intravisit::walk_expr()` to keep walking the subparts). /// - Pro: Visitor methods for any kind of HIR node, not just item-like things. /// - Pro: Integrates well into dependency tracking. /// - Con: Don't get information about nesting between items @@ -30,10 +30,9 @@ use super::intravisit::Visitor; /// item-like things. /// - Example: Lifetime resolution, which wants to bring lifetimes declared on the /// impl into scope while visiting the impl-items, and then back out again. -/// - How: Implement `intravisit::Visitor` and override the -/// `nested_visit_map()` methods to return -/// `NestedVisitorMap::All`. Walk your crate with -/// `intravisit::walk_crate()` invoked on `tcx.hir().krate()`. +/// - How: Implement `intravisit::Visitor` and override the `nested_visit_map()` method +/// to return `NestedVisitorMap::All`. Walk your crate with `intravisit::walk_crate()` +/// invoked on `tcx.hir().krate()`. /// - Pro: Visitor methods for any kind of HIR node, not just item-like things. /// - Pro: Preserves nesting information /// - Con: Does not integrate well into dependency tracking. @@ -79,7 +78,7 @@ impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V> } } -/// A parallel variant of ItemLikeVisitor +/// 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); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 493083c680aad..72fd054ee8a20 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -32,12 +32,15 @@ //! get confused if the spans from leaf AST nodes occur in multiple places //! in the HIR, especially for multiple identifiers. +mod expr; +mod item; + use crate::dep_graph::DepGraph; use crate::hir::{self, ParamName}; use crate::hir::HirVec; use crate::hir::map::{DefKey, DefPathData, Definitions}; use crate::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; -use crate::hir::def::{Res, DefKind, PartialRes, PerNS}; +use crate::hir::def::{Namespace, Res, DefKind, PartialRes, PerNS}; use crate::hir::{GenericArg, ConstArg}; use crate::hir::ptr::P; use crate::lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, @@ -49,11 +52,11 @@ use crate::util::common::FN_OUTPUT_NAME; use crate::util::nodemap::{DefIdMap, NodeMap}; use errors::Applicability; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::vec::IndexVec; use rustc_data_structures::thin_vec::ThinVec; use rustc_data_structures::sync::Lrc; -use std::collections::{BTreeSet, BTreeMap}; +use std::collections::BTreeMap; use std::mem; use smallvec::SmallVec; use syntax::attr; @@ -64,19 +67,19 @@ use syntax::errors; use syntax::ext::base::SpecialDerives; use syntax::ext::hygiene::ExpnId; use syntax::print::pprust; -use syntax::source_map::{respan, ExpnInfo, ExpnKind, DesugaringKind, Spanned}; +use syntax::source_map::{respan, ExpnData, ExpnKind, DesugaringKind, Spanned}; use syntax::symbol::{kw, sym, Symbol}; use syntax::tokenstream::{TokenStream, TokenTree}; use syntax::parse::token::{self, Token}; use syntax::visit::{self, Visitor}; -use syntax_pos::{DUMMY_SP, Span}; +use syntax_pos::Span; const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF; pub struct LoweringContext<'a> { crate_root: Option, - /// Used to assign ids to HIR nodes that do not directly correspond to an AST node. + /// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes. sess: &'a Session, cstore: &'a dyn CrateStore, @@ -94,7 +97,7 @@ pub struct LoweringContext<'a> { trait_impls: BTreeMap>, - modules: BTreeMap, + modules: BTreeMap, generator_kind: Option, @@ -123,7 +126,7 @@ pub struct LoweringContext<'a> { /// lifetime definitions in the corresponding impl or function generics. lifetimes_to_define: Vec<(Span, ParamName)>, - /// Whether or not in-band lifetimes are being collected. This is used to + /// `true` if in-band lifetimes are being collected. This is used to /// indicate whether or not we're in a place where new lifetimes will result /// in in-band lifetime definitions, such a function or an impl header, /// including implicit lifetimes from `impl_header_lifetime_elision`. @@ -133,9 +136,12 @@ pub struct LoweringContext<'a> { /// When `is_collectin_in_band_lifetimes` is true, each lifetime is checked /// against this list to see if it is already in-scope, or if a definition /// needs to be created for it. - in_scope_lifetimes: Vec, + /// + /// We always store a `modern()` version of the param-name in this + /// vector. + in_scope_lifetimes: Vec, - current_module: NodeId, + current_module: hir::HirId, type_def_lifetime_params: DefIdMap, @@ -148,20 +154,13 @@ pub struct LoweringContext<'a> { } pub trait Resolver { - /// Resolve a path generated by the lowerer when expanding `for`, `if let`, etc. - fn resolve_ast_path( - &mut self, - path: &ast::Path, - is_value: bool, - ) -> Res; - - /// Obtain resolution for a `NodeId` with a single resolution. + /// Obtains resolution for a `NodeId` with a single resolution. fn get_partial_res(&mut self, id: NodeId) -> Option; - /// Obtain per-namespace resolutions for `use` statement with the given `NoedId`. + /// Obtains per-namespace resolutions for `use` statement with the given `NodeId`. fn get_import_res(&mut self, id: NodeId) -> PerNS>>; - /// Obtain resolution for a label with the given `NodeId`. + /// Obtains resolution for a label with the given `NodeId`. fn get_label_res(&mut self, id: NodeId) -> Option; /// We must keep the set of definitions up to date as we add nodes that weren't in the AST. @@ -175,7 +174,7 @@ pub trait Resolver { span: Span, crate_root: Option, components: &[Symbol], - is_value: bool, + ns: Namespace, ) -> (ast::Path, Res); fn has_derives(&self, node_id: NodeId, derives: SpecialDerives) -> bool; @@ -243,6 +242,8 @@ pub fn lower_crate( // incr. comp. yet. dep_graph.assert_ignored(); + let _prof_timer = sess.prof.generic_activity("hir_lowering"); + LoweringContext { crate_root: sess.parse_sess.injected_crate_name.try_get().copied(), sess, @@ -263,7 +264,7 @@ pub fn lower_crate( is_in_dyn_type: false, anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough, type_def_lifetime_params: Default::default(), - current_module: CRATE_NODE_ID, + current_module: hir::CRATE_HIR_ID, current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)], item_local_id_counters: Default::default(), node_id_to_hir_id: IndexVec::new(), @@ -323,7 +324,7 @@ enum ParenthesizedGenericArgs { /// `resolve_lifetime` module. Often we "fallthrough" to that code by generating /// an "elided" or "underscore" lifetime name. In the future, we probably want to move /// everything into HIR lowering. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] enum AnonymousLifetimeMode { /// For **Modern** cases, create a new anonymous region parameter /// and reference that. @@ -341,56 +342,13 @@ enum AnonymousLifetimeMode { /// Pass responsibility to `resolve_lifetime` code for all cases. PassThrough, - - /// Used in the return types of `async fn` where there exists - /// exactly one argument-position elided lifetime. - /// - /// In `async fn`, we lower the arguments types using the `CreateParameter` - /// mode, meaning that non-`dyn` elided lifetimes are assigned a fresh name. - /// If any corresponding elided lifetimes appear in the output, we need to - /// replace them with references to the fresh name assigned to the corresponding - /// elided lifetime in the arguments. - /// - /// For **Modern cases**, replace the anonymous parameter with a - /// reference to a specific freshly-named lifetime that was - /// introduced in argument - /// - /// For **Dyn Bound** cases, pass responsibility to - /// `resole_lifetime` code. - Replace(LtReplacement), -} - -/// The type of elided lifetime replacement to perform on `async fn` return types. -#[derive(Copy, Clone)] -enum LtReplacement { - /// Fresh name introduced by the single non-dyn elided lifetime - /// in the arguments of the async fn. - Some(ParamName), - - /// There is no single non-dyn elided lifetime because no lifetimes - /// appeared in the arguments. - NoLifetimes, - - /// There is no single non-dyn elided lifetime because multiple - /// lifetimes appeared in the arguments. - MultipleLifetimes, -} - -/// Calculates the `LtReplacement` to use for elided lifetimes in the return -/// type based on the fresh elided lifetimes introduced in argument position. -fn get_elided_lt_replacement(arg_position_lifetimes: &[(Span, ParamName)]) -> LtReplacement { - match arg_position_lifetimes { - [] => LtReplacement::NoLifetimes, - [(_span, param)] => LtReplacement::Some(*param), - _ => LtReplacement::MultipleLifetimes, - } } struct ImplTraitTypeIdVisitor<'a> { ids: &'a mut SmallVec<[NodeId; 1]> } impl<'a, 'b> Visitor<'a> for ImplTraitTypeIdVisitor<'b> { fn visit_ty(&mut self, ty: &'a Ty) { - match ty.node { + match ty.kind { | TyKind::Typeof(_) | TyKind::BareFn(_) => return, @@ -469,15 +427,11 @@ impl<'a> LoweringContext<'a> { impl<'tcx, 'interner> Visitor<'tcx> for MiscCollector<'tcx, 'interner> { fn visit_pat(&mut self, p: &'tcx Pat) { - match p.node { + if let PatKind::Paren(..) | PatKind::Rest = p.kind { // Doesn't generate a HIR node - PatKind::Paren(..) | PatKind::Rest => {}, - _ => { - if let Some(owner) = self.hir_id_owner { - self.lctx.lower_node_id_with_owner(p.id, owner); - } - } - }; + } else if let Some(owner) = self.hir_id_owner { + self.lctx.lower_node_id_with_owner(p.id, owner); + } visit::walk_pat(self, p) } @@ -485,7 +439,7 @@ impl<'a> LoweringContext<'a> { fn visit_item(&mut self, item: &'tcx Item) { let hir_id = self.lctx.allocate_hir_id_counter(item.id); - match item.node { + match item.kind { ItemKind::Struct(_, ref generics) | ItemKind::Union(_, ref generics) | ItemKind::Enum(_, ref generics) @@ -517,7 +471,7 @@ impl<'a> LoweringContext<'a> { fn visit_trait_item(&mut self, item: &'tcx TraitItem) { self.lctx.allocate_hir_id_counter(item.id); - match item.node { + match item.kind { TraitItemKind::Method(_, None) => { // Ignore patterns in trait methods without bodies self.with_hir_id_owner(None, |this| { @@ -545,7 +499,7 @@ impl<'a> LoweringContext<'a> { } fn visit_ty(&mut self, t: &'tcx Ty) { - match t.node { + match t.kind { // Mirrors the case in visit::walk_ty TyKind::BareFn(ref f) => { walk_list!( @@ -554,12 +508,12 @@ impl<'a> LoweringContext<'a> { &f.generic_params ); // Mirrors visit::walk_fn_decl - for argument in &f.decl.inputs { + for parameter in &f.decl.inputs { // We don't lower the ids of argument patterns self.with_hir_id_owner(None, |this| { - this.visit_pat(&argument.pat); + this.visit_pat(¶meter.pat); }); - self.visit_ty(&argument.ty) + self.visit_ty(¶meter.ty) } self.visit_fn_ret_ty(&f.decl.output) } @@ -568,90 +522,11 @@ impl<'a> LoweringContext<'a> { } } - struct ItemLowerer<'tcx, 'interner> { - lctx: &'tcx mut LoweringContext<'interner>, - } - - impl<'tcx, 'interner> ItemLowerer<'tcx, 'interner> { - fn with_trait_impl_ref(&mut self, trait_impl_ref: &Option, f: F) - where - F: FnOnce(&mut Self), - { - let old = self.lctx.is_in_trait_impl; - self.lctx.is_in_trait_impl = if let &None = trait_impl_ref { - false - } else { - true - }; - f(self); - self.lctx.is_in_trait_impl = old; - } - } - - impl<'tcx, 'interner> Visitor<'tcx> for ItemLowerer<'tcx, 'interner> { - fn visit_mod(&mut self, m: &'tcx Mod, _s: Span, _attrs: &[Attribute], n: NodeId) { - self.lctx.modules.insert(n, hir::ModuleItems { - items: BTreeSet::new(), - trait_items: BTreeSet::new(), - impl_items: BTreeSet::new(), - }); - - let old = self.lctx.current_module; - self.lctx.current_module = n; - visit::walk_mod(self, m); - self.lctx.current_module = old; - } - - fn visit_item(&mut self, item: &'tcx Item) { - let mut item_hir_id = None; - self.lctx.with_hir_id_owner(item.id, |lctx| { - if let Some(hir_item) = lctx.lower_item(item) { - item_hir_id = Some(hir_item.hir_id); - lctx.insert_item(hir_item); - } - }); - - if let Some(hir_id) = item_hir_id { - self.lctx.with_parent_item_lifetime_defs(hir_id, |this| { - let this = &mut ItemLowerer { lctx: this }; - if let ItemKind::Impl(.., ref opt_trait_ref, _, _) = item.node { - this.with_trait_impl_ref(opt_trait_ref, |this| { - visit::walk_item(this, item) - }); - } else { - visit::walk_item(this, item); - } - }); - } - } - - fn visit_trait_item(&mut self, item: &'tcx TraitItem) { - self.lctx.with_hir_id_owner(item.id, |lctx| { - let hir_item = lctx.lower_trait_item(item); - let id = hir::TraitItemId { hir_id: hir_item.hir_id }; - lctx.trait_items.insert(id, hir_item); - lctx.modules.get_mut(&lctx.current_module).unwrap().trait_items.insert(id); - }); - - visit::walk_trait_item(self, item); - } - - fn visit_impl_item(&mut self, item: &'tcx ImplItem) { - self.lctx.with_hir_id_owner(item.id, |lctx| { - let hir_item = lctx.lower_impl_item(item); - let id = hir::ImplItemId { hir_id: hir_item.hir_id }; - lctx.impl_items.insert(id, hir_item); - lctx.modules.get_mut(&lctx.current_module).unwrap().impl_items.insert(id); - }); - visit::walk_impl_item(self, item); - } - } - self.lower_node_id(CRATE_NODE_ID); debug_assert!(self.node_id_to_hir_id[CRATE_NODE_ID] == hir::CRATE_HIR_ID); visit::walk_crate(&mut MiscCollector { lctx: &mut self, hir_id_owner: None }, c); - visit::walk_crate(&mut ItemLowerer { lctx: &mut self }, c); + visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c); let module = self.lower_mod(&c.module); let attrs = self.lower_attrs(&c.attrs); @@ -790,57 +665,6 @@ impl<'a> LoweringContext<'a> { }) } - fn generator_movability_for_fn( - &mut self, - decl: &ast::FnDecl, - fn_decl_span: Span, - generator_kind: Option, - movability: Movability, - ) -> Option { - match generator_kind { - Some(hir::GeneratorKind::Gen) => { - if !decl.inputs.is_empty() { - span_err!( - self.sess, - fn_decl_span, - E0628, - "generators cannot have explicit arguments" - ); - self.sess.abort_if_errors(); - } - Some(match movability { - Movability::Movable => hir::GeneratorMovability::Movable, - Movability::Static => hir::GeneratorMovability::Static, - }) - }, - Some(hir::GeneratorKind::Async) => { - bug!("non-`async` closure body turned `async` during lowering"); - }, - None => { - if movability == Movability::Static { - span_err!( - self.sess, - fn_decl_span, - E0697, - "closures cannot be static" - ); - } - None - }, - } - } - - fn record_body(&mut self, arguments: HirVec, value: hir::Expr) -> hir::BodyId { - let body = hir::Body { - generator_kind: self.generator_kind, - arguments, - value, - }; - let id = body.id(); - self.bodies.insert(id, body); - id - } - fn next_id(&mut self) -> hir::HirId { self.lower_node_id(self.sess.next_node_id()) } @@ -848,7 +672,7 @@ impl<'a> LoweringContext<'a> { fn lower_res(&mut self, res: Res) -> Res { res.map_id(|id| { self.lower_node_id_generic(id, |_| { - panic!("expected node_id to be lowered already for res {:#?}", res) + panic!("expected `NodeId` to be lowered already for res {:#?}", res); }) }) } @@ -878,10 +702,9 @@ impl<'a> LoweringContext<'a> { span: Span, allow_internal_unstable: Option>, ) -> Span { - span.fresh_expansion(ExpnId::root(), ExpnInfo { - def_site: span, + span.fresh_expansion(ExpnData { allow_internal_unstable, - ..ExpnInfo::default(ExpnKind::Desugaring(reason), span, self.sess.edition()) + ..ExpnData::default(ExpnKind::Desugaring(reason), span, self.sess.edition()) }) } @@ -890,10 +713,16 @@ impl<'a> LoweringContext<'a> { anonymous_lifetime_mode: AnonymousLifetimeMode, op: impl FnOnce(&mut Self) -> R, ) -> R { + debug!( + "with_anonymous_lifetime_mode(anonymous_lifetime_mode={:?})", + anonymous_lifetime_mode, + ); let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode; self.anonymous_lifetime_mode = anonymous_lifetime_mode; let result = op(self); self.anonymous_lifetime_mode = old_anonymous_lifetime_mode; + debug!("with_anonymous_lifetime_mode: restoring anonymous_lifetime_mode={:?}", + old_anonymous_lifetime_mode); result } @@ -904,7 +733,7 @@ impl<'a> LoweringContext<'a> { /// /// Presuming that in-band lifetimes are enabled, then /// `self.anonymous_lifetime_mode` will be updated to match the - /// argument while `f` is running (and restored afterwards). + /// parameter while `f` is running (and restored afterwards). fn collect_in_band_defs( &mut self, parent_id: DefId, @@ -999,7 +828,7 @@ impl<'a> LoweringContext<'a> { return; } - if self.in_scope_lifetimes.contains(&ident.modern()) { + if self.in_scope_lifetimes.contains(&ParamName::Plain(ident.modern())) { return; } @@ -1017,7 +846,7 @@ impl<'a> LoweringContext<'a> { /// header, we convert it to an in-band lifetime. fn collect_fresh_in_band_lifetime(&mut self, span: Span) -> ParamName { assert!(self.is_collecting_in_band_lifetimes); - let index = self.lifetimes_to_define.len(); + let index = self.lifetimes_to_define.len() + self.in_scope_lifetimes.len(); let hir_name = ParamName::Fresh(index); self.lifetimes_to_define.push((span, hir_name)); hir_name @@ -1033,39 +862,7 @@ impl<'a> LoweringContext<'a> { { let old_len = self.in_scope_lifetimes.len(); let lt_def_names = params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => Some(param.ident.modern()), - _ => None, - }); - self.in_scope_lifetimes.extend(lt_def_names); - - let res = f(self); - - self.in_scope_lifetimes.truncate(old_len); - res - } - - // Same as the method above, but accepts `hir::GenericParam`s - // instead of `ast::GenericParam`s. - // This should only be used with generics that have already had their - // in-band lifetimes added. In practice, this means that this function is - // only used when lowering a child item of a trait or impl. - fn with_parent_item_lifetime_defs(&mut self, - parent_hir_id: hir::HirId, - f: F - ) -> T where - F: FnOnce(&mut LoweringContext<'_>) -> T, - { - let old_len = self.in_scope_lifetimes.len(); - - let parent_generics = match self.items.get(&parent_hir_id).unwrap().node { - hir::ItemKind::Impl(_, _, _, ref generics, ..) - | hir::ItemKind::Trait(_, _, ref generics, ..) => { - &generics.params[..] - } - _ => &[], - }; - let lt_def_names = parent_generics.iter().filter_map(|param| match param.kind { - hir::GenericParamKind::Lifetime { .. } => Some(param.name.ident().modern()), + GenericParamKind::Lifetime { .. } => Some(ParamName::Plain(param.ident.modern())), _ => None, }); self.in_scope_lifetimes.extend(lt_def_names); @@ -1081,7 +878,7 @@ impl<'a> LoweringContext<'a> { /// /// Presuming that in-band lifetimes are enabled, then /// `self.anonymous_lifetime_mode` will be updated to match the - /// argument while `f` is running (and restored afterwards). + /// parameter while `f` is running (and restored afterwards). fn add_in_band_defs( &mut self, generics: &Generics, @@ -1137,131 +934,6 @@ impl<'a> LoweringContext<'a> { (lowered_generics, res) } - fn with_catch_scope(&mut self, catch_id: NodeId, f: F) -> T - where - F: FnOnce(&mut LoweringContext<'_>) -> T, - { - let len = self.catch_scopes.len(); - self.catch_scopes.push(catch_id); - - let result = f(self); - assert_eq!( - len + 1, - self.catch_scopes.len(), - "catch scopes should be added and removed in stack order" - ); - - self.catch_scopes.pop().unwrap(); - - result - } - - fn make_async_expr( - &mut self, - capture_clause: CaptureBy, - closure_node_id: NodeId, - ret_ty: Option>, - span: Span, - body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr, - ) -> hir::ExprKind { - let capture_clause = self.lower_capture_clause(capture_clause); - let output = match ret_ty { - Some(ty) => FunctionRetTy::Ty(ty), - None => FunctionRetTy::Default(span), - }; - let ast_decl = FnDecl { - inputs: vec![], - output, - c_variadic: false - }; - let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None); - let body_id = self.lower_fn_body(&ast_decl, |this| { - this.generator_kind = Some(hir::GeneratorKind::Async); - body(this) - }); - let generator = hir::Expr { - hir_id: self.lower_node_id(closure_node_id), - node: hir::ExprKind::Closure(capture_clause, decl, body_id, span, - Some(hir::GeneratorMovability::Static)), - span, - attrs: ThinVec::new(), - }; - - let unstable_span = self.mark_span_with_reason( - DesugaringKind::Async, - span, - self.allow_gen_future.clone(), - ); - let gen_future = self.expr_std_path( - unstable_span, &[sym::future, sym::from_generator], None, ThinVec::new()); - hir::ExprKind::Call(P(gen_future), hir_vec![generator]) - } - - fn lower_body( - &mut self, - f: impl FnOnce(&mut LoweringContext<'_>) -> (HirVec, hir::Expr), - ) -> hir::BodyId { - let prev_gen_kind = self.generator_kind.take(); - let (arguments, result) = f(self); - let body_id = self.record_body(arguments, result); - self.generator_kind = prev_gen_kind; - body_id - } - - fn lower_fn_body( - &mut self, - decl: &FnDecl, - body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr, - ) -> hir::BodyId { - self.lower_body(|this| ( - decl.inputs.iter().map(|x| this.lower_arg(x)).collect(), - body(this), - )) - } - - fn lower_const_body(&mut self, expr: &Expr) -> hir::BodyId { - self.lower_body(|this| (hir_vec![], this.lower_expr(expr))) - } - - fn with_loop_scope(&mut self, loop_id: NodeId, f: F) -> T - where - F: FnOnce(&mut LoweringContext<'_>) -> T, - { - // We're no longer in the base loop's condition; we're in another loop. - let was_in_loop_condition = self.is_in_loop_condition; - self.is_in_loop_condition = false; - - let len = self.loop_scopes.len(); - self.loop_scopes.push(loop_id); - - let result = f(self); - assert_eq!( - len + 1, - self.loop_scopes.len(), - "loop scopes should be added and removed in stack order" - ); - - self.loop_scopes.pop().unwrap(); - - self.is_in_loop_condition = was_in_loop_condition; - - result - } - - fn with_loop_condition_scope(&mut self, f: F) -> T - where - F: FnOnce(&mut LoweringContext<'_>) -> T, - { - let was_in_loop_condition = self.is_in_loop_condition; - self.is_in_loop_condition = true; - - let result = f(self); - - self.is_in_loop_condition = was_in_loop_condition; - - result - } - fn with_dyn_type_scope(&mut self, in_scope: bool, f: F) -> T where F: FnOnce(&mut LoweringContext<'_>) -> T, @@ -1302,36 +974,6 @@ impl<'a> LoweringContext<'a> { } } - fn lower_label(&mut self, label: Option, D}` + /// An enum definition, e.g., `enum Foo {C, D}`. Enum(EnumDef, Generics), - /// A struct definition, e.g., `struct Foo {x: A}` + /// A struct definition, e.g., `struct Foo {x: A}`. Struct(VariantData, Generics), - /// A union definition, e.g., `union Foo {x: A, y: B}` + /// A union definition, e.g., `union Foo {x: A, y: B}`. Union(VariantData, Generics), - /// A trait definition + /// A trait definition. Trait(IsAuto, Unsafety, Generics, GenericBounds, HirVec), - /// A trait alias + /// A trait alias. TraitAlias(Generics, GenericBounds), - /// An implementation, eg `impl Trait for Foo { .. }` + /// An implementation, e.g., `impl Trait for Foo { .. }`. Impl(Unsafety, ImplPolarity, Defaultness, @@ -2536,7 +2620,7 @@ pub struct ForeignItem { #[stable_hasher(project(name))] pub ident: Ident, pub attrs: HirVec, - pub node: ForeignItemKind, + pub kind: ForeignItemKind, pub hir_id: HirId, pub span: Span, pub vis: Visibility, @@ -2609,6 +2693,11 @@ pub struct CodegenFnAttrs { /// probably isn't set when this is set, this is for foreign items while /// `#[export_name]` is for Rust-defined functions. pub link_name: Option, + /// The `#[link_ordinal = "..."]` attribute, indicating an ordinal an + /// imported function has in the dynamic library. Note that this must not + /// be set when `link_name` is set. This is for foreign items with the + /// "raw-dylib" kind. + pub link_ordinal: Option, /// The `#[target_feature(enable = "...")]` attribute and the enabled /// features (only enabled features are supported right now). pub target_features: Vec, @@ -2656,7 +2745,9 @@ bitflags! { const USED = 1 << 9; /// #[ffi_returns_twice], indicates that an extern function can return /// multiple times - const FFI_RETURNS_TWICE = 1 << 10; + const FFI_RETURNS_TWICE = 1 << 10; + /// #[track_caller]: allow access to the caller location + const TRACK_CALLER = 1 << 11; } } @@ -2668,6 +2759,7 @@ impl CodegenFnAttrs { optimize: OptimizeAttr::None, export_name: None, link_name: None, + link_ordinal: None, target_features: vec![], linkage: None, link_section: None, @@ -2703,7 +2795,7 @@ impl CodegenFnAttrs { #[derive(Copy, Clone, Debug)] pub enum Node<'hir> { - Arg(&'hir Arg), + Param(&'hir Param), Item(&'hir Item), ForeignItem(&'hir ForeignItem), TraitItem(&'hir TraitItem), @@ -2733,3 +2825,15 @@ pub enum Node<'hir> { Crate, } + +impl Node<'_> { + pub fn ident(&self) -> Option { + match self { + Node::TraitItem(TraitItem { ident, .. }) | + Node::ImplItem(ImplItem { ident, .. }) | + Node::ForeignItem(ForeignItem { ident, .. }) | + Node::Item(Item { ident, .. }) => Some(*ident), + _ => None, + } + } +} diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index 0d2c7d393bb89..feb0d97822c42 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -45,7 +45,7 @@ impl EnumerateAndAdjustIterator for T { impl hir::Pat { pub fn is_refutable(&self) -> bool { - match self.node { + match self.kind { PatKind::Lit(_) | PatKind::Range(..) | PatKind::Path(hir::QPath::Resolved(Some(..), _)) | @@ -66,50 +66,70 @@ impl hir::Pat { /// Call `f` on every "binding" in a pattern, e.g., on `a` in /// `match foo() { Some(a) => (), None => () }` - pub fn each_binding(&self, mut f: F) - where F: FnMut(hir::BindingAnnotation, HirId, Span, ast::Ident), - { + pub fn each_binding(&self, mut f: impl FnMut(hir::BindingAnnotation, HirId, Span, ast::Ident)) { self.walk(|p| { - if let PatKind::Binding(binding_mode, _, ident, _) = p.node { + if let PatKind::Binding(binding_mode, _, ident, _) = p.kind { f(binding_mode, p.hir_id, p.span, ident); } true }); } + /// Call `f` on every "binding" in a pattern, e.g., on `a` in + /// `match foo() { Some(a) => (), None => () }`. + /// + /// When encountering an or-pattern `p_0 | ... | p_n` only `p_0` will be visited. + pub fn each_binding_or_first( + &self, + f: &mut impl FnMut(hir::BindingAnnotation, HirId, Span, ast::Ident), + ) { + self.walk(|p| match &p.kind { + PatKind::Or(ps) => { + ps[0].each_binding_or_first(f); + false + }, + PatKind::Binding(bm, _, ident, _) => { + f(*bm, p.hir_id, p.span, *ident); + true + } + _ => true, + }) + } + /// Checks if the pattern contains any patterns that bind something to /// an ident, e.g., `foo`, or `Foo(foo)` or `foo @ Bar(..)`. pub fn contains_bindings(&self) -> bool { - let mut contains_bindings = false; - self.walk(|p| { - if let PatKind::Binding(..) = p.node { - contains_bindings = true; - false // there's at least one binding, can short circuit now. - } else { - true - } - }); - contains_bindings + self.satisfies(|p| match p.kind { + PatKind::Binding(..) => true, + _ => false, + }) } /// Checks if the pattern contains any patterns that bind something to /// an ident or wildcard, e.g., `foo`, or `Foo(_)`, `foo @ Bar(..)`, pub fn contains_bindings_or_wild(&self) -> bool { - let mut contains_bindings = false; - self.walk(|p| { - match p.node { - PatKind::Binding(..) | PatKind::Wild => { - contains_bindings = true; - false // there's at least one binding/wildcard, can short circuit now. - } - _ => true + self.satisfies(|p| match p.kind { + PatKind::Binding(..) | PatKind::Wild => true, + _ => false, + }) + } + + /// Checks if the pattern satisfies the given predicate on some sub-pattern. + fn satisfies(&self, pred: impl Fn(&Self) -> bool) -> bool { + let mut satisfies = false; + self.walk_short(|p| { + if pred(p) { + satisfies = true; + false // Found one, can short circuit now. + } else { + true } }); - contains_bindings + satisfies } pub fn simple_ident(&self) -> Option { - match self.node { + match self.kind { PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, None) | PatKind::Binding(hir::BindingAnnotation::Mutable, _, ident, None) => Some(ident), _ => None, @@ -119,20 +139,20 @@ impl hir::Pat { /// Returns variants that are necessary to exist for the pattern to match. pub fn necessary_variants(&self) -> Vec { let mut variants = vec![]; - self.walk(|p| { - match p.node { - PatKind::Path(hir::QPath::Resolved(_, ref path)) | - PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) | - PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => { - match path.res { - Res::Def(DefKind::Variant, id) => variants.push(id), - Res::Def(DefKind::Ctor(CtorOf::Variant, ..), id) => variants.push(id), - _ => () - } + self.walk(|p| match &p.kind { + PatKind::Or(_) => false, + PatKind::Path(hir::QPath::Resolved(_, path)) | + PatKind::TupleStruct(hir::QPath::Resolved(_, path), ..) | + PatKind::Struct(hir::QPath::Resolved(_, path), ..) => { + if let Res::Def(DefKind::Variant, id) + | Res::Def(DefKind::Ctor(CtorOf::Variant, ..), id) + = path.res + { + variants.push(id); } - _ => () + true } - true + _ => true, }); variants.sort(); variants.dedup(); @@ -148,33 +168,14 @@ impl hir::Pat { let mut result = None; self.each_binding(|annotation, _, _, _| { match annotation { - hir::BindingAnnotation::Ref => { - match result { - None | Some(hir::MutImmutable) => result = Some(hir::MutImmutable), - _ => (), - } + hir::BindingAnnotation::Ref => match result { + None | Some(hir::MutImmutable) => result = Some(hir::MutImmutable), + _ => {} } hir::BindingAnnotation::RefMut => result = Some(hir::MutMutable), - _ => (), + _ => {} } }); result } } - -impl hir::Arm { - /// Checks if the patterns for this arm contain any `ref` or `ref mut` - /// bindings, and if yes whether its containing mutable ones or just immutables ones. - pub fn contains_explicit_ref_binding(&self) -> Option { - // FIXME(tschottdorf): contains_explicit_ref_binding() must be removed - // for #42640 (default match binding modes). - // - // See #44848. - self.pats.iter() - .filter_map(|pat| pat.contains_explicit_ref_binding()) - .max_by_key(|m| match *m { - hir::MutMutable => 1, - hir::MutImmutable => 0, - }) - } -} diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 11ba512053084..6cffaa8a494c4 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -33,7 +33,7 @@ pub enum Nested { TraitItem(hir::TraitItemId), ImplItem(hir::ImplItemId), Body(hir::BodyId), - BodyArgPat(hir::BodyId, usize) + BodyParamPat(hir::BodyId, usize) } pub trait PpAnn { @@ -62,7 +62,7 @@ impl PpAnn for hir::Crate { Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)), Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)), Nested::Body(id) => state.print_expr(&self.body(id).value), - Nested::BodyArgPat(id, i) => state.print_pat(&self.body(id).arguments[i].pat) + Nested::BodyParamPat(id, i) => state.print_pat(&self.body(id).params[i].pat) } } } @@ -286,7 +286,7 @@ impl<'a> State<'a> { pub fn print_type(&mut self, ty: &hir::Ty) { self.maybe_print_comment(ty.span.lo()); self.ibox(0); - match ty.node { + match ty.kind { hir::TyKind::Slice(ref ty) => { self.s.word("["); self.print_type(&ty); @@ -318,7 +318,7 @@ impl<'a> State<'a> { } hir::TyKind::BareFn(ref f) => { self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &f.generic_params, - &f.arg_names[..]); + &f.param_names[..]); } hir::TyKind::Def(..) => {}, hir::TyKind::Path(ref qpath) => { @@ -361,9 +361,6 @@ impl<'a> State<'a> { self.s.word("/*ERROR*/"); self.pclose(); } - hir::TyKind::CVarArgs(_) => { - self.s.word("..."); - } } self.end() } @@ -372,7 +369,7 @@ impl<'a> State<'a> { self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); self.print_outer_attributes(&item.attrs); - match item.node { + match item.kind { hir::ForeignItemKind::Fn(ref decl, ref arg_names, ref generics) => { self.head(""); self.print_fn(decl, @@ -474,7 +471,7 @@ impl<'a> State<'a> { self.maybe_print_comment(item.span.lo()); self.print_outer_attributes(&item.attrs); self.ann.pre(self, AnnNode::Item(item)); - match item.node { + match item.kind { hir::ItemKind::ExternCrate(orig_name) => { self.head(visibility_qualified(&item.vis, "extern crate")); if let Some(orig_name) = orig_name { @@ -737,7 +734,7 @@ impl<'a> State<'a> { for v in variants { self.space_if_not_bol(); self.maybe_print_comment(v.span.lo()); - self.print_outer_attributes(&v.node.attrs); + self.print_outer_attributes(&v.attrs); self.ibox(INDENT_UNIT); self.print_variant(v); self.s.word(","); @@ -829,8 +826,8 @@ impl<'a> State<'a> { pub fn print_variant(&mut self, v: &hir::Variant) { self.head(""); let generics = hir::Generics::empty(); - self.print_struct(&v.node.data, &generics, v.node.ident.name, v.span, false); - if let Some(ref d) = v.node.disr_expr { + self.print_struct(&v.data, &generics, v.ident.name, v.span, false); + if let Some(ref d) = v.disr_expr { self.s.space(); self.word_space("="); self.print_anon_const(d); @@ -858,7 +855,7 @@ impl<'a> State<'a> { self.hardbreak_if_not_bol(); self.maybe_print_comment(ti.span.lo()); self.print_outer_attributes(&ti.attrs); - match ti.node { + match ti.kind { hir::TraitItemKind::Const(ref ty, default) => { let vis = Spanned { span: syntax_pos::DUMMY_SP, node: hir::VisibilityKind::Inherited }; @@ -896,7 +893,7 @@ impl<'a> State<'a> { self.print_outer_attributes(&ii.attrs); self.print_defaultness(ii.defaultness); - match ii.node { + match ii.kind { hir::ImplItemKind::Const(ref ty, expr) => { self.print_associated_const(ii.ident, &ty, Some(expr), &ii.vis); } @@ -944,7 +941,7 @@ impl<'a> State<'a> { pub fn print_stmt(&mut self, st: &hir::Stmt) { self.maybe_print_comment(st.span.lo()); - match st.node { + match st.kind { hir::StmtKind::Local(ref loc) => { self.print_local(loc.init.as_deref(), |this| this.print_local_decl(&loc)); } @@ -961,7 +958,7 @@ impl<'a> State<'a> { self.s.word(";"); } } - if stmt_ends_with_semi(&st.node) { + if stmt_ends_with_semi(&st.kind) { self.s.word(";"); } self.maybe_print_trailing_comment(st.span, None) @@ -1035,7 +1032,7 @@ impl<'a> State<'a> { /// Print an expr using syntax that's acceptable in a condition position, such as the `cond` in /// `if cond { ... }`. pub fn print_expr_as_cond(&mut self, expr: &hir::Expr) { - let needs_par = match expr.node { + let needs_par = match expr.kind { // These cases need parens due to the parse error observed in #26461: `if return {}` // parses as the erroneous construct `if (return {})`, not `if (return) {}`. hir::ExprKind::Closure(..) | @@ -1119,11 +1116,10 @@ impl<'a> State<'a> { } fn print_expr_call(&mut self, func: &hir::Expr, args: &[hir::Expr]) { - let prec = - match func.node { - hir::ExprKind::Field(..) => parser::PREC_FORCE_PAREN, - _ => parser::PREC_POSTFIX, - }; + let prec = match func.kind { + hir::ExprKind::Field(..) => parser::PREC_FORCE_PAREN, + _ => parser::PREC_POSTFIX, + }; self.print_expr_maybe_paren(func, prec); self.print_call_post(args) @@ -1161,7 +1157,7 @@ impl<'a> State<'a> { Fixity::None => (prec + 1, prec + 1), }; - let left_prec = match (&lhs.node, op.node) { + let left_prec = match (&lhs.kind, op.node) { // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead // of `(x as i32) < ...`. We need to convince it _not_ to do that. @@ -1200,7 +1196,7 @@ impl<'a> State<'a> { self.print_outer_attributes(&expr.attrs); self.ibox(INDENT_UNIT); self.ann.pre(self, AnnNode::Expr(expr)); - match expr.node { + match expr.kind { hir::ExprKind::Box(ref expr) => { self.word_space("box"); self.print_expr_maybe_paren(expr, parser::PREC_PREFIX); @@ -1290,14 +1286,14 @@ impl<'a> State<'a> { hir::ExprKind::Closure(capture_clause, ref decl, body, _fn_decl_span, _gen) => { self.print_capture_clause(capture_clause); - self.print_closure_args(&decl, body); + self.print_closure_params(&decl, body); self.s.space(); - // this is a bare expression + // This is a bare expression. self.ann.nested(self, Nested::Body(body)); self.end(); // need to close a box - // a box will be closed by print_expr, but we didn't want an overall + // A box will be closed by `print_expr`, but we didn't want an overall // wrapper so we closed the corresponding opening. so create an // empty box to satisfy the close. self.ibox(0); @@ -1307,9 +1303,9 @@ impl<'a> State<'a> { self.print_ident(label.ident); self.word_space(":"); } - // containing cbox, will be closed by print-block at } + // containing cbox, will be closed by print-block at `}` self.cbox(INDENT_UNIT); - // head-box, will be closed by print-block after { + // head-box, will be closed by print-block after `{` self.ibox(0); self.print_block(&blk); } @@ -1457,7 +1453,7 @@ impl<'a> State<'a> { } pub fn print_name(&mut self, name: ast::Name) { - self.print_ident(ast::Ident::with_empty_ctxt(name)) + self.print_ident(ast::Ident::with_dummy_span(name)) } pub fn print_for_decl(&mut self, loc: &hir::Local, coll: &hir::Expr) { @@ -1618,7 +1614,7 @@ impl<'a> State<'a> { self.ann.pre(self, AnnNode::Pat(pat)); // Pat isn't normalized, but the beauty of it // is that it doesn't matter - match pat.node { + match pat.kind { PatKind::Wild => self.s.word("_"), PatKind::Binding(binding_mode, _, ident, ref sub) => { match binding_mode { @@ -1670,14 +1666,14 @@ impl<'a> State<'a> { &fields[..], |s, f| { s.cbox(INDENT_UNIT); - if !f.node.is_shorthand { - s.print_ident(f.node.ident); + if !f.is_shorthand { + s.print_ident(f.ident); s.word_nbsp(":"); } - s.print_pat(&f.node.pat); + s.print_pat(&f.pat); s.end() }, - |f| f.node.pat.span); + |f| f.pat.span); if etc { if !fields.is_empty() { self.word_space(","); @@ -1687,6 +1683,9 @@ impl<'a> State<'a> { self.s.space(); self.s.word("}"); } + PatKind::Or(ref pats) => { + self.strsep("|", true, Inconsistent, &pats[..], |s, p| s.print_pat(&p)); + } PatKind::Tuple(ref elts, ddpos) => { self.popen(); if let Some(ddpos) = ddpos { @@ -1708,7 +1707,7 @@ impl<'a> State<'a> { self.pclose(); } PatKind::Box(ref inner) => { - let is_range_inner = match inner.node { + let is_range_inner = match inner.kind { PatKind::Range(..) => true, _ => false, }; @@ -1722,7 +1721,7 @@ impl<'a> State<'a> { } } PatKind::Ref(ref inner, mutbl) => { - let is_range_inner = match inner.node { + let is_range_inner = match inner.kind { PatKind::Range(..) => true, _ => false, }; @@ -1755,8 +1754,8 @@ impl<'a> State<'a> { if !before.is_empty() { self.word_space(","); } - if let PatKind::Wild = p.node { - // Print nothing + if let PatKind::Wild = p.kind { + // Print nothing. } else { self.print_pat(&p); } @@ -1772,7 +1771,7 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Pat(pat)) } - pub fn print_arg(&mut self, arg: &hir::Arg) { + pub fn print_param(&mut self, arg: &hir::Param) { self.print_outer_attributes(&arg.attrs); self.print_pat(&arg.pat); } @@ -1787,16 +1786,7 @@ impl<'a> State<'a> { self.ann.pre(self, AnnNode::Arm(arm)); self.ibox(0); self.print_outer_attributes(&arm.attrs); - let mut first = true; - for p in &arm.pats { - if first { - first = false; - } else { - self.s.space(); - self.word_space("|"); - } - self.print_pat(&p); - } + self.print_pat(&arm.pat); self.s.space(); if let Some(ref g) = arm.guard { match g { @@ -1809,7 +1799,7 @@ impl<'a> State<'a> { } self.word_space("=>"); - match arm.body.node { + match arm.body.kind { hir::ExprKind::Block(ref blk, opt_label) => { if let Some(label) = opt_label { self.print_ident(label.ident); @@ -1861,7 +1851,7 @@ impl<'a> State<'a> { s.s.word(":"); s.s.space(); } else if let Some(body_id) = body_id { - s.ann.nested(s, Nested::BodyArgPat(body_id, i)); + s.ann.nested(s, Nested::BodyParamPat(body_id, i)); s.s.word(":"); s.s.space(); } @@ -1878,17 +1868,17 @@ impl<'a> State<'a> { self.print_where_clause(&generics.where_clause) } - fn print_closure_args(&mut self, decl: &hir::FnDecl, body_id: hir::BodyId) { + fn print_closure_params(&mut self, decl: &hir::FnDecl, body_id: hir::BodyId) { self.s.word("|"); let mut i = 0; self.commasep(Inconsistent, &decl.inputs, |s, ty| { s.ibox(INDENT_UNIT); - s.ann.nested(s, Nested::BodyArgPat(body_id, i)); + s.ann.nested(s, Nested::BodyParamPat(body_id, i)); i += 1; - if let hir::TyKind::Infer = ty.node { - // Print nothing + if let hir::TyKind::Infer = ty.kind { + // Print nothing. } else { s.s.word(":"); s.s.space(); @@ -2218,7 +2208,6 @@ impl<'a> State<'a> { } } -// Dup'ed from parse::classify, but adapted for the HIR. /// Does this expression require a semicolon to be treated /// as a statement? The negation of this: 'can this expression /// be used as a statement without a semicolon' -- is used @@ -2226,8 +2215,10 @@ impl<'a> State<'a> { /// if true {...} else {...} /// |x| 5 /// isn't parsed as (if true {...} else {...} | x) | 5 +// +// Duplicated from `parse::classify`, but adapted for the HIR. fn expr_requires_semi_to_be_stmt(e: &hir::Expr) -> bool { - match e.node { + match e.kind { hir::ExprKind::Match(..) | hir::ExprKind::Block(..) | hir::ExprKind::Loop(..) => false, @@ -2235,7 +2226,7 @@ fn expr_requires_semi_to_be_stmt(e: &hir::Expr) -> bool { } } -/// this statement requires a semicolon after it. +/// This statement requires a semicolon after it. /// note that in one case (stmt_semi), we've already /// seen the semicolon, and thus don't need another. fn stmt_ends_with_semi(stmt: &hir::StmtKind) -> bool { @@ -2274,17 +2265,17 @@ fn bin_op_to_assoc_op(op: hir::BinOpKind) -> AssocOp { } } -/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any +/// Expressions that syntactically contain an "exterior" struct literal, i.e., not surrounded by any /// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and /// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not. fn contains_exterior_struct_lit(value: &hir::Expr) -> bool { - match value.node { + match value.kind { hir::ExprKind::Struct(..) => true, hir::ExprKind::Assign(ref lhs, ref rhs) | hir::ExprKind::AssignOp(_, ref lhs, ref rhs) | hir::ExprKind::Binary(_, ref lhs, ref rhs) => { - // X { y: 1 } + X { y: 2 } + // `X { y: 1 } + X { y: 2 }` contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs) } hir::ExprKind::Unary(_, ref x) | @@ -2292,12 +2283,12 @@ fn contains_exterior_struct_lit(value: &hir::Expr) -> bool { hir::ExprKind::Type(ref x, _) | hir::ExprKind::Field(ref x, _) | hir::ExprKind::Index(ref x, _) => { - // &X { y: 1 }, X { y: 1 }.y + // `&X { y: 1 }, X { y: 1 }.y` contains_exterior_struct_lit(&x) } hir::ExprKind::MethodCall(.., ref exprs) => { - // X { y: 1 }.bar(...) + // `X { y: 1 }.bar(...)` contains_exterior_struct_lit(&exprs[0]) } diff --git a/src/librustc/hir/ptr.rs b/src/librustc/hir/ptr.rs index 1976b4c9e54ff..8cdcf5202fcda 100644 --- a/src/librustc/hir/ptr.rs +++ b/src/librustc/hir/ptr.rs @@ -9,8 +9,7 @@ use std::{slice, vec}; use rustc_serialize::{Encodable, Decodable, Encoder, Decoder}; -use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, - HashStable}; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; /// An owned smart pointer. #[derive(Hash, PartialEq, Eq)] pub struct P { @@ -133,9 +132,7 @@ impl Decodable for P<[T]> { impl HashStable for P where T: ?Sized + HashStable { - fn hash_stable(&self, - hcx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { (**self).hash_stable(hcx, hasher); } } diff --git a/src/librustc/hir/upvars.rs b/src/librustc/hir/upvars.rs index cc532cb064ebe..5c5f7f6120082 100644 --- a/src/librustc/hir/upvars.rs +++ b/src/librustc/hir/upvars.rs @@ -47,7 +47,7 @@ impl Visitor<'tcx> for LocalCollector { } fn visit_pat(&mut self, pat: &'tcx hir::Pat) { - if let hir::PatKind::Binding(_, hir_id, ..) = pat.node { + if let hir::PatKind::Binding(_, hir_id, ..) = pat.kind { self.locals.insert(hir_id); } intravisit::walk_pat(self, pat); @@ -82,7 +82,7 @@ impl Visitor<'tcx> for CaptureCollector<'a, 'tcx> { } fn visit_expr(&mut self, expr: &'tcx hir::Expr) { - if let hir::ExprKind::Closure(..) = expr.node { + if let hir::ExprKind::Closure(..) = expr.kind { let closure_def_id = self.tcx.hir().local_def_id(expr.hir_id); if let Some(upvars) = self.tcx.upvars(closure_def_id) { // Every capture of a closure expression is a local in scope, diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index ae7d82c2020ac..3e6b271b83497 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -12,7 +12,6 @@ use std::hash as std_hash; use std::cell::RefCell; use syntax::ast; - use syntax::source_map::SourceMap; use syntax::ext::hygiene::SyntaxContext; use syntax::symbol::Symbol; @@ -20,9 +19,9 @@ use syntax::tokenstream::DelimSpan; use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::hygiene; -use rustc_data_structures::stable_hasher::{HashStable, - StableHasher, StableHasherResult, - ToStableHashKey}; +use rustc_data_structures::stable_hasher::{ + HashStable, StableHasher, ToStableHashKey, +}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use smallvec::SmallVec; @@ -32,9 +31,9 @@ fn compute_ignored_attr_names() -> FxHashSet { } /// This is the context state available during incr. comp. hashing. It contains -/// enough information to transform DefIds and HirIds into stable DefPaths (i.e. -/// a reference to the TyCtxt) and it holds a few caches for speeding up various -/// things (e.g., each DefId/DefPath is only hashed once). +/// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e., +/// a reference to the `TyCtxt`) and it holds a few caches for speeding up various +/// things (e.g., each `DefId`/`DefPath` is only hashed once). #[derive(Clone)] pub struct StableHashingContext<'a> { sess: &'a Session, @@ -46,7 +45,7 @@ pub struct StableHashingContext<'a> { node_id_hashing_mode: NodeIdHashingMode, // Very often, we are hashing something that does not need the - // CachingSourceMapView, so we initialize it lazily. + // `CachingSourceMapView`, so we initialize it lazily. raw_source_map: &'a SourceMap, caching_source_map: Option>, } @@ -57,24 +56,24 @@ pub enum NodeIdHashingMode { HashDefPath, } -/// The BodyResolver allows to map a BodyId to the corresponding hir::Body. -/// We could also just store a plain reference to the hir::Crate but we want +/// The `BodyResolver` allows mapping a `BodyId` to the corresponding `hir::Body`. +/// We could also just store a plain reference to the `hir::Crate` but we want /// to avoid that the crate is used to get untracked access to all of the HIR. #[derive(Clone, Copy)] struct BodyResolver<'tcx>(&'tcx hir::Crate); impl<'tcx> BodyResolver<'tcx> { - // Return a reference to the hir::Body with the given BodyId. - // DOES NOT DO ANY TRACKING, use carefully. + /// Returns a reference to the `hir::Body` with the given `BodyId`. + /// **Does not do any tracking**; use carefully. fn body(self, id: hir::BodyId) -> &'tcx hir::Body { self.0.body(id) } } impl<'a> StableHashingContext<'a> { - // The `krate` here is only used for mapping BodyIds to Bodies. - // Don't use it for anything else or you'll run the risk of - // leaking data out of the tracking system. + /// The `krate` here is only used for mapping `BodyId`s to `Body`s. + /// Don't use it for anything else or you'll run the risk of + /// leaking data out of the tracking system. #[inline] pub fn new(sess: &'a Session, krate: &'a hir::Crate, @@ -217,14 +216,10 @@ impl<'a> StableHashingContextProvider<'a> for StableHashingContext<'a> { } } -impl<'a> crate::dep_graph::DepGraphSafe for StableHashingContext<'a> { -} - +impl<'a> crate::dep_graph::DepGraphSafe for StableHashingContext<'a> {} impl<'a> HashStable> for hir::BodyId { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { if hcx.hash_bodies() { hcx.body_resolver.body(*self).hash_stable(hcx, hasher); } @@ -233,9 +228,7 @@ impl<'a> HashStable> for hir::BodyId { impl<'a> HashStable> for hir::HirId { #[inline] - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { match hcx.node_id_hashing_mode { NodeIdHashingMode::Ignore => { // Don't do anything. @@ -266,9 +259,7 @@ impl<'a> ToStableHashKey> for hir::HirId { } impl<'a> HashStable> for ast::NodeId { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { match hcx.node_id_hashing_mode { NodeIdHashingMode::Ignore => { // Don't do anything. @@ -292,19 +283,16 @@ impl<'a> ToStableHashKey> for ast::NodeId { } impl<'a> HashStable> for Span { - - // Hash a span in a stable way. We can't directly hash the span's BytePos - // fields (that would be similar to hashing pointers, since those are just - // offsets into the SourceMap). Instead, we hash the (file name, line, column) - // triple, which stays the same even if the containing SourceFile has moved - // within the SourceMap. - // Also note that we are hashing byte offsets for the column, not unicode - // codepoint offsets. For the purpose of the hash that's sufficient. - // Also, hashing filenames is expensive so we avoid doing it twice when the - // span starts and ends in the same file, which is almost always the case. - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + /// Hashes a span in a stable way. We can't directly hash the span's `BytePos` + /// fields (that would be similar to hashing pointers, since those are just + /// offsets into the `SourceMap`). Instead, we hash the (file name, line, column) + /// triple, which stays the same even if the containing `SourceFile` has moved + /// within the `SourceMap`. + /// Also note that we are hashing byte offsets for the column, not unicode + /// codepoint offsets. For the purpose of the hash that's sufficient. + /// Also, hashing filenames is expensive so we avoid doing it twice when the + /// span starts and ends in the same file, which is almost always the case. + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { const TAG_VALID_SPAN: u8 = 0; const TAG_INVALID_SPAN: u8 = 1; const TAG_EXPANSION: u8 = 0; @@ -340,7 +328,7 @@ impl<'a> HashStable> for Span { } std_hash::Hash::hash(&TAG_VALID_SPAN, hasher); - // We truncate the stable_id hash and line and col numbers. The chances + // We truncate the stable ID hash and line and column numbers. The chances // of causing a collision this way should be minimal. std_hash::Hash::hash(&(file_lo.name_hash as u64), hasher); @@ -350,7 +338,7 @@ impl<'a> HashStable> for Span { let line_col_len = col | line | len; std_hash::Hash::hash(&line_col_len, hasher); - if span.ctxt == SyntaxContext::empty() { + if span.ctxt == SyntaxContext::root() { TAG_NO_EXPANSION.hash_stable(hcx, hasher); } else { TAG_EXPANSION.hash_stable(hcx, hasher); @@ -370,7 +358,7 @@ impl<'a> HashStable> for Span { } let mut hasher = StableHasher::new(); - expn_id.expn_info().hash_stable(hcx, &mut hasher); + expn_id.expn_data().hash_stable(hcx, &mut hasher); let sub_hash: Fingerprint = hasher.finish(); let sub_hash = sub_hash.to_smaller_hash(); cache.borrow_mut().insert(expn_id, sub_hash); @@ -383,24 +371,18 @@ impl<'a> HashStable> for Span { } impl<'a> HashStable> for DelimSpan { - fn hash_stable( - &self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher, - ) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.open.hash_stable(hcx, hasher); self.close.hash_stable(hcx, hasher); } } -pub fn hash_stable_trait_impls<'a, W>( +pub fn hash_stable_trait_impls<'a>( hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher, + hasher: &mut StableHasher, blanket_impls: &[DefId], non_blanket_impls: &FxHashMap>, -) where - W: StableHasherResult, -{ +) { { let mut blanket_impls: SmallVec<[_; 8]> = blanket_impls .iter() diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 30d76f240d1fa..c0255e5b8a481 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -5,8 +5,8 @@ use crate::hir; use crate::hir::map::DefPathHash; use crate::hir::def_id::{DefId, LocalDefId, CrateNum, CRATE_DEF_INDEX}; use crate::ich::{StableHashingContext, NodeIdHashingMode, Fingerprint}; -use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, - StableHasher, StableHasherResult}; + +use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher}; use smallvec::SmallVec; use std::mem; use syntax::ast; @@ -14,9 +14,7 @@ use syntax::attr; impl<'a> HashStable> for DefId { #[inline] - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.def_path_hash(*self).hash_stable(hcx, hasher); } } @@ -32,9 +30,7 @@ impl<'a> ToStableHashKey> for DefId { impl<'a> HashStable> for LocalDefId { #[inline] - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.def_path_hash(self.to_def_id()).hash_stable(hcx, hasher); } } @@ -50,9 +46,7 @@ impl<'a> ToStableHashKey> for LocalDefId { impl<'a> HashStable> for CrateNum { #[inline] - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.def_path_hash(DefId { krate: *self, index: CRATE_DEF_INDEX @@ -82,17 +76,15 @@ for hir::ItemLocalId { } } -// The following implementations of HashStable for ItemId, TraitItemId, and -// ImplItemId deserve special attention. Normally we do not hash NodeIds within -// the HIR, since they just signify a HIR nodes own path. But ItemId et al +// The following implementations of HashStable for `ItemId`, `TraitItemId`, and +// `ImplItemId` deserve special attention. Normally we do not hash `NodeId`s within +// the HIR, since they just signify a HIR nodes own path. But `ItemId` et al // are used when another item in the HIR is *referenced* and we certainly // want to pick up on a reference changing its target, so we hash the NodeIds // in "DefPath Mode". impl<'a> HashStable> for hir::ItemId { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::ItemId { id } = *self; @@ -104,9 +96,7 @@ impl<'a> HashStable> for hir::ItemId { } impl<'a> HashStable> for hir::TraitItemId { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::TraitItemId { hir_id } = * self; @@ -118,9 +108,7 @@ impl<'a> HashStable> for hir::TraitItemId { } impl<'a> HashStable> for hir::ImplItemId { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::ImplItemId { hir_id } = * self; @@ -131,35 +119,30 @@ impl<'a> HashStable> for hir::ImplItemId { } } - impl_stable_hash_for!(struct ast::Label { ident }); impl<'a> HashStable> for hir::Ty { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.while_hashing_hir_bodies(true, |hcx| { let hir::Ty { hir_id: _, - ref node, + ref kind, ref span, } = *self; - node.hash_stable(hcx, hasher); + kind.hash_stable(hcx, hasher); span.hash_stable(hcx, hasher); }) } } -impl_stable_hash_for_spanned!(hir::FieldPat); - impl_stable_hash_for_spanned!(hir::BinOpKind); impl_stable_hash_for!(struct hir::Stmt { hir_id, - node, + kind, span, }); @@ -167,19 +150,17 @@ impl_stable_hash_for!(struct hir::Stmt { impl_stable_hash_for_spanned!(ast::Name); impl<'a> HashStable> for hir::Expr { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.while_hashing_hir_bodies(true, |hcx| { let hir::Expr { hir_id: _, ref span, - ref node, + ref kind, ref attrs } = *self; span.hash_stable(hcx, hasher); - node.hash_stable(hcx, hasher); + kind.hash_stable(hcx, hasher); attrs.hash_stable(hcx, hasher); }) } @@ -187,23 +168,19 @@ impl<'a> HashStable> for hir::Expr { impl_stable_hash_for_spanned!(usize); -impl_stable_hash_for_spanned!(ast::Ident); - impl_stable_hash_for!(struct ast::Ident { name, span, }); impl<'a> HashStable> for hir::TraitItem { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::TraitItem { hir_id: _, ident, ref attrs, ref generics, - ref node, + ref kind, span } = *self; @@ -211,7 +188,7 @@ impl<'a> HashStable> for hir::TraitItem { ident.name.hash_stable(hcx, hasher); attrs.hash_stable(hcx, hasher); generics.hash_stable(hcx, hasher); - node.hash_stable(hcx, hasher); + kind.hash_stable(hcx, hasher); span.hash_stable(hcx, hasher); }); } @@ -219,9 +196,7 @@ impl<'a> HashStable> for hir::TraitItem { impl<'a> HashStable> for hir::ImplItem { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::ImplItem { hir_id: _, ident, @@ -229,7 +204,7 @@ impl<'a> HashStable> for hir::ImplItem { defaultness, ref attrs, ref generics, - ref node, + ref kind, span } = *self; @@ -239,21 +214,19 @@ impl<'a> HashStable> for hir::ImplItem { defaultness.hash_stable(hcx, hasher); attrs.hash_stable(hcx, hasher); generics.hash_stable(hcx, hasher); - node.hash_stable(hcx, hasher); + kind.hash_stable(hcx, hasher); span.hash_stable(hcx, hasher); }); } } -impl_stable_hash_for!(enum ::syntax::ast::CrateSugar { +impl_stable_hash_for!(enum ast::CrateSugar { JustCrate, PubCrate, }); impl<'a> HashStable> for hir::VisibilityKind { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { hir::VisibilityKind::Public | @@ -276,9 +249,7 @@ impl<'a> HashStable> for hir::VisibilityKind { impl_stable_hash_for_spanned!(hir::VisibilityKind); impl<'a> HashStable> for hir::Mod { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::Mod { inner: ref inner_span, ref item_ids, @@ -304,18 +275,16 @@ impl<'a> HashStable> for hir::Mod { } } -impl_stable_hash_for_spanned!(hir::VariantKind); +impl_stable_hash_for_spanned!(hir::Variant); impl<'a> HashStable> for hir::Item { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::Item { ident, ref attrs, hir_id: _, - ref node, + ref kind, ref vis, span } = *self; @@ -323,7 +292,7 @@ impl<'a> HashStable> for hir::Item { hcx.hash_hir_item_like(|hcx| { ident.name.hash_stable(hcx, hasher); attrs.hash_stable(hcx, hasher); - node.hash_stable(hcx, hasher); + kind.hash_stable(hcx, hasher); vis.hash_stable(hcx, hasher); span.hash_stable(hcx, hasher); }); @@ -331,17 +300,15 @@ impl<'a> HashStable> for hir::Item { } impl<'a> HashStable> for hir::Body { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::Body { - arguments, + params, value, generator_kind, } = self; hcx.with_node_id_hashing_mode(NodeIdHashingMode::Ignore, |hcx| { - arguments.hash_stable(hcx, hasher); + params.hash_stable(hcx, hasher); value.hash_stable(hcx, hasher); generator_kind.hash_stable(hcx, hasher); }); @@ -362,15 +329,12 @@ impl<'a> ToStableHashKey> for hir::BodyId { impl<'a> HashStable> for hir::def_id::DefIndex { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.local_def_path_hash(*self).hash_stable(hcx, hasher); } } -impl<'a> ToStableHashKey> -for hir::def_id::DefIndex { +impl<'a> ToStableHashKey> for hir::def_id::DefIndex { type KeyType = DefPathHash; #[inline] @@ -380,17 +344,13 @@ for hir::def_id::DefIndex { } impl<'a> HashStable> for crate::middle::lang_items::LangItem { - fn hash_stable(&self, - _: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, _: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { ::std::hash::Hash::hash(self, hasher); } } impl<'a> HashStable> for hir::TraitCandidate { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { let hir::TraitCandidate { def_id, @@ -422,17 +382,13 @@ impl<'a> ToStableHashKey> for hir::TraitCandidate { } impl<'hir> HashStable> for attr::InlineAttr { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'hir>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); } } impl<'hir> HashStable> for attr::OptimizeAttr { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'hir>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); } } diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 5cc8324b31606..23a2f115e05e2 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -9,21 +9,18 @@ use std::mem; use syntax::ast; use syntax::feature_gate; use syntax::parse::token; -use syntax::symbol::{InternedString, LocalInternedString}; +use syntax::symbol::InternedString; use syntax::tokenstream; use syntax_pos::SourceFile; use crate::hir::def_id::{DefId, CrateNum, CRATE_DEF_INDEX}; use smallvec::SmallVec; -use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, - StableHasher, StableHasherResult}; +use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher}; impl<'a> HashStable> for InternedString { #[inline] - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.with(|s| s.hash_stable(hcx, hasher)) } } @@ -39,32 +36,9 @@ impl<'a> ToStableHashKey> for InternedString { } } -impl<'a> HashStable> for LocalInternedString { - #[inline] - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - let s: &str = &**self; - s.hash_stable(hcx, hasher); - } -} - -impl<'a> ToStableHashKey> for LocalInternedString { - type KeyType = LocalInternedString; - - #[inline] - fn to_stable_hash_key(&self, - _: &StableHashingContext<'a>) - -> LocalInternedString { - self.clone() - } -} - impl<'a> HashStable> for ast::Name { #[inline] - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.as_str().hash_stable(hcx, hasher); } } @@ -131,14 +105,13 @@ impl_stable_hash_for!(enum ::syntax::edition::Edition { impl<'a> HashStable> for ::syntax::attr::StabilityLevel { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { - ::syntax::attr::StabilityLevel::Unstable { ref reason, ref issue } => { + ::syntax::attr::StabilityLevel::Unstable { ref reason, ref issue, ref is_soft } => { reason.hash_stable(hcx, hasher); issue.hash_stable(hcx, hasher); + is_soft.hash_stable(hcx, hasher); } ::syntax::attr::StabilityLevel::Stable { ref since } => { since.hash_stable(hcx, hasher); @@ -162,7 +135,7 @@ impl_stable_hash_for!(enum ::syntax::ast::LitIntType { }); impl_stable_hash_for!(struct ::syntax::ast::Lit { - node, + kind, token, span }); @@ -192,9 +165,7 @@ impl_stable_hash_for!(enum ::syntax::ast::StrStyle { Cooked, Raw(pounds) }); impl_stable_hash_for!(enum ::syntax::ast::AttrStyle { Outer, Inner }); impl<'a> HashStable> for [ast::Attribute] { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { if self.len() == 0 { self.len().hash_stable(hcx, hasher); return @@ -217,9 +188,7 @@ impl<'a> HashStable> for [ast::Attribute] { } impl<'a> HashStable> for ast::Path { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.segments.len().hash_stable(hcx, hasher); for segment in &self.segments { segment.ident.name.hash_stable(hcx, hasher); @@ -227,37 +196,34 @@ impl<'a> HashStable> for ast::Path { } } +impl_stable_hash_for!(struct ::syntax::ast::AttrItem { + path, + tokens, +}); + impl<'a> HashStable> for ast::Attribute { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { // Make sure that these have been filtered out. debug_assert!(!self.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name))); debug_assert!(!self.is_sugared_doc); let ast::Attribute { + ref item, id: _, style, - ref path, - ref tokens, is_sugared_doc: _, span, } = *self; + item.hash_stable(hcx, hasher); style.hash_stable(hcx, hasher); - path.hash_stable(hcx, hasher); - for tt in tokens.trees() { - tt.hash_stable(hcx, hasher); - } span.hash_stable(hcx, hasher); } } impl<'a> HashStable> for tokenstream::TokenTree { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { tokenstream::TokenTree::Token(ref token) => { @@ -276,9 +242,7 @@ for tokenstream::TokenTree { impl<'a> HashStable> for tokenstream::TokenStream { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { for sub_tt in self.trees() { sub_tt.hash_stable(hcx, hasher); } @@ -305,9 +269,7 @@ impl_stable_hash_for!(struct token::Lit { }); impl<'a> HashStable> for token::TokenKind { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { token::Eq | @@ -381,7 +343,7 @@ impl_stable_hash_for!(enum ::syntax::ast::NestedMetaItem { impl_stable_hash_for!(struct ::syntax::ast::MetaItem { path, - node, + kind, span }); @@ -397,11 +359,11 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::Transparency { Opaque, }); -impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { - call_site, +impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnData { kind, + parent -> _, + call_site, def_site, - default_transparency, allow_internal_unstable, allow_internal_unsafe, local_inner_macros, @@ -411,9 +373,17 @@ impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnKind { Root, Macro(kind, descr), + AstPass(kind), Desugaring(kind) }); +impl_stable_hash_for!(enum ::syntax_pos::hygiene::AstPass { + StdImports, + TestHarness, + ProcMacroHarness, + PluginMacroDefs, +}); + impl_stable_hash_for!(enum ::syntax_pos::hygiene::DesugaringKind { CondTemporary, Async, @@ -438,9 +408,7 @@ impl_stable_hash_for!(enum ::syntax_pos::FileName { }); impl<'a> HashStable> for SourceFile { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let SourceFile { name: _, // We hash the smaller name_hash instead of this name_hash, @@ -514,11 +482,7 @@ fn stable_non_narrow_char(swc: ::syntax_pos::NonNarrowChar, } impl<'tcx> HashStable> for feature_gate::Features { - fn hash_stable( - &self, - hcx: &mut StableHashingContext<'tcx>, - hasher: &mut StableHasher, - ) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { // Unfortunately we cannot exhaustively list fields here, since the // struct is macro generated. self.declared_lang_features.hash_stable(hcx, hasher); diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 0ddc9211f9811..c643baf11254c 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -3,8 +3,7 @@ use crate::ich::{Fingerprint, StableHashingContext, NodeIdHashingMode}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, - StableHasher, StableHasherResult}; +use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher}; use std::cell::RefCell; use std::mem; use crate::middle::region; @@ -15,9 +14,7 @@ impl<'a, 'tcx, T> HashStable> for &'tcx ty::List where T: HashStable>, { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { thread_local! { static CACHE: RefCell> = RefCell::new(Default::default()); @@ -56,19 +53,15 @@ where } } -impl<'a, 'tcx> HashStable> for ty::subst::Kind<'tcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { +impl<'a, 'tcx> HashStable> for ty::subst::GenericArg<'tcx> { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.unpack().hash_stable(hcx, hasher); } } impl<'a> HashStable> for ty::RegionKind { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { ty::ReErased | @@ -112,31 +105,21 @@ for ty::RegionKind { impl<'a> HashStable> for ty::RegionVid { #[inline] - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.index().hash_stable(hcx, hasher); } } impl<'a, 'tcx> HashStable> for ty::ConstVid<'tcx> { #[inline] - fn hash_stable( - &self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher, - ) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.index.hash_stable(hcx, hasher); } } impl<'tcx> HashStable> for ty::BoundVar { #[inline] - fn hash_stable( - &self, - hcx: &mut StableHashingContext<'tcx>, - hasher: &mut StableHasher, - ) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { self.index().hash_stable(hcx, hasher); } } @@ -145,20 +128,14 @@ impl<'a, T> HashStable> for ty::Binder where T: HashStable>, { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.skip_binder().hash_stable(hcx, hasher); } } // AllocIds get resolved to whatever they point to (to be stable) impl<'a> HashStable> for mir::interpret::AllocId { - fn hash_stable( - &self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher, - ) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { ty::tls::with_opt(|tcx| { trace!("hashing {:?}", *self); let tcx = tcx.expect("can't hash AllocIds during hir lowering"); @@ -168,25 +145,17 @@ impl<'a> HashStable> for mir::interpret::AllocId { } } -// Allocations treat their relocations specially -impl<'a> HashStable> for mir::interpret::Allocation { - fn hash_stable( - &self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher, - ) { - let mir::interpret::Allocation { - bytes, relocations, undef_mask, align, mutability, - extra: _, - } = self; - bytes.hash_stable(hcx, hasher); - relocations.len().hash_stable(hcx, hasher); - for reloc in relocations.iter() { +// `Relocations` with default type parameters is a sorted map. +impl<'a, Tag> HashStable> +for mir::interpret::Relocations +where + Tag: HashStable>, +{ + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + self.len().hash_stable(hcx, hasher); + for reloc in self.iter() { reloc.hash_stable(hcx, hasher); } - undef_mask.hash_stable(hcx, hasher); - align.hash_stable(hcx, hasher); - mutability.hash_stable(hcx, hasher); } } @@ -205,30 +174,24 @@ impl<'a> ToStableHashKey> for region::Scope { } impl<'a> HashStable> for ty::TyVid { - fn hash_stable(&self, - _hcx: &mut StableHashingContext<'a>, - _hasher: &mut StableHasher) { - // TyVid values are confined to an inference context and hence + fn hash_stable(&self, _hcx: &mut StableHashingContext<'a>, _hasher: &mut StableHasher) { + // `TyVid` values are confined to an inference context and hence // should not be hashed. bug!("ty::TyKind::hash_stable() - can't hash a TyVid {:?}.", *self) } } impl<'a> HashStable> for ty::IntVid { - fn hash_stable(&self, - _hcx: &mut StableHashingContext<'a>, - _hasher: &mut StableHasher) { - // IntVid values are confined to an inference context and hence + fn hash_stable(&self, _hcx: &mut StableHashingContext<'a>, _hasher: &mut StableHasher) { + // `IntVid` values are confined to an inference context and hence // should not be hashed. bug!("ty::TyKind::hash_stable() - can't hash an IntVid {:?}.", *self) } } impl<'a> HashStable> for ty::FloatVid { - fn hash_stable(&self, - _hcx: &mut StableHashingContext<'a>, - _hasher: &mut StableHasher) { - // FloatVid values are confined to an inference context and hence + fn hash_stable(&self, _hcx: &mut StableHashingContext<'a>, _hasher: &mut StableHasher) { + // `FloatVid` values are confined to an inference context and hence // should not be hashed. bug!("ty::TyKind::hash_stable() - can't hash a FloatVid {:?}.", *self) } @@ -238,18 +201,14 @@ impl<'a, T> HashStable> for ty::steal::Steal where T: HashStable>, { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.borrow().hash_stable(hcx, hasher); } } impl<'a> HashStable> for crate::middle::privacy::AccessLevels { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { let crate::middle::privacy::AccessLevels { ref map diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index db724875b8aa3..b9474f869ee29 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -13,12 +13,12 @@ use crate::infer::InferCtxt; use crate::mir::interpret::ConstValue; use std::sync::atomic::Ordering; use crate::ty::fold::{TypeFoldable, TypeFolder}; -use crate::ty::subst::Kind; +use crate::ty::subst::GenericArg; use crate::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags}; use crate::ty::flags::FlagComputation; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use smallvec::SmallVec; impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { @@ -282,7 +282,7 @@ struct Canonicalizer<'cx, 'tcx> { query_state: &'cx mut OriginalQueryValues<'tcx>, // Note that indices is only used once `var_values` is big enough to be // heap-allocated. - indices: FxHashMap, BoundVar>, + indices: FxHashMap, BoundVar>, canonicalize_region_mode: &'cx dyn CanonicalizeRegionMode, needs_canonical_flags: TypeFlags, @@ -343,7 +343,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.sty { + match t.kind { ty::Infer(ty::TyVar(vid)) => { debug!("canonical: type var found with vid {:?}", vid); match self.infcx.unwrap().probe_ty_var(vid) { @@ -566,7 +566,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { /// or returns an existing variable if `kind` has already been /// seen. `kind` is expected to be an unbound variable (or /// potentially a free region). - fn canonical_var(&mut self, info: CanonicalVarInfo, kind: Kind<'tcx>) -> BoundVar { + fn canonical_var(&mut self, info: CanonicalVarInfo, kind: GenericArg<'tcx>) -> BoundVar { let Canonicalizer { variables, query_state, diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index 6840611d4be79..562a463ded86a 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -25,14 +25,14 @@ use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVari use crate::infer::{ConstVariableOrigin, ConstVariableOriginKind}; use crate::infer::region_constraints::MemberConstraint; use crate::mir::interpret::ConstValue; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use rustc_serialize::UseSpecializedDecodable; use smallvec::SmallVec; use std::ops::Index; use syntax::source_map::Span; use crate::ty::fold::TypeFoldable; -use crate::ty::subst::Kind; +use crate::ty::subst::GenericArg; use crate::ty::{self, BoundVar, InferConst, Lift, List, Region, TyCtxt}; mod canonicalizer; @@ -66,7 +66,7 @@ impl<'tcx> UseSpecializedDecodable for CanonicalVarInfos<'tcx> {} /// canonicalized query response. #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)] pub struct CanonicalVarValues<'tcx> { - pub var_values: IndexVec>, + pub var_values: IndexVec>, } /// When we canonicalize a value to form a query, we wind up replacing @@ -83,7 +83,7 @@ pub struct OriginalQueryValues<'tcx> { /// This is equivalent to `CanonicalVarValues`, but using a /// `SmallVec` yields a significant performance win. - pub var_values: SmallVec<[Kind<'tcx>; 8]>, + pub var_values: SmallVec<[GenericArg<'tcx>; 8]>, } impl Default for OriginalQueryValues<'tcx> { @@ -308,7 +308,7 @@ impl<'tcx, V> Canonical<'tcx, V> { } pub type QueryOutlivesConstraint<'tcx> = - ty::Binder, Region<'tcx>>>; + ty::Binder, Region<'tcx>>>; impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// Creates a substitution S for the canonical value with fresh @@ -359,7 +359,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { variables: &List, universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, ) -> CanonicalVarValues<'tcx> { - let var_values: IndexVec> = variables + let var_values: IndexVec> = variables .iter() .map(|info| self.instantiate_canonical_var(span, *info, &universe_map)) .collect(); @@ -376,7 +376,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { span: Span, cv_info: CanonicalVarInfo, universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, - ) -> Kind<'tcx> { + ) -> GenericArg<'tcx> { match cv_info.kind { CanonicalVarKind::Ty(ty_kind) => { let ty = match ty_kind { @@ -495,19 +495,19 @@ impl<'tcx> CanonicalVarValues<'tcx> { /// we'll return a substitution `subst` with: /// `subst.var_values == [Type(^0), Lifetime(^1), Type(^2)]`. pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self { - use crate::ty::subst::UnpackedKind; + use crate::ty::subst::GenericArgKind; CanonicalVarValues { var_values: self.var_values.iter() .zip(0..) .map(|(kind, i)| match kind.unpack() { - UnpackedKind::Type(..) => tcx.mk_ty( + GenericArgKind::Type(..) => tcx.mk_ty( ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into()) ).into(), - UnpackedKind::Lifetime(..) => tcx.mk_region( + GenericArgKind::Lifetime(..) => tcx.mk_region( ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i)) ).into(), - UnpackedKind::Const(ct) => { + GenericArgKind::Const(ct) => { tcx.mk_const(ty::Const { ty: ct.ty, val: ConstValue::Infer( @@ -522,8 +522,8 @@ impl<'tcx> CanonicalVarValues<'tcx> { } impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> { - type Item = Kind<'tcx>; - type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, Kind<'tcx>>>; + type Item = GenericArg<'tcx>; + type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, GenericArg<'tcx>>>; fn into_iter(self) -> Self::IntoIter { self.var_values.iter().cloned() @@ -570,9 +570,9 @@ BraceStructLiftImpl! { } impl<'tcx> Index for CanonicalVarValues<'tcx> { - type Output = Kind<'tcx>; + type Output = GenericArg<'tcx>; - fn index(&self, value: BoundVar) -> &Kind<'tcx> { + fn index(&self, value: BoundVar) -> &GenericArg<'tcx> { &self.var_values[value] } } diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index 79c5538626be1..95b6a8bc84342 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -17,15 +17,15 @@ use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::InferCtxtBuilder; use crate::infer::{InferCtxt, InferOk, InferResult}; use crate::mir::interpret::ConstValue; -use rustc_data_structures::indexed_vec::Idx; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::vec::Idx; +use rustc_index::vec::IndexVec; use std::fmt::Debug; use syntax_pos::DUMMY_SP; use crate::traits::query::{Fallible, NoSolution}; use crate::traits::TraitEngine; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; use crate::ty::fold::TypeFoldable; -use crate::ty::subst::{Kind, UnpackedKind}; +use crate::ty::subst::{GenericArg, GenericArgKind}; use crate::ty::{self, BoundVar, InferConst, Ty, TyCtxt}; use crate::util::captures::Captures; @@ -298,11 +298,14 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { &v.var_values[BoundVar::new(index)] }); match (original_value.unpack(), result_value.unpack()) { - (UnpackedKind::Lifetime(ty::ReErased), UnpackedKind::Lifetime(ty::ReErased)) => { - // no action needed + ( + GenericArgKind::Lifetime(ty::ReErased), + GenericArgKind::Lifetime(ty::ReErased), + ) => { + // No action needed. } - (UnpackedKind::Lifetime(v_o), UnpackedKind::Lifetime(v_r)) => { + (GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => { // To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`. if v_o != v_r { output_query_region_constraints @@ -314,12 +317,12 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { } } - (UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => { + (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => { let ok = self.at(cause, param_env).eq(v1, v2)?; obligations.extend(ok.into_obligations()); } - (UnpackedKind::Const(v1), UnpackedKind::Const(v2)) => { + (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => { let ok = self.at(cause, param_env).eq(v1, v2)?; obligations.extend(ok.into_obligations()); } @@ -462,16 +465,16 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // is directly equal to one of the canonical variables in the // result, then we can type the corresponding value from the // input. See the example above. - let mut opt_values: IndexVec>> = + let mut opt_values: IndexVec>> = IndexVec::from_elem_n(None, query_response.variables.len()); // In terms of our example above, we are iterating over pairs like: // [(?A, Vec), ('static, '?1), (?B, ?0)] for (original_value, result_value) in original_values.var_values.iter().zip(result_values) { match result_value.unpack() { - UnpackedKind::Type(result_value) => { + GenericArgKind::Type(result_value) => { // e.g., here `result_value` might be `?0` in the example above... - if let ty::Bound(debruijn, b) = result_value.sty { + if let ty::Bound(debruijn, b) = result_value.kind { // ...in which case we would set `canonical_vars[0]` to `Some(?U)`. // We only allow a `ty::INNERMOST` index in substitutions. @@ -479,7 +482,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { opt_values[b.var] = Some(*original_value); } } - UnpackedKind::Lifetime(result_value) => { + GenericArgKind::Lifetime(result_value) => { // e.g., here `result_value` might be `'?1` in the example above... if let &ty::RegionKind::ReLateBound(debruijn, br) = result_value { // ... in which case we would set `canonical_vars[0]` to `Some('static)`. @@ -489,7 +492,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { opt_values[br.assert_bound_var()] = Some(*original_value); } } - UnpackedKind::Const(result_value) => { + GenericArgKind::Const(result_value) => { if let ty::Const { val: ConstValue::Infer(InferConst::Canonical(debrujin, b)), .. @@ -553,7 +556,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // canonical variable; this is taken from // `query_response.var_values` after applying the substitution // `result_subst`. - let substituted_query_response = |index: BoundVar| -> Kind<'tcx> { + let substituted_query_response = |index: BoundVar| -> GenericArg<'tcx> { query_response.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index]) }; @@ -586,17 +589,17 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { cause.clone(), param_env, match k1.unpack() { - UnpackedKind::Lifetime(r1) => ty::Predicate::RegionOutlives( + GenericArgKind::Lifetime(r1) => ty::Predicate::RegionOutlives( ty::Binder::bind( ty::OutlivesPredicate(r1, r2) ) ), - UnpackedKind::Type(t1) => ty::Predicate::TypeOutlives( + GenericArgKind::Type(t1) => ty::Predicate::TypeOutlives( ty::Binder::bind( ty::OutlivesPredicate(t1, r2) ) ), - UnpackedKind::Const(..) => { + GenericArgKind::Const(..) => { // Consts cannot outlive one another, so we don't expect to // ecounter this branch. span_bug!(cause.span, "unexpected const outlives {:?}", constraint); @@ -613,7 +616,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, variables1: &OriginalQueryValues<'tcx>, - variables2: impl Fn(BoundVar) -> Kind<'tcx>, + variables2: impl Fn(BoundVar) -> GenericArg<'tcx>, ) -> InferResult<'tcx, ()> { self.commit_if_ok(|_| { let mut obligations = vec![]; @@ -621,21 +624,21 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { let value2 = variables2(BoundVar::new(index)); match (value1.unpack(), value2.unpack()) { - (UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => { + (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => { obligations .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); } ( - UnpackedKind::Lifetime(ty::ReErased), - UnpackedKind::Lifetime(ty::ReErased), + GenericArgKind::Lifetime(ty::ReErased), + GenericArgKind::Lifetime(ty::ReErased), ) => { // no action needed } - (UnpackedKind::Lifetime(v1), UnpackedKind::Lifetime(v2)) => { + (GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => { obligations .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); } - (UnpackedKind::Const(v1), UnpackedKind::Const(v2)) => { + (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => { let ok = self.at(cause, param_env).eq(v1, v2)?; obligations.extend(ok.into_obligations()); } diff --git a/src/librustc/infer/canonical/substitute.rs b/src/librustc/infer/canonical/substitute.rs index 1234b96ab110c..4f5bb09c9167a 100644 --- a/src/librustc/infer/canonical/substitute.rs +++ b/src/librustc/infer/canonical/substitute.rs @@ -8,7 +8,7 @@ use crate::infer::canonical::{Canonical, CanonicalVarValues}; use crate::ty::fold::TypeFoldable; -use crate::ty::subst::UnpackedKind; +use crate::ty::subst::GenericArgKind; use crate::ty::{self, TyCtxt}; impl<'tcx, V> Canonical<'tcx, V> { @@ -58,21 +58,21 @@ where } else { let fld_r = |br: ty::BoundRegion| { match var_values.var_values[br.assert_bound_var()].unpack() { - UnpackedKind::Lifetime(l) => l, + GenericArgKind::Lifetime(l) => l, r => bug!("{:?} is a region but value is {:?}", br, r), } }; let fld_t = |bound_ty: ty::BoundTy| { match var_values.var_values[bound_ty.var].unpack() { - UnpackedKind::Type(ty) => ty, + GenericArgKind::Type(ty) => ty, r => bug!("{:?} is a type but value is {:?}", bound_ty, r), } }; let fld_c = |bound_ct: ty::BoundVar, _| { match var_values.var_values[bound_ct].unpack() { - UnpackedKind::Const(ct) => ct, + GenericArgKind::Const(ct) => ct, c => bug!("{:?} is a const but value is {:?}", bound_ct, c), } }; diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 4a9b68f24371d..6f73275d455f5 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -30,6 +30,7 @@ use super::sub::Sub; use super::type_variable::TypeVariableValue; use super::unify_key::{ConstVarValue, ConstVariableValue}; use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; +use super::unify_key::replace_if_possible; use crate::hir::def_id::DefId; use crate::mir::interpret::ConstValue; @@ -69,7 +70,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { { let a_is_expected = relation.a_is_expected(); - match (&a.sty, &b.sty) { + match (&a.kind, &b.kind) { // Relate integral variables to other types (&ty::Infer(ty::IntVar(a_id)), &ty::Infer(ty::IntVar(b_id))) => { self.int_unification_table @@ -127,6 +128,12 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { where R: TypeRelation<'tcx>, { + debug!("{}.consts({:?}, {:?})", relation.tag(), a, b); + if a == b { return Ok(a); } + + let a = replace_if_possible(self.const_unification_table.borrow_mut(), a); + let b = replace_if_possible(self.const_unification_table.borrow_mut(), b); + let a_is_expected = relation.a_is_expected(); match (a.val, b.val) { @@ -479,7 +486,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { // any other type variable related to `vid` via // subtyping. This is basically our "occurs check", preventing // us from creating infinitely sized types. - match t.sty { + match t.kind { ty::Infer(ty::TyVar(vid)) => { let mut variables = self.infcx.type_variables.borrow_mut(); let vid = variables.root_var(vid); diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index 5dfa0d29daf1b..aea58acab5450 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -1,14 +1,12 @@ -use super::combine::{CombineFields, RelationDir, const_unification_error}; +use super::combine::{CombineFields, RelationDir}; use super::Subtype; use crate::hir::def_id::DefId; -use crate::ty::{self, Ty, TyCtxt, InferConst}; +use crate::ty::{self, Ty, TyCtxt}; use crate::ty::TyVar; use crate::ty::subst::SubstsRef; use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use crate::mir::interpret::ConstValue; -use crate::infer::unify_key::replace_if_possible; /// Ensures `a` is made equal to `b`. Returns `a` on success. pub struct Equate<'combine, 'infcx, 'tcx> { @@ -70,7 +68,7 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> { debug!("{}.tys: replacements ({:?}, {:?})", self.tag(), a, b); - match (&a.sty, &b.sty) { + match (&a.kind, &b.kind) { (&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => { infcx.type_variables.borrow_mut().equate(a_id, b_id); } @@ -97,7 +95,7 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> { self.tag(), a, b); - let origin = Subtype(self.fields.trace.clone()); + let origin = Subtype(box self.fields.trace.clone()); self.fields.infcx.borrow_region_constraints() .make_eqregion(origin, a, b); Ok(a) @@ -108,39 +106,7 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> { a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>, ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - debug!("{}.consts({:?}, {:?})", self.tag(), a, b); - if a == b { return Ok(a); } - - let infcx = self.fields.infcx; - let a = replace_if_possible(infcx.const_unification_table.borrow_mut(), a); - let b = replace_if_possible(infcx.const_unification_table.borrow_mut(), b); - let a_is_expected = self.a_is_expected(); - - match (a.val, b.val) { - (ConstValue::Infer(InferConst::Var(a_vid)), - ConstValue::Infer(InferConst::Var(b_vid))) => { - infcx.const_unification_table - .borrow_mut() - .unify_var_var(a_vid, b_vid) - .map_err(|e| const_unification_error(a_is_expected, e))?; - return Ok(a); - } - - (ConstValue::Infer(InferConst::Var(a_id)), _) => { - self.fields.infcx.unify_const_variable(a_is_expected, a_id, b)?; - return Ok(a); - } - - (_, ConstValue::Infer(InferConst::Var(b_id))) => { - self.fields.infcx.unify_const_variable(!a_is_expected, b_id, a)?; - return Ok(a); - } - - _ => {} - } - - self.fields.infcx.super_combine_consts(self, a, b)?; - Ok(a) + self.fields.infcx.super_combine_consts(self, a, b) } fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 8d0ead5c8fe90..f1192c7ce10a9 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -55,7 +55,8 @@ use crate::hir::def_id::DefId; use crate::hir::Node; use crate::infer::opaque_types; use crate::middle::region; -use crate::traits::{ObligationCause, ObligationCauseCode}; +use crate::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause}; +use crate::traits::{ObligationCauseCode}; use crate::ty::error::TypeError; use crate::ty::{self, subst::{Subst, SubstsRef}, Region, Ty, TyCtxt, TypeFoldable}; use errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString}; @@ -89,7 +90,7 @@ impl<'tcx> TyCtxt<'tcx> { let span = scope.span(self, region_scope_tree); let tag = match self.hir().find(scope.hir_id(region_scope_tree)) { Some(Node::Block(_)) => "block", - Some(Node::Expr(expr)) => match expr.node { + Some(Node::Expr(expr)) => match expr.kind { hir::ExprKind::Call(..) => "call", hir::ExprKind::MethodCall(..) => "method call", hir::ExprKind::Match(.., hir::MatchSource::IfLetDesugar { .. }) => "if let", @@ -247,7 +248,7 @@ impl<'tcx> TyCtxt<'tcx> { } fn item_scope_tag(item: &hir::Item) -> &'static str { - match item.node { + match item.kind { hir::ItemKind::Impl(..) => "impl", hir::ItemKind::Struct(..) => "struct", hir::ItemKind::Union(..) => "union", @@ -259,14 +260,14 @@ impl<'tcx> TyCtxt<'tcx> { } fn trait_item_scope_tag(item: &hir::TraitItem) -> &'static str { - match item.node { + match item.kind { hir::TraitItemKind::Method(..) => "method body", hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => "associated item", } } fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str { - match item.node { + match item.kind { hir::ImplItemKind::Method(..) => "method body", hir::ImplItemKind::Const(..) | hir::ImplItemKind::OpaqueTy(..) @@ -463,7 +464,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { use hir::def_id::CrateNum; use hir::map::DisambiguatedDefPathData; use ty::print::Printer; - use ty::subst::Kind; + use ty::subst::GenericArg; struct AbsolutePathPrinter<'tcx> { tcx: TyCtxt<'tcx>, @@ -547,7 +548,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn path_generic_args( self, print_prefix: impl FnOnce(Self) -> Result, - _args: &[Kind<'tcx>], + _args: &[GenericArg<'tcx>], ) -> Result { print_prefix(self) } @@ -588,7 +589,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // if they are both "path types", there's a chance of ambiguity // due to different versions of the same crate if let (&ty::Adt(exp_adt, _), &ty::Adt(found_adt, _)) - = (&exp_found.expected.sty, &exp_found.found.sty) + = (&exp_found.expected.kind, &exp_found.found.kind) { report_path_match(err, exp_adt.did, found_adt.did); } @@ -624,13 +625,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } } - ObligationCauseCode::MatchExpressionArm { + ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { source, ref prior_arms, last_ty, discrim_hir_id, .. - } => match source { + }) => match source { hir::MatchSource::IfLetDesugar { .. } => { let msg = "`if let` arms have incompatible types"; err.span_label(cause.span, msg); @@ -638,7 +639,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { hir::MatchSource::TryDesugar => { if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found { let discrim_expr = self.tcx.hir().expect_expr(discrim_hir_id); - let discrim_ty = if let hir::ExprKind::Call(_, args) = &discrim_expr.node { + let discrim_ty = if let hir::ExprKind::Call(_, args) = &discrim_expr.kind { let arg_expr = args.first().expect("try desugaring call w/out arg"); self.in_progress_tables.and_then(|tables| { tables.borrow().expr_ty_opt(arg_expr) @@ -662,23 +663,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } _ => { + // `last_ty` can be `!`, `expected` will have better info when present. + let t = self.resolve_vars_if_possible(&match exp_found { + Some(ty::error::ExpectedFound { expected, .. }) => expected, + _ => last_ty, + }); let msg = "`match` arms have incompatible types"; err.span_label(cause.span, msg); if prior_arms.len() <= 4 { for sp in prior_arms { - err.span_label(*sp, format!( - "this is found to be of type `{}`", - self.resolve_vars_if_possible(&last_ty), - )); + err.span_label( *sp, format!("this is found to be of type `{}`", t)); } } else if let Some(sp) = prior_arms.last() { - err.span_label(*sp, format!( - "this and all prior arms are found to be of type `{}`", last_ty, - )); + err.span_label( + *sp, + format!("this and all prior arms are found to be of type `{}`", t), + ); } } }, - ObligationCauseCode::IfExpression { then, outer, semicolon } => { + ObligationCauseCode::IfExpression(box IfExpressionCause { then, outer, semicolon }) => { err.span_label(then, "expected because of this"); outer.map(|sp| err.span_label(sp, "if and else have incompatible types")); if let Some(sp) = semicolon { @@ -799,7 +803,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); return Some(()); } - if let &ty::Adt(def, _) = &ta.sty { + if let &ty::Adt(def, _) = &ta.kind { let path_ = self.tcx.def_path_str(def.did.clone()); if path_ == other_path { self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); @@ -864,7 +868,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// relevant differences, and return two representation of those types for highlighted printing. fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagnosticStyledString, DiagnosticStyledString) { fn equals<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match (&a.sty, &b.sty) { + match (&a.kind, &b.kind) { (a, b) if *a == *b => true, (&ty::Int(_), &ty::Infer(ty::InferTy::IntVar(_))) | (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Int(_)) @@ -898,7 +902,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { s.push_normal(ty.to_string()); } - match (&t1.sty, &t2.sty) { + match (&t1.kind, &t2.kind) { (&ty::Adt(def1, sub1), &ty::Adt(def2, sub2)) => { let sub_no_defaults_1 = self.strip_generic_default_params(def1.did, sub1); let sub_no_defaults_2 = self.strip_generic_default_params(def2.did, sub2); @@ -931,6 +935,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .filter(|(a, b)| a == b) .count(); let len = sub1.len() - common_default_params; + let consts_offset = len - sub1.consts().count(); // Only draw `<...>` if there're lifetime/type arguments. if len > 0 { @@ -977,7 +982,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // ^ elided type as this type argument was the same in both sides let type_arguments = sub1.types().zip(sub2.types()); let regions_len = sub1.regions().count(); - for (i, (ta1, ta2)) in type_arguments.take(len).enumerate() { + let num_display_types = consts_offset - regions_len; + for (i, (ta1, ta2)) in type_arguments.take(num_display_types).enumerate() { let i = i + regions_len; if ta1 == ta2 { values.0.push_normal("_"); @@ -990,6 +996,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.push_comma(&mut values.0, &mut values.1, len, i); } + // Do the same for const arguments, if they are equal, do not highlight and + // elide them from the output. + let const_arguments = sub1.consts().zip(sub2.consts()); + for (i, (ca1, ca2)) in const_arguments.enumerate() { + let i = i + consts_offset; + if ca1 == ca2 { + values.0.push_normal("_"); + values.1.push_normal("_"); + } else { + values.0.push_highlighted(ca1.to_string()); + values.1.push_highlighted(ca2.to_string()); + } + self.push_comma(&mut values.0, &mut values.1, len, i); + } + // Close the type argument bracket. // Only draw `<...>` if there're lifetime/type arguments. if len > 0 { @@ -1115,7 +1136,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Some((expected, found)) => Some((expected, found)), None => { // Derived error. Cancel the emitter. - self.tcx.sess.diagnostic().cancel(diag); + diag.cancel(); return; } }; @@ -1133,37 +1154,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let Some((expected, found)) = expected_found { match (terr, is_simple_error, expected == found) { (&TypeError::Sorts(ref values), false, true) => { + let sort_string = | a_type: Ty<'tcx> | + if let ty::Opaque(def_id, _) = a_type.kind { + format!(" (opaque type at {})", self.tcx.sess.source_map() + .mk_substr_filename(self.tcx.def_span(def_id))) + } else { + format!(" ({})", a_type.sort_string(self.tcx)) + }; diag.note_expected_found_extra( &"type", expected, found, - &format!(" ({})", values.expected.sort_string(self.tcx)), - &format!(" ({})", values.found.sort_string(self.tcx)), + &sort_string(values.expected), + &sort_string(values.found), ); } (_, false, _) => { if let Some(exp_found) = exp_found { - let (def_id, ret_ty) = match exp_found.found.sty { - ty::FnDef(def, _) => { - (Some(def), Some(self.tcx.fn_sig(def).output())) - } - _ => (None, None), - }; - - let exp_is_struct = match exp_found.expected.sty { - ty::Adt(def, _) => def.is_struct(), - _ => false, - }; - - if let (Some(def_id), Some(ret_ty)) = (def_id, ret_ty) { - if exp_is_struct && &exp_found.expected == ret_ty.skip_binder() { - let message = format!( - "did you mean `{}(/* fields */)`?", - self.tcx.def_path_str(def_id) - ); - diag.span_label(span, message); - } - } self.suggest_as_ref_where_appropriate(span, &exp_found, diag); } @@ -1189,9 +1196,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { exp_found: &ty::error::ExpectedFound>, diag: &mut DiagnosticBuilder<'tcx>, ) { - match (&exp_found.expected.sty, &exp_found.found.sty) { + match (&exp_found.expected.kind, &exp_found.found.kind) { (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) => { - if let ty::Adt(found_def, found_substs) = found_ty.sty { + if let ty::Adt(found_def, found_substs) = found_ty.kind { let path_str = format!("{:?}", exp_def); if exp_def == &found_def { let opt_msg = "you can convert from `&Option` to `Option<&T>` using \ @@ -1213,9 +1220,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { let mut show_suggestion = true; for (exp_ty, found_ty) in exp_substs.types().zip(found_substs.types()) { - match exp_ty.sty { + match exp_ty.kind { ty::Ref(_, exp_ty, _) => { - match (&exp_ty.sty, &found_ty.sty) { + match (&exp_ty.kind, &found_ty.kind) { (_, ty::Param(_)) | (_, ty::Infer(_)) | (ty::Param(_), _) | @@ -1347,7 +1354,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let generics = self.tcx.generics_of(did); // Account for the case where `did` corresponds to `Self`, which doesn't have // the expected type argument. - if !param.is_self() { + if !(generics.has_self && param.index == 0) { let type_param = generics.type_param(param, self.tcx); let hir = &self.tcx.hir(); hir.as_local_hir_id(type_param.def_id).map(|id| { @@ -1355,7 +1362,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // We do this to avoid suggesting code that ends up as `T: 'a'b`, // instead we suggest `T: 'a + 'b` in that case. let mut has_bounds = false; - if let Node::GenericParam(ref param) = hir.get(id) { + if let Node::GenericParam(param) = hir.get(id) { has_bounds = !param.bounds.is_empty(); } let sp = hir.span(id); @@ -1633,19 +1640,21 @@ impl<'tcx> ObligationCause<'tcx> { use crate::traits::ObligationCauseCode::*; match self.code { CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"), - MatchExpressionArm { source, .. } => Error0308(match source { - hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have incompatible types", - hir::MatchSource::TryDesugar => { - "try expression alternatives have incompatible types" - } - _ => "match arms have incompatible types", - }), + MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => + Error0308(match source { + hir::MatchSource::IfLetDesugar { .. } => + "`if let` arms have incompatible types", + hir::MatchSource::TryDesugar => { + "try expression alternatives have incompatible types" + } + _ => "match arms have incompatible types", + }), IfExpression { .. } => Error0308("if and else have incompatible types"), IfExpressionWithNoElse => Error0317("if may be missing an else clause"), MainFunctionType => Error0580("main function has wrong type"), StartFunctionType => Error0308("start function has wrong type"), IntrinsicType => Error0308("intrinsic has wrong type"), - MethodReceiver => Error0308("mismatched method receiver"), + MethodReceiver => Error0308("mismatched `self` parameter type"), // In the case where we have no more specific thing to // say, also take a look at the error code, maybe we can @@ -1654,6 +1663,9 @@ impl<'tcx> ObligationCause<'tcx> { TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => { Error0644("closure/generator type that references itself") } + TypeError::IntrinsicCast => { + Error0308("cannot coerce intrinsics to function pointers") + } _ => Error0308("mismatched types"), }, } @@ -1664,11 +1676,11 @@ impl<'tcx> ObligationCause<'tcx> { match self.code { CompareImplMethodObligation { .. } => "method type is compatible with trait", ExprAssignable => "expression is assignable", - MatchExpressionArm { source, .. } => match source { + MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source { hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have compatible types", _ => "match arms have compatible types", }, - IfExpression { .. } => "if and else have compatible types", + IfExpression { .. } => "if and else have incompatible types", IfExpressionWithNoElse => "if missing an else returns ()", MainFunctionType => "`main` function has the correct type", StartFunctionType => "`start` function has the correct type", diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 770d5155777bb..b89731273f7e2 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -1,5 +1,5 @@ use crate::hir::def::Namespace; -use crate::hir::{self, Local, Pat, Body, HirId}; +use crate::hir::{self, Body, FunctionRetTy, Expr, ExprKind, HirId, Local, Pat}; use crate::hir::intravisit::{self, Visitor, NestedVisitorMap}; use crate::infer::InferCtxt; use crate::infer::type_variable::TypeVariableOriginKind; @@ -7,7 +7,7 @@ use crate::ty::{self, Ty, Infer, TyVar}; use crate::ty::print::Print; use syntax::source_map::DesugaringKind; use syntax_pos::Span; -use errors::DiagnosticBuilder; +use errors::{Applicability, DiagnosticBuilder}; struct FindLocalByTypeVisitor<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, @@ -16,9 +16,26 @@ struct FindLocalByTypeVisitor<'a, 'tcx> { found_local_pattern: Option<&'tcx Pat>, found_arg_pattern: Option<&'tcx Pat>, found_ty: Option>, + found_closure: Option<&'tcx ExprKind>, } impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> { + fn new( + infcx: &'a InferCtxt<'a, 'tcx>, + target_ty: Ty<'tcx>, + hir_map: &'a hir::map::Map<'tcx>, + ) -> Self { + Self { + infcx, + target_ty, + hir_map, + found_local_pattern: None, + found_arg_pattern: None, + found_ty: None, + found_closure: None, + } + } + fn node_matches_type(&mut self, hir_id: HirId) -> Option> { let ty_opt = self.infcx.in_progress_tables.and_then(|tables| { tables.borrow().node_type_opt(hir_id) @@ -27,7 +44,7 @@ impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> { Some(ty) => { let ty = self.infcx.resolve_vars_if_possible(&ty); if ty.walk().any(|inner_ty| { - inner_ty == self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) { + inner_ty == self.target_ty || match (&inner_ty.kind, &self.target_ty.kind) { (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => { self.infcx .type_variables @@ -61,17 +78,71 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> { } fn visit_body(&mut self, body: &'tcx Body) { - for argument in &body.arguments { + for param in &body.params { if let (None, Some(ty)) = ( self.found_arg_pattern, - self.node_matches_type(argument.hir_id), + self.node_matches_type(param.hir_id), ) { - self.found_arg_pattern = Some(&*argument.pat); + self.found_arg_pattern = Some(&*param.pat); self.found_ty = Some(ty); } } intravisit::walk_body(self, body); } + + fn visit_expr(&mut self, expr: &'tcx Expr) { + if let (ExprKind::Closure(_, _fn_decl, _id, _sp, _), Some(_)) = ( + &expr.kind, + self.node_matches_type(expr.hir_id), + ) { + self.found_closure = Some(&expr.kind); + } + intravisit::walk_expr(self, expr); + } +} + +/// Suggest giving an appropriate return type to a closure expression. +fn closure_return_type_suggestion( + span: Span, + err: &mut DiagnosticBuilder<'_>, + output: &FunctionRetTy, + body: &Body, + name: &str, + ret: &str, +) { + let (arrow, post) = match output { + FunctionRetTy::DefaultReturn(_) => ("-> ", " "), + _ => ("", ""), + }; + let suggestion = match body.value.kind { + ExprKind::Block(..) => { + vec![(output.span(), format!("{}{}{}", arrow, ret, post))] + } + _ => { + vec![ + (output.span(), format!("{}{}{}{{ ", arrow, ret, post)), + (body.value.span.shrink_to_hi(), " }".to_string()), + ] + } + }; + err.multipart_suggestion( + "give this closure an explicit return type without `_` placeholders", + suggestion, + Applicability::HasPlaceholders, + ); + err.span_label(span, InferCtxt::missing_type_msg(&name)); +} + +/// Given a closure signature, return a `String` containing a list of all its argument types. +fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String { + fn_sig.inputs() + .skip_binder() + .iter() + .next() + .map(|args| args.tuple_fields() + .map(|arg| arg.to_string()) + .collect::>().join(", ")) + .unwrap_or_default() } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { @@ -79,12 +150,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, ty: Ty<'tcx>, highlight: Option, - ) -> String { - if let ty::Infer(ty::TyVar(ty_vid)) = ty.sty { + ) -> (String, Option) { + if let ty::Infer(ty::TyVar(ty_vid)) = ty.kind { let ty_vars = self.type_variables.borrow(); - if let TypeVariableOriginKind::TypeParameterDefinition(name) = - ty_vars.var_origin(ty_vid).kind { - return name.to_string(); + let var_origin = ty_vars.var_origin(ty_vid); + if let TypeVariableOriginKind::TypeParameterDefinition(name) = var_origin.kind { + return (name.to_string(), Some(var_origin.span)); } } @@ -94,7 +165,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { printer.region_highlight_mode = highlight; } let _ = ty.print(printer); - s + (s, None) } pub fn need_type_info_err( @@ -104,18 +175,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) -> DiagnosticBuilder<'tcx> { let ty = self.resolve_vars_if_possible(&ty); - let name = self.extract_type_name(&ty, None); - - let mut err_span = span; + let (name, name_sp) = self.extract_type_name(&ty, None); - let mut local_visitor = FindLocalByTypeVisitor { - infcx: &self, - target_ty: ty, - hir_map: &self.tcx.hir(), - found_local_pattern: None, - found_arg_pattern: None, - found_ty: None, - }; + let mut local_visitor = FindLocalByTypeVisitor::new(&self, ty, &self.tcx.hir()); let ty_to_string = |ty: Ty<'tcx>| -> String { let mut s = String::new(); let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); @@ -136,6 +198,39 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let expr = self.tcx.hir().expect_expr(body_id.hir_id); local_visitor.visit_expr(expr); } + let err_span = if let Some(pattern) = local_visitor.found_arg_pattern { + pattern.span + } else if let Some(span) = name_sp { + // `span` here lets us point at `sum` instead of the entire right hand side expr: + // error[E0282]: type annotations needed + // --> file2.rs:3:15 + // | + // 3 | let _ = x.sum() as f64; + // | ^^^ cannot infer type for `S` + span + } else { + span + }; + + let is_named_and_not_impl_trait = |ty: Ty<'_>| { + &ty.to_string() != "_" && + // FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527 + (!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings) + }; + + let ty_msg = match local_visitor.found_ty { + Some(ty::TyS { kind: ty::Closure(def_id, substs), .. }) => { + let fn_sig = substs.as_closure().sig(*def_id, self.tcx); + let args = closure_args(&fn_sig); + let ret = fn_sig.output().skip_binder().to_string(); + format!(" for the closure `fn({}) -> {}`", args, ret) + } + Some(ty) if is_named_and_not_impl_trait(ty) => { + let ty = ty_to_string(ty); + format!(" for `{}`", ty) + } + _ => String::new(), + }; // When `name` corresponds to a type argument, show the path of the full type we're // trying to infer. In the following example, `ty_msg` contains @@ -150,27 +245,58 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // | consider giving `b` the explicit type `std::result::Result`, where // | the type parameter `E` is specified // ``` - let (ty_msg, suffix) = match &local_visitor.found_ty { - Some(ty) if &ty.to_string() != "_" && name == "_" => { + let mut err = struct_span_err!( + self.tcx.sess, + err_span, + E0282, + "type annotations needed{}", + ty_msg, + ); + + let suffix = match local_visitor.found_ty { + Some(ty::TyS { kind: ty::Closure(def_id, substs), .. }) => { + let fn_sig = substs.as_closure().sig(*def_id, self.tcx); + let ret = fn_sig.output().skip_binder().to_string(); + + if let Some(ExprKind::Closure(_, decl, body_id, ..)) = local_visitor.found_closure { + if let Some(body) = self.tcx.hir().krate().bodies.get(body_id) { + closure_return_type_suggestion( + span, + &mut err, + &decl.output, + &body, + &name, + &ret, + ); + // We don't want to give the other suggestions when the problem is the + // closure return type. + return err; + } + } + + // This shouldn't be reachable, but just in case we leave a reasonable fallback. + let args = closure_args(&fn_sig); + // This suggestion is incomplete, as the user will get further type inference + // errors due to the `_` placeholders and the introduction of `Box`, but it does + // nudge them in the right direction. + format!("a boxed closure type like `Box {}>`", args, ret) + } + Some(ty) if is_named_and_not_impl_trait(ty) && name == "_" => { let ty = ty_to_string(ty); - (format!(" for `{}`", ty), - format!("the explicit type `{}`, with the type parameters specified", ty)) + format!("the explicit type `{}`, with the type parameters specified", ty) } - Some(ty) if &ty.to_string() != "_" && ty.to_string() != name => { + Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != name => { let ty = ty_to_string(ty); - (format!(" for `{}`", ty), - format!( - "the explicit type `{}`, where the type parameter `{}` is specified", + format!( + "the explicit type `{}`, where the type parameter `{}` is specified", ty, name, - )) + ) } - _ => (String::new(), "a type".to_owned()), + _ => "a type".to_string(), }; - let mut labels = vec![(span, InferCtxt::missing_type_msg(&name))]; if let Some(pattern) = local_visitor.found_arg_pattern { - err_span = pattern.span; // We don't want to show the default label for closures. // // So, before clearing, the output would look something like this: @@ -187,39 +313,48 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // ^ consider giving this closure parameter the type `[_; 0]` // with the type parameter `_` specified // ``` - labels.clear(); - labels.push(( + err.span_label( pattern.span, format!("consider giving this closure parameter {}", suffix), - )); + ); } else if let Some(pattern) = local_visitor.found_local_pattern { - if let Some(simple_ident) = pattern.simple_ident() { + let msg = if let Some(simple_ident) = pattern.simple_ident() { match pattern.span.desugaring_kind() { - None => labels.push(( - pattern.span, - format!("consider giving `{}` {}", simple_ident, suffix), - )), - Some(DesugaringKind::ForLoop) => labels.push(( - pattern.span, - "the element type for this iterator is not specified".to_owned(), - )), - _ => {} + None => { + format!("consider giving `{}` {}", simple_ident, suffix) + } + Some(DesugaringKind::ForLoop) => { + "the element type for this iterator is not specified".to_string() + } + _ => format!("this needs {}", suffix), } } else { - labels.push((pattern.span, format!("consider giving this pattern {}", suffix))); - } - }; - - let mut err = struct_span_err!( - self.tcx.sess, - err_span, - E0282, - "type annotations needed{}", - ty_msg, - ); - - for (target_span, label_message) in labels { - err.span_label(target_span, label_message); + format!("consider giving this pattern {}", suffix) + }; + err.span_label(pattern.span, msg); + } + // Instead of the following: + // error[E0282]: type annotations needed + // --> file2.rs:3:15 + // | + // 3 | let _ = x.sum() as f64; + // | --^^^--------- cannot infer type for `S` + // | + // = note: type must be known at this point + // We want: + // error[E0282]: type annotations needed + // --> file2.rs:3:15 + // | + // 3 | let _ = x.sum() as f64; + // | ^^^ cannot infer type for `S` + // | + // = note: type must be known at this point + let span = name_sp.unwrap_or(span); + if !err.span.span_labels().iter().any(|span_label| { + span_label.label.is_some() && span_label.span == span + }) && local_visitor.found_arg_pattern.is_none() + { // Avoid multiple labels pointing at `span`. + err.span_label(span, InferCtxt::missing_type_msg(&name)); } err @@ -232,7 +367,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) -> DiagnosticBuilder<'tcx> { let ty = self.resolve_vars_if_possible(&ty); - let name = self.extract_type_name(&ty, None); + let name = self.extract_type_name(&ty, None).0; let mut err = struct_span_err!( self.tcx.sess, span, E0698, "type inside {} must be known in this context", kind, ); diff --git a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs index 6bd2c04d51281..979815fa7f184 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -2,7 +2,7 @@ //! where both the regions are anonymous. use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::error_reporting::nice_region_error::util::AnonymousArgInfo; +use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo; use crate::util::common::ErrorReported; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { @@ -59,13 +59,13 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let ty_sub = self.find_anon_type(sub, &bregion_sub)?; debug!( - "try_report_anon_anon_conflict: found_arg1={:?} sup={:?} br1={:?}", + "try_report_anon_anon_conflict: found_param1={:?} sup={:?} br1={:?}", ty_sub, sup, bregion_sup ); debug!( - "try_report_anon_anon_conflict: found_arg2={:?} sub={:?} br2={:?}", + "try_report_anon_anon_conflict: found_param2={:?} sub={:?} br2={:?}", ty_sup, sub, bregion_sub @@ -74,24 +74,24 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let (ty_sup, ty_fndecl_sup) = ty_sup; let (ty_sub, ty_fndecl_sub) = ty_sub; - let AnonymousArgInfo { - arg: anon_arg_sup, .. - } = self.find_arg_with_region(sup, sup)?; - let AnonymousArgInfo { - arg: anon_arg_sub, .. - } = self.find_arg_with_region(sub, sub)?; + let AnonymousParamInfo { + param: anon_param_sup, .. + } = self.find_param_with_region(sup, sup)?; + let AnonymousParamInfo { + param: anon_param_sub, .. + } = self.find_param_with_region(sub, sub)?; let sup_is_ret_type = self.is_return_type_anon(scope_def_id_sup, bregion_sup, ty_fndecl_sup); let sub_is_ret_type = self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub); - let span_label_var1 = match anon_arg_sup.pat.simple_ident() { + let span_label_var1 = match anon_param_sup.pat.simple_ident() { Some(simple_ident) => format!(" from `{}`", simple_ident), None => String::new(), }; - let span_label_var2 = match anon_arg_sub.pat.simple_ident() { + let span_label_var2 = match anon_param_sub.pat.simple_ident() { Some(simple_ident) => format!(" into `{}`", simple_ident), None => String::new(), }; diff --git a/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs b/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs index 34f3b8a2c7205..9c362a5e20791 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -31,15 +31,15 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { if let Some(hir_id) = self.tcx().hir().as_local_hir_id(def_id) { let fndecl = match self.tcx().hir().get(hir_id) { Node::Item(&hir::Item { - node: hir::ItemKind::Fn(ref fndecl, ..), + kind: hir::ItemKind::Fn(ref fndecl, ..), .. }) => &fndecl, Node::TraitItem(&hir::TraitItem { - node: hir::TraitItemKind::Method(ref m, ..), + kind: hir::TraitItemKind::Method(ref m, ..), .. }) | Node::ImplItem(&hir::ImplItem { - node: hir::ImplItemKind::Method(ref m, ..), + kind: hir::ImplItemKind::Method(ref m, ..), .. }) => &m.decl, _ => return None, @@ -98,7 +98,7 @@ impl Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { } fn visit_ty(&mut self, arg: &'tcx hir::Ty) { - match arg.node { + match arg.kind { hir::TyKind::BareFn(_) => { self.current_index.shift_in(1); intravisit::walk_ty(self, arg); diff --git a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 51bee49b70fc0..a9a2c15d7d99b 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -6,7 +6,7 @@ use crate::ty; use errors::{Applicability, DiagnosticBuilder}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { - /// When given a `ConcreteFailure` for a function with arguments containing a named region and + /// When given a `ConcreteFailure` for a function with parameters containing a named region and /// an anonymous region, emit an descriptive diagnostic error. pub(super) fn try_report_named_anon_conflict(&self) -> Option> { let (span, sub, sup) = self.get_regions(); @@ -24,23 +24,23 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // only introduced anonymous regions in parameters) as well as a // version new_ty of its type where the anonymous region is replaced // with the named one.//scope_def_id - let (named, anon, anon_arg_info, region_info) = if self.is_named_region(sub) + let (named, anon, anon_param_info, region_info) = if self.is_named_region(sub) && self.tcx().is_suitable_region(sup).is_some() - && self.find_arg_with_region(sup, sub).is_some() + && self.find_param_with_region(sup, sub).is_some() { ( sub, sup, - self.find_arg_with_region(sup, sub).unwrap(), + self.find_param_with_region(sup, sub).unwrap(), self.tcx().is_suitable_region(sup).unwrap(), ) } else if self.is_named_region(sup) && self.tcx().is_suitable_region(sub).is_some() - && self.find_arg_with_region(sub, sup).is_some() + && self.find_param_with_region(sub, sup).is_some() { ( sup, sub, - self.find_arg_with_region(sub, sup).unwrap(), + self.find_param_with_region(sub, sup).unwrap(), self.tcx().is_suitable_region(sub).unwrap(), ) } else { @@ -49,20 +49,20 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { debug!("try_report_named_anon_conflict: named = {:?}", named); debug!( - "try_report_named_anon_conflict: anon_arg_info = {:?}", - anon_arg_info + "try_report_named_anon_conflict: anon_param_info = {:?}", + anon_param_info ); debug!( "try_report_named_anon_conflict: region_info = {:?}", region_info ); - let (arg, new_ty, new_ty_span, br, is_first, scope_def_id, is_impl_item) = ( - anon_arg_info.arg, - anon_arg_info.arg_ty, - anon_arg_info.arg_ty_span, - anon_arg_info.bound_region, - anon_arg_info.is_first, + let (param, new_ty, new_ty_span, br, is_first, scope_def_id, is_impl_item) = ( + anon_param_info.param, + anon_param_info.param_ty, + anon_param_info.param_ty_span, + anon_param_info.bound_region, + anon_param_info.is_first, region_info.def_id, region_info.is_impl_item, ); @@ -87,7 +87,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { return None; } if let FunctionRetTy::Return(ty) = &fndecl.output { - if let (TyKind::Def(_, _), ty::ReStatic) = (&ty.node, sub) { + if let (TyKind::Def(_, _), ty::ReStatic) = (&ty.kind, sub) { // This is an impl Trait return that evaluates de need of 'static. // We handle this case better in `static_impl_trait`. return None; @@ -95,7 +95,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } } - let (error_var, span_label_var) = match arg.pat.simple_ident() { + let (error_var, span_label_var) = match param.pat.simple_ident() { Some(simple_ident) => ( format!("the type of `{}`", simple_ident), format!("the type of `{}`", simple_ident), diff --git a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs b/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs index f5a4dac2c2cb8..9231e4f779eb7 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs @@ -50,7 +50,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let hir = &self.tcx().hir(); if let Some(hir_id) = hir.as_local_hir_id(free_region.scope) { if let Node::Expr(Expr { - node: Closure(_, _, _, closure_span, None), + kind: Closure(_, _, _, closure_span, None), .. }) = hir.get(hir_id) { let sup_sp = sup_origin.span(); diff --git a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs index b4fb018920647..bfa8353ca343f 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -30,7 +30,7 @@ impl NiceRegionError<'me, 'tcx> { Some(RegionResolutionError::SubSupConflict( vid, _, - SubregionOrigin::Subtype(TypeTrace { + SubregionOrigin::Subtype(box TypeTrace { cause, values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), }), @@ -50,7 +50,7 @@ impl NiceRegionError<'me, 'tcx> { Some(RegionResolutionError::SubSupConflict( vid, _, - SubregionOrigin::Subtype(TypeTrace { + SubregionOrigin::Subtype(box TypeTrace { cause, values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), }), @@ -70,7 +70,7 @@ impl NiceRegionError<'me, 'tcx> { Some(RegionResolutionError::SubSupConflict( vid, _, - SubregionOrigin::Subtype(TypeTrace { + SubregionOrigin::Subtype(box TypeTrace { cause, values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), }), @@ -92,7 +92,7 @@ impl NiceRegionError<'me, 'tcx> { _, _, _, - SubregionOrigin::Subtype(TypeTrace { + SubregionOrigin::Subtype(box TypeTrace { cause, values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), }), @@ -108,7 +108,7 @@ impl NiceRegionError<'me, 'tcx> { )), Some(RegionResolutionError::ConcreteFailure( - SubregionOrigin::Subtype(TypeTrace { + SubregionOrigin::Subtype(box TypeTrace { cause, values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), }), @@ -125,7 +125,7 @@ impl NiceRegionError<'me, 'tcx> { )), Some(RegionResolutionError::ConcreteFailure( - SubregionOrigin::Subtype(TypeTrace { + SubregionOrigin::Subtype(box TypeTrace { cause, values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), }), @@ -142,7 +142,7 @@ impl NiceRegionError<'me, 'tcx> { )), Some(RegionResolutionError::ConcreteFailure( - SubregionOrigin::Subtype(TypeTrace { + SubregionOrigin::Subtype(box TypeTrace { cause, values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), }), @@ -192,23 +192,28 @@ impl NiceRegionError<'me, 'tcx> { vid, sub_placeholder, sup_placeholder, trait_def_id, expected_substs, actual_substs ); - let mut err = self.tcx().sess.struct_span_err( - cause.span(self.tcx()), - &format!( - "implementation of `{}` is not general enough", - self.tcx().def_path_str(trait_def_id), - ), + let span = cause.span(self.tcx()); + let msg = format!( + "implementation of `{}` is not general enough", + self.tcx().def_path_str(trait_def_id), + ); + let mut err = self.tcx().sess.struct_span_err(span, &msg); + err.span_label( + self.tcx().def_span(trait_def_id), + format!("trait `{}` defined here", self.tcx().def_path_str(trait_def_id)), ); - match cause.code { - ObligationCauseCode::ItemObligation(def_id) => { - err.note(&format!( - "Due to a where-clause on `{}`,", - self.tcx().def_path_str(def_id), - )); - } - _ => (), - } + let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = cause.code { + err.span_label(span, "doesn't satisfy where-clause"); + err.span_label( + self.tcx().def_span(def_id), + &format!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id)), + ); + true + } else { + err.span_label(span, &msg); + false + }; let expected_trait_ref = self.infcx.resolve_vars_if_possible(&ty::TraitRef { def_id: trait_def_id, @@ -295,6 +300,7 @@ impl NiceRegionError<'me, 'tcx> { expected_has_vid, actual_has_vid, any_self_ty_has_vid, + leading_ellipsis, ); err @@ -318,6 +324,7 @@ impl NiceRegionError<'me, 'tcx> { expected_has_vid: Option, actual_has_vid: Option, any_self_ty_has_vid: bool, + leading_ellipsis: bool, ) { // HACK(eddyb) maybe move this in a more central location. #[derive(Copy, Clone)] @@ -392,13 +399,15 @@ impl NiceRegionError<'me, 'tcx> { let mut note = if passive_voice { format!( - "`{}` would have to be implemented for the type `{}`", + "{}`{}` would have to be implemented for the type `{}`", + if leading_ellipsis { "..." } else { "" }, expected_trait_ref, expected_trait_ref.map(|tr| tr.self_ty()), ) } else { format!( - "`{}` must implement `{}`", + "{}`{}` must implement `{}`", + if leading_ellipsis { "..." } else { "" }, expected_trait_ref.map(|tr| tr.self_ty()), expected_trait_ref, ) @@ -407,20 +416,20 @@ impl NiceRegionError<'me, 'tcx> { match (has_sub, has_sup) { (Some(n1), Some(n2)) => { let _ = write!(note, - ", for any two lifetimes `'{}` and `'{}`", + ", for any two lifetimes `'{}` and `'{}`...", std::cmp::min(n1, n2), std::cmp::max(n1, n2), ); } (Some(n), _) | (_, Some(n)) => { let _ = write!(note, - ", for any lifetime `'{}`", + ", for any lifetime `'{}`...", n, ); } (None, None) => if let Some(n) = expected_has_vid { let _ = write!(note, - ", for some specific lifetime `'{}`", + ", for some specific lifetime `'{}`...", n, ); }, @@ -439,13 +448,13 @@ impl NiceRegionError<'me, 'tcx> { let mut note = if passive_voice { format!( - "but `{}` is actually implemented for the type `{}`", + "...but `{}` is actually implemented for the type `{}`", actual_trait_ref, actual_trait_ref.map(|tr| tr.self_ty()), ) } else { format!( - "but `{}` actually implements `{}`", + "...but `{}` actually implements `{}`", actual_trait_ref.map(|tr| tr.self_ty()), actual_trait_ref, ) diff --git a/src/librustc/infer/error_reporting/nice_region_error/util.rs b/src/librustc/infer/error_reporting/nice_region_error/util.rs index f33f917392653..a2e48cf07cb7c 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/util.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/util.rs @@ -10,37 +10,37 @@ use syntax_pos::Span; // The struct contains the information about the anonymous region // we are searching for. #[derive(Debug)] -pub(super) struct AnonymousArgInfo<'tcx> { - // the argument corresponding to the anonymous region - pub arg: &'tcx hir::Arg, - // the type corresponding to the anonymopus region argument - pub arg_ty: Ty<'tcx>, +pub(super) struct AnonymousParamInfo<'tcx> { + // the parameter corresponding to the anonymous region + pub param: &'tcx hir::Param, + // the type corresponding to the anonymopus region parameter + pub param_ty: Ty<'tcx>, // the ty::BoundRegion corresponding to the anonymous region pub bound_region: ty::BoundRegion, - // arg_ty_span contains span of argument type - pub arg_ty_span : Span, + // param_ty_span contains span of parameter type + pub param_ty_span : Span, // corresponds to id the argument is the first parameter // in the declaration pub is_first: bool, } impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { - // This method walks the Type of the function body arguments using + // This method walks the Type of the function body parameters using // `fold_regions()` function and returns the - // &hir::Arg of the function argument corresponding to the anonymous + // &hir::Param of the function parameter corresponding to the anonymous // region and the Ty corresponding to the named region. // Currently only the case where the function declaration consists of // one named region and one anonymous region is handled. // Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32` - // Here, we would return the hir::Arg for y, we return the type &'a + // Here, we would return the hir::Param for y, we return the type &'a // i32, which is the type of y but with the anonymous region replaced // with 'a, the corresponding bound region and is_first which is true if - // the hir::Arg is the first argument in the function declaration. - pub(super) fn find_arg_with_region( + // the hir::Param is the first parameter in the function declaration. + pub(super) fn find_param_with_region( &self, anon_region: Region<'tcx>, replace_region: Region<'tcx>, - ) -> Option> { + ) -> Option> { let (id, bound_region) = match *anon_region { ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region), ty::ReEarlyBound(ebr) => ( @@ -57,16 +57,16 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let owner_id = hir.body_owner(body_id); let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap(); if let Some(tables) = self.tables { - body.arguments + body.params .iter() .enumerate() - .filter_map(|(index, arg)| { + .filter_map(|(index, param)| { // May return None; sometimes the tables are not yet populated. let ty_hir_id = fn_decl.inputs[index].hir_id; - let arg_ty_span = hir.span(ty_hir_id); - let ty = tables.node_type_opt(arg.hir_id)?; + let param_ty_span = hir.span(ty_hir_id); + let ty = tables.node_type_opt(param.hir_id)?; let mut found_anon_region = false; - let new_arg_ty = self.tcx().fold_regions(&ty, &mut false, |r, _| { + let new_param_ty = self.tcx().fold_regions(&ty, &mut false, |r, _| { if *r == *anon_region { found_anon_region = true; replace_region @@ -76,10 +76,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { }); if found_anon_region { let is_first = index == 0; - Some(AnonymousArgInfo { - arg: arg, - arg_ty: new_arg_ty, - arg_ty_span : arg_ty_span, + Some(AnonymousParamInfo { + param: param, + param_ty: new_param_ty, + param_ty_span : param_ty_span, bound_region: bound_region, is_first: is_first, }) @@ -109,7 +109,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { decl: &hir::FnDecl, ) -> Option { let ret_ty = self.tcx().type_of(scope_def_id); - if let ty::FnDef(_, _) = ret_ty.sty { + if let ty::FnDef(_, _) = ret_ty.kind { let sig = ret_ty.fn_sig(self.tcx()); let late_bound_regions = self.tcx() .collect_referenced_late_bound_regions(&sig.output()); diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs index caed4288892ef..115ffea97bf1a 100644 --- a/src/librustc/infer/error_reporting/note.rs +++ b/src/librustc/infer/error_reporting/note.rs @@ -138,7 +138,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { sup: Region<'tcx>) -> DiagnosticBuilder<'tcx> { match origin { - infer::Subtype(trace) => { + infer::Subtype(box trace) => { let terr = TypeError::RegionsDoesNotOutlive(sup, sub); let mut err = self.report_and_explain_type_error(trace, &terr); self.tcx.note_and_explain_region(region_scope_tree, &mut err, "", sup, "..."); @@ -450,7 +450,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) -> DiagnosticBuilder<'tcx> { // I can't think how to do better than this right now. -nikomatsakis match placeholder_origin { - infer::Subtype(trace) => { + infer::Subtype(box trace) => { let terr = TypeError::RegionsPlaceholderMismatch; self.report_and_explain_type_error(trace, &terr) } diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 400a538baa965..9e9220cc3d8cc 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -153,7 +153,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { let tcx = self.infcx.tcx; - match t.sty { + match t.kind { ty::Infer(ty::TyVar(v)) => { let opt_ty = self.infcx.type_variables.borrow_mut().probe(v).known(); self.freshen_ty( diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index 658a9c1d88805..e27766f461697 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -148,7 +148,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.sty { + match ty.kind { ty::Infer(ty::InferTy::TyVar(vid)) => { if self.type_vars.0.contains(&vid) { // This variable was created during the fudging. diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index 2cef521176269..37de54a7e8558 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -57,7 +57,7 @@ impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> { a, b); - let origin = Subtype(self.fields.trace.clone()); + let origin = Subtype(box self.fields.trace.clone()); Ok(self.fields.infcx.borrow_region_constraints().glb_regions(self.tcx(), origin, a, b)) } @@ -66,11 +66,6 @@ impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> { a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>, ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - debug!("{}.consts({:?}, {:?})", self.tag(), a, b); - if a == b { - return Ok(a); - } - self.fields.infcx.super_combine_consts(self, a, b) } diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs index 68cbef4407677..39701231aad7e 100644 --- a/src/librustc/infer/lattice.rs +++ b/src/librustc/infer/lattice.rs @@ -61,7 +61,7 @@ where let infcx = this.infcx(); let a = infcx.type_variables.borrow_mut().replace_if_possible(a); let b = infcx.type_variables.borrow_mut().replace_if_possible(b); - match (&a.sty, &b.sty) { + match (&a.kind, &b.kind) { // If one side is known to be a variable and one is not, // create a variable (`v`) to represent the LUB. Make sure to // relate `v` to the non-type-variable first (by passing it diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index 6282fde59cad4..f11f94c428e86 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -19,7 +19,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::implementation::{ Direction, Graph, NodeIndex, INCOMING, OUTGOING, }; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_index::vec::{Idx, IndexVec}; use smallvec::SmallVec; use std::fmt; use syntax_pos::Span; diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index e20372f151371..a1a94865e74e3 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -57,7 +57,7 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> { a, b); - let origin = Subtype(self.fields.trace.clone()); + let origin = Subtype(box self.fields.trace.clone()); Ok(self.fields.infcx.borrow_region_constraints().lub_regions(self.tcx(), origin, a, b)) } @@ -66,11 +66,6 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> { a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>, ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - debug!("{}.consts({:?}, {:?})", self.tag(), a, b); - if a == b { - return Ok(a); - } - self.fields.infcx.super_combine_consts(self, a, b) } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index e1d77a97c1160..af74d13572431 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -20,10 +20,10 @@ use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine}; use crate::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use crate::ty::fold::{TypeFolder, TypeFoldable}; use crate::ty::relate::RelateResult; -use crate::ty::subst::{Kind, InternalSubsts, SubstsRef}; +use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt, InferConst}; use crate::ty::{FloatVid, IntVid, TyVid, ConstVid}; -use crate::util::nodemap::FxHashMap; +use crate::util::nodemap::{FxHashMap, FxHashSet}; use errors::DiagnosticBuilder; use rustc_data_structures::sync::Lrc; @@ -93,6 +93,8 @@ impl SuppressRegionErrors { /// checks, so we should ignore errors if NLL is (unconditionally) /// enabled. pub fn when_nll_is_enabled(tcx: TyCtxt<'_>) -> Self { + // FIXME(Centril): Once we actually remove `::Migrate` also make + // this always `true` and then proceed to eliminate the dead code. match tcx.borrowck_mode() { // If we're on Migrate mode, report AST region errors BorrowckMode::Migrate => SuppressRegionErrors { suppressed: false }, @@ -153,6 +155,8 @@ pub struct InferCtxt<'a, 'tcx> { /// avoid reporting the same error twice. pub reported_trait_errors: RefCell>>>, + pub reported_closure_mismatch: RefCell)>>, + /// When an error occurs, we want to avoid reporting "derived" /// errors that are due to this original failure. Normally, we /// handle this with the `err_count_on_creation` count, which @@ -254,7 +258,7 @@ pub struct TypeTrace<'tcx> { #[derive(Clone, Debug)] pub enum SubregionOrigin<'tcx> { /// Arose from a subtyping relation - Subtype(TypeTrace<'tcx>), + Subtype(Box>), /// Stack-allocated closures cannot outlive innermost loop /// or function so as to ensure we only require finite stack @@ -340,6 +344,10 @@ pub enum SubregionOrigin<'tcx> { }, } +// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert_size!(SubregionOrigin<'_>, 32); + /// Places that type/region parameters can appear. #[derive(Clone, Copy, Debug)] pub enum ParameterOrigin { @@ -410,7 +418,19 @@ pub enum NLLRegionVariableOrigin { /// from a `for<'a> T` binder). Meant to represent "any region". Placeholder(ty::PlaceholderRegion), - Existential, + Existential { + /// If this is true, then this variable was created to represent a lifetime + /// bound in a `for` binder. For example, it might have been created to + /// represent the lifetime `'a` in a type like `for<'a> fn(&'a u32)`. + /// Such variables are created when we are trying to figure out if there + /// is any valid instantiation of `'a` that could fit into some scenario. + /// + /// This is used to inform error reporting: in the case that we are trying to + /// determine whether there is any valid instantiation of a `'a` variable that meets + /// some constraint C, we want to blame the "source" of that `for` type, + /// rather than blaming the source of the constraint C. + from_forall: bool + }, } impl NLLRegionVariableOrigin { @@ -418,7 +438,7 @@ impl NLLRegionVariableOrigin { match self { NLLRegionVariableOrigin::FreeRegion => true, NLLRegionVariableOrigin::Placeholder(..) => true, - NLLRegionVariableOrigin::Existential => false, + NLLRegionVariableOrigin::Existential{ .. } => false, } } @@ -532,6 +552,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { selection_cache: Default::default(), evaluation_cache: Default::default(), reported_trait_errors: Default::default(), + reported_closure_mismatch: Default::default(), tainted_by_errors_flag: Cell::new(false), err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), @@ -610,7 +631,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool { - match ty.sty { + match ty.kind { ty::Infer(ty::TyVar(vid)) => self.type_variables.borrow().var_diverges(vid), _ => false, } @@ -623,7 +644,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn type_is_unconstrained_numeric(&'a self, ty: Ty<'_>) -> UnconstrainedNumeric { use crate::ty::error::UnconstrainedNumeric::Neither; use crate::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; - match ty.sty { + match ty.kind { ty::Infer(ty::IntVar(vid)) => { if self.int_unification_table .borrow_mut() @@ -793,16 +814,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Executes `f` and commit the bindings. pub fn commit_unconditionally(&self, f: F) -> R where - F: FnOnce() -> R, + F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, { - debug!("commit()"); + debug!("commit_unconditionally()"); let snapshot = self.start_snapshot(); - let r = f(); + let r = f(&snapshot); self.commit_from(snapshot); r } - /// Executes `f` and commit the bindings if closure `f` returns `Ok(_)`. + /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`. pub fn commit_if_ok(&self, f: F) -> Result where F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result, @@ -822,19 +843,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { r } - /// Execute `f` in a snapshot, and commit the bindings it creates. - pub fn in_snapshot(&self, f: F) -> T - where - F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> T, - { - debug!("in_snapshot()"); - let snapshot = self.start_snapshot(); - let r = f(&snapshot); - self.commit_from(snapshot); - r - } - - /// Executes `f` then unroll any bindings it creates. + /// Execute `f` then unroll any bindings it creates. pub fn probe(&self, f: F) -> R where F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, @@ -1106,7 +1115,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.next_region_var_in_universe(RegionVariableOrigin::NLL(origin), universe) } - pub fn var_for_def(&self, span: Span, param: &ty::GenericParamDef) -> Kind<'tcx> { + pub fn var_for_def(&self, span: Span, param: &ty::GenericParamDef) -> GenericArg<'tcx> { match param.kind { GenericParamDefKind::Lifetime => { // Create a region inference variable for the given @@ -1298,6 +1307,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + /// Resolve any type variables found in `value` -- but only one + /// level. So, if the variable `?X` is bound to some type + /// `Foo`, then this would return `Foo` (but `?Y` may + /// itself be bound to a type). + /// + /// Useful when you only need to inspect the outermost level of + /// the type and don't care about nested types (or perhaps you + /// will be resolving them as well, e.g. in a loop). pub fn shallow_resolve(&self, value: T) -> T where T: TypeFoldable<'tcx>, @@ -1321,13 +1338,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { T: TypeFoldable<'tcx>, { if !value.needs_infer() { - return value.clone(); // avoid duplicated subst-folding + return value.clone(); // Avoid duplicated subst-folding. } let mut r = resolve::OpportunisticVarResolver::new(self); value.fold_with(&mut r) } - /// Returns first unresolved variable contained in `T`. In the + /// Returns the first unresolved variable contained in `T`. In the /// process of visiting `T`, this will resolve (where possible) /// type variables in `T`, but it never constructs the final, /// resolved type, so it's more efficient than @@ -1456,13 +1473,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // type-checking closure types are in local tables only. if !self.in_progress_tables.is_some() || !ty.has_closure_types() { if !(param_env, ty).has_local_value() { - return ty.is_copy_modulo_regions(self.tcx.global_tcx(), param_env, span); + return ty.is_copy_modulo_regions(self.tcx, param_env, span); } } - let copy_def_id = self.tcx.require_lang_item(lang_items::CopyTraitLangItem); + let copy_def_id = self.tcx.require_lang_item(lang_items::CopyTraitLangItem, None); - // this can get called from typeck (by euv), and moves_by_default + // This can get called from typeck (by euv), and `moves_by_default` // rightly refuses to work with inference variables, but // moves_by_default has a cache, which we want to use in other // cases. @@ -1475,23 +1492,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn closure_kind( &self, closure_def_id: DefId, - closure_substs: ty::ClosureSubsts<'tcx>, + closure_substs: SubstsRef<'tcx>, ) -> Option { - let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self.tcx); + let closure_kind_ty = closure_substs.as_closure().kind_ty(closure_def_id, self.tcx); let closure_kind_ty = self.shallow_resolve(closure_kind_ty); closure_kind_ty.to_opt_closure_kind() } - /// Obtain the signature of a closure. For closures, unlike + /// Obtains the signature of a closure. For closures, unlike /// `tcx.fn_sig(def_id)`, this method will work during the /// type-checking of the enclosing function and return the closure /// signature in its partially inferred state. pub fn closure_sig( &self, def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, + substs: SubstsRef<'tcx>, ) -> ty::PolyFnSig<'tcx> { - let closure_sig_ty = substs.closure_sig_ty(def_id, self.tcx); + let closure_sig_ty = substs.as_closure().sig_ty(def_id, self.tcx); let closure_sig_ty = self.shallow_resolve(closure_sig_ty); closure_sig_ty.fn_sig(self.tcx) } @@ -1558,12 +1575,11 @@ impl<'a, 'tcx> ShallowResolver<'a, 'tcx> { ShallowResolver { infcx } } - // We have this force-inlined variant of `shallow_resolve` for the one - // callsite that is extremely hot. All other callsites use the normal - // variant. - #[inline(always)] - pub fn inlined_shallow_resolve(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> { - match typ.sty { + /// If `typ` is a type variable of some kind, resolve it one level + /// (but do not resolve types found in the result). If `typ` is + /// not a type variable, just return it unmodified. + pub fn shallow_resolve(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> { + match typ.kind { ty::Infer(ty::TyVar(v)) => { // Not entirely obvious: if `typ` is a type variable, // it can be resolved to an int/float variable, which @@ -1597,6 +1613,43 @@ impl<'a, 'tcx> ShallowResolver<'a, 'tcx> { _ => typ, } } + + // `resolver.shallow_resolve_changed(ty)` is equivalent to + // `resolver.shallow_resolve(ty) != ty`, but more efficient. It's always + // inlined, despite being large, because it has only two call sites that + // are extremely hot. + #[inline(always)] + pub fn shallow_resolve_changed(&mut self, typ: Ty<'tcx>) -> bool { + match typ.kind { + ty::Infer(ty::TyVar(v)) => { + use self::type_variable::TypeVariableValue; + + // See the comment in `shallow_resolve()`. + match self.infcx.type_variables.borrow_mut().inlined_probe(v) { + TypeVariableValue::Known { value: t } => self.fold_ty(t) != typ, + TypeVariableValue::Unknown { .. } => false, + } + } + + ty::Infer(ty::IntVar(v)) => { + match self.infcx.int_unification_table.borrow_mut().inlined_probe_value(v) { + Some(v) => v.to_type(self.infcx.tcx) != typ, + None => false, + } + } + + ty::Infer(ty::FloatVar(v)) => { + // Not `inlined_probe_value(v)` because this call site is colder. + match self.infcx.float_unification_table.borrow_mut().probe_value(v) { + Some(v) => v.to_type(self.infcx.tcx) != typ, + None => false, + } + } + + _ => false, + } + } + } impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> { @@ -1605,7 +1658,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.inlined_shallow_resolve(ty) + self.shallow_resolve(ty) } fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs index 5d521def65b0b..4649f3f9567e7 100644 --- a/src/librustc/infer/nll_relate/mod.rs +++ b/src/librustc/infer/nll_relate/mod.rs @@ -26,7 +26,7 @@ use crate::traits::DomainGoal; use crate::ty::error::TypeError; use crate::ty::fold::{TypeFoldable, TypeVisitor}; use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use crate::ty::subst::Kind; +use crate::ty::subst::GenericArg; use crate::ty::{self, Ty, TyCtxt, InferConst}; use crate::mir::interpret::ConstValue; use rustc_data_structures::fx::FxHashMap; @@ -93,7 +93,7 @@ pub trait TypeRelatingDelegate<'tcx> { /// we will invoke this method to instantiate `'a` with an /// inference variable (though `'b` would be instantiated first, /// as a placeholder). - fn next_existential_region_var(&mut self) -> ty::Region<'tcx>; + fn next_existential_region_var(&mut self, was_placeholder: bool) -> ty::Region<'tcx>; /// Creates a new region variable representing a /// higher-ranked region that is instantiated universally. @@ -124,7 +124,7 @@ pub trait TypeRelatingDelegate<'tcx> { #[derive(Clone, Debug)] struct ScopesAndKind<'tcx> { scopes: Vec>, - kind: Kind<'tcx>, + kind: GenericArg<'tcx>, } #[derive(Clone, Debug, Default)] @@ -193,7 +193,7 @@ where let placeholder = ty::PlaceholderRegion { universe, name: br }; delegate.next_placeholder_region(placeholder) } else { - delegate.next_existential_region_var() + delegate.next_existential_region_var(true) } } }; @@ -274,7 +274,7 @@ where use crate::traits::WhereClause; use syntax_pos::DUMMY_SP; - match value_ty.sty { + match value_ty.kind { ty::Projection(other_projection_ty) => { let var = self.infcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, @@ -328,7 +328,7 @@ where // This only presently applies to chalk integration, as NLL // doesn't permit type variables to appear on both sides (and // doesn't use lazy norm). - match value_ty.sty { + match value_ty.kind { ty::Infer(ty::TyVar(value_vid)) => { // Two type variables: just equate them. self.infcx @@ -548,7 +548,7 @@ where b = self.infcx.shallow_resolve(b); } - match (&a.sty, &b.sty) { + match (&a.kind, &b.kind) { (_, &ty::Infer(ty::TyVar(vid))) => { if D::forbid_inference_vars() { // Forbid inference variables in the RHS. @@ -878,7 +878,7 @@ where debug!("TypeGeneralizer::tys(a={:?})", a); - match a.sty { + match a.kind { ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) if D::forbid_inference_vars() => { diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 5c62f76e3bb31..bd19a002fe8b7 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -7,7 +7,7 @@ use crate::middle::region; use crate::mir::interpret::ConstValue; use crate::traits::{self, PredicateObligation}; use crate::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; -use crate::ty::subst::{InternalSubsts, Kind, SubstsRef, UnpackedKind}; +use crate::ty::subst::{InternalSubsts, GenericArg, SubstsRef, GenericArgKind}; use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt}; use crate::util::nodemap::DefIdMap; use errors::DiagnosticBuilder; @@ -127,8 +127,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)> { debug!( "instantiate_opaque_types(value={:?}, parent_def_id={:?}, body_id={:?}, \ - param_env={:?})", - value, parent_def_id, body_id, param_env, + param_env={:?}, value_span={:?})", + value, parent_def_id, body_id, param_env, value_span, ); let mut instantiator = Instantiator { infcx: self, @@ -561,16 +561,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { def_id, instantiated_ty ); - let gcx = self.tcx.global_tcx(); - // Use substs to build up a reverse map from regions to their // identity mappings. This is necessary because of `impl // Trait` lifetimes are computed by replacing existing // lifetimes with 'static and remapping only those used in the // `impl Trait` return type, resulting in the parameters // shifting. - let id_substs = InternalSubsts::identity_for_item(gcx, def_id); - let map: FxHashMap, Kind<'tcx>> = opaque_defn + let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id); + let map: FxHashMap, GenericArg<'tcx>> = opaque_defn .substs .iter() .enumerate() @@ -720,27 +718,27 @@ where return false; // keep visiting } - match ty.sty { + match ty.kind { ty::Closure(def_id, ref substs) => { // Skip lifetime parameters of the enclosing item(s) - for upvar_ty in substs.upvar_tys(def_id, self.tcx) { + for upvar_ty in substs.as_closure().upvar_tys(def_id, self.tcx) { upvar_ty.visit_with(self); } - substs.closure_sig_ty(def_id, self.tcx).visit_with(self); + substs.as_closure().sig_ty(def_id, self.tcx).visit_with(self); } ty::Generator(def_id, ref substs, _) => { // Skip lifetime parameters of the enclosing item(s) // Also skip the witness type, because that has no free regions. - for upvar_ty in substs.upvar_tys(def_id, self.tcx) { + for upvar_ty in substs.as_generator().upvar_tys(def_id, self.tcx) { upvar_ty.visit_with(self); } - substs.return_ty(def_id, self.tcx).visit_with(self); - substs.yield_ty(def_id, self.tcx).visit_with(self); + substs.as_generator().return_ty(def_id, self.tcx).visit_with(self); + substs.as_generator().yield_ty(def_id, self.tcx).visit_with(self); } _ => { ty.super_visit_with(self); @@ -759,7 +757,7 @@ struct ReverseMapper<'tcx> { tainted_by_errors: bool, opaque_type_def_id: DefId, - map: FxHashMap, Kind<'tcx>>, + map: FxHashMap, GenericArg<'tcx>>, map_missing_regions_to_empty: bool, /// initially `Some`, set to `None` once error has been reported @@ -774,7 +772,7 @@ impl ReverseMapper<'tcx> { tcx: TyCtxt<'tcx>, tainted_by_errors: bool, opaque_type_def_id: DefId, - map: FxHashMap, Kind<'tcx>>, + map: FxHashMap, GenericArg<'tcx>>, hidden_ty: Ty<'tcx>, span: Span, ) -> Self { @@ -789,7 +787,10 @@ impl ReverseMapper<'tcx> { } } - fn fold_kind_mapping_missing_regions_to_empty(&mut self, kind: Kind<'tcx>) -> Kind<'tcx> { + fn fold_kind_mapping_missing_regions_to_empty( + &mut self, + kind: GenericArg<'tcx>, + ) -> GenericArg<'tcx> { assert!(!self.map_missing_regions_to_empty); self.map_missing_regions_to_empty = true; let kind = kind.fold_with(self); @@ -797,7 +798,7 @@ impl ReverseMapper<'tcx> { kind } - fn fold_kind_normally(&mut self, kind: Kind<'tcx>) -> Kind<'tcx> { + fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { assert!(!self.map_missing_regions_to_empty); kind.fold_with(self) } @@ -822,7 +823,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { let generics = self.tcx().generics_of(self.opaque_type_def_id); match self.map.get(&r.into()).map(|k| k.unpack()) { - Some(UnpackedKind::Lifetime(r1)) => r1, + Some(GenericArgKind::Lifetime(r1)) => r1, Some(u) => panic!("region mapped to unexpected kind: {:?}", u), None if generics.parent.is_some() => { if !self.map_missing_regions_to_empty && !self.tainted_by_errors { @@ -851,13 +852,13 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { ) .emit(); - self.tcx().global_tcx().mk_region(ty::ReStatic) + self.tcx().mk_region(ty::ReStatic) }, } } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.sty { + match ty.kind { ty::Closure(def_id, substs) => { // I am a horrible monster and I pray for death. When // we encounter a closure here, it is always a closure @@ -885,7 +886,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { let generics = self.tcx.generics_of(def_id); let substs = - self.tcx.mk_substs(substs.substs.iter().enumerate().map(|(index, &kind)| { + self.tcx.mk_substs(substs.iter().enumerate().map(|(index, &kind)| { if index < generics.parent_count { // Accommodate missing regions in the parent kinds... self.fold_kind_mapping_missing_regions_to_empty(kind) @@ -895,13 +896,13 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { } })); - self.tcx.mk_closure(def_id, ty::ClosureSubsts { substs }) + self.tcx.mk_closure(def_id, substs) } ty::Generator(def_id, substs, movability) => { let generics = self.tcx.generics_of(def_id); let substs = - self.tcx.mk_substs(substs.substs.iter().enumerate().map(|(index, &kind)| { + self.tcx.mk_substs(substs.iter().enumerate().map(|(index, &kind)| { if index < generics.parent_count { // Accommodate missing regions in the parent kinds... self.fold_kind_mapping_missing_regions_to_empty(kind) @@ -911,7 +912,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { } })); - self.tcx.mk_generator(def_id, ty::GeneratorSubsts { substs }, movability) + self.tcx.mk_generator(def_id, substs, movability) } ty::Param(..) => { @@ -919,7 +920,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { match self.map.get(&ty.into()).map(|k| k.unpack()) { // Found it in the substitution list; replace with the parameter from the // opaque type. - Some(UnpackedKind::Type(t1)) => t1, + Some(GenericArgKind::Type(t1)) => t1, Some(u) => panic!("type mapped to unexpected kind: {:?}", u), None => { self.tcx.sess @@ -949,7 +950,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { match self.map.get(&ct.into()).map(|k| k.unpack()) { // Found it in the substitution list, replace with the parameter from the // opaque type. - Some(UnpackedKind::Const(c1)) => c1, + Some(GenericArgKind::Const(c1)) => c1, Some(u) => panic!("const mapped to unexpected kind: {:?}", u), None => { self.tcx.sess @@ -988,7 +989,9 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { value.fold_with(&mut BottomUpFolder { tcx, ty_op: |ty| { - if let ty::Opaque(def_id, substs) = ty.sty { + if ty.references_error() { + return tcx.types.err; + } else if let ty::Opaque(def_id, substs) = ty.kind { // Check that this is `impl Trait` type is // declared by `parent_def_id` -- i.e., one whose // value we are inferring. At present, this is @@ -1031,7 +1034,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { .local_def_id(opaque_parent_hir_id) }; let (in_definition_scope, origin) = match tcx.hir().find(opaque_hir_id) { - Some(Node::Item(item)) => match item.node { + Some(Node::Item(item)) => match item.kind { // Anonymous `impl Trait` hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(parent), @@ -1055,7 +1058,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { (def_scope_default(), hir::OpaqueTyOrigin::TypeAlias) } }, - Some(Node::ImplItem(item)) => match item.node { + Some(Node::ImplItem(item)) => match item.kind { hir::ImplItemKind::OpaqueTy(_) => ( may_define_opaque_type( tcx, @@ -1108,9 +1111,11 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { // Use the same type variable if the exact same opaque type appears more // than once in the return type (e.g., if it's passed to a type alias). if let Some(opaque_defn) = self.opaque_types.get(&def_id) { + debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty); return opaque_defn.concrete_ty; } let span = tcx.def_span(def_id); + debug!("fold_opaque_ty {:?} {:?}", self.value_span, span); let ty_var = infcx .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); @@ -1153,6 +1158,15 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { ); debug!("instantiate_opaque_types: ty_var={:?}", ty_var); + for predicate in &bounds.predicates { + if let ty::Predicate::Projection(projection) = &predicate { + if projection.skip_binder().ty.references_error() { + // No point on adding these obligations since there's a type error involved. + return ty_var; + } + } + } + self.obligations.reserve(bounds.predicates.len()); for predicate in bounds.predicates { // Change the predicate to refer to the type variable, @@ -1199,7 +1213,7 @@ pub fn may_define_opaque_type( let mut hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); // Named opaque types can be defined by any siblings or children of siblings. - let scope = tcx.hir().get_defining_scope(opaque_hir_id).expect("could not get defining scope"); + let scope = tcx.hir().get_defining_scope(opaque_hir_id); // We walk up the node tree until we hit the root or the scope of the opaque type. while hir_id != scope && hir_id != hir::CRATE_HIR_ID { hir_id = tcx.hir().get_parent_item(hir_id); diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index e1470e4ef0232..f7806188775fa 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -67,7 +67,7 @@ use crate::hir; use crate::traits::ObligationCause; use crate::ty::outlives::Component; use crate::ty::{self, Region, Ty, TyCtxt, TypeFoldable}; -use crate::ty::subst::UnpackedKind; +use crate::ty::subst::GenericArgKind; impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// Registers that the given region obligation must be resolved @@ -403,7 +403,7 @@ where // 'a` in the environment but `trait Foo<'b> { type Item: 'b // }` in the trait definition. approx_env_bounds.retain(|bound| { - match bound.0.sty { + match bound.0.kind { ty::Projection(projection_ty) => { self.verify_bound.projection_declared_bounds_from_trait(projection_ty) .all(|r| r != bound.1) @@ -433,13 +433,13 @@ where for k in projection_ty.substs { match k.unpack() { - UnpackedKind::Lifetime(lt) => { + GenericArgKind::Lifetime(lt) => { self.delegate.push_sub_region_constraint(origin.clone(), region, lt); } - UnpackedKind::Type(ty) => { + GenericArgKind::Type(ty) => { self.type_must_outlive(origin.clone(), ty, region); } - UnpackedKind::Const(_) => { + GenericArgKind::Const(_) => { // Const parameters don't impose constraints. } } diff --git a/src/librustc/infer/outlives/verify.rs b/src/librustc/infer/outlives/verify.rs index f23e52fcfe499..3110b027c5bbe 100644 --- a/src/librustc/infer/outlives/verify.rs +++ b/src/librustc/infer/outlives/verify.rs @@ -44,7 +44,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { } fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { - match ty.sty { + match ty.kind { ty::Param(p) => self.param_bound(p), ty::Projection(data) => self.projection_bound(data), _ => self.recursive_type_bound(ty), @@ -87,7 +87,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx); let erased_projection_ty = self.tcx.erase_regions(&projection_ty); self.declared_generic_bounds_from_env_with_compare_fn(|ty| { - if let ty::Projection(..) = ty.sty { + if let ty::Projection(..) = ty.kind { let erased_ty = self.tcx.erase_regions(&ty); erased_ty == erased_projection_ty } else { diff --git a/src/librustc/infer/region_constraints/leak_check.rs b/src/librustc/infer/region_constraints/leak_check.rs index 0c83bbc1e5394..3d069425685c7 100644 --- a/src/librustc/infer/region_constraints/leak_check.rs +++ b/src/librustc/infer/region_constraints/leak_check.rs @@ -14,9 +14,11 @@ impl<'tcx> RegionConstraintCollector<'tcx> { /// retain the older (arguably incorrect) behavior of the /// compiler. /// - /// NB. The use of snapshot here is mostly an efficiency thing -- - /// we could search *all* region constraints, but that'd be a - /// bigger set and the data structures are not setup for that. If + /// NB. Although `_snapshot` isn't used, it's passed in to prove + /// that we are in a snapshot, which guarantees that we can just + /// search the "undo log" for edges. This is mostly an efficiency + /// thing -- we could search *all* region constraints, but that'd be + /// a bigger set and the data structures are not setup for that. If /// we wind up keeping some form of this check long term, it would /// probably be better to remove the snapshot parameter and to /// refactor the constraint set. diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index 21904edb309cb..b4b4d1fe3e1f6 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -7,7 +7,7 @@ use super::unify_key; use super::{MiscVariable, RegionVariableOrigin, SubregionOrigin}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::vec::IndexVec; use rustc_data_structures::sync::Lrc; use rustc_data_structures::unify as ut; use crate::hir::def_id::DefId; diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs index 7e553d7666b22..2db18674e2f53 100644 --- a/src/librustc/infer/resolve.rs +++ b/src/librustc/infer/resolve.rs @@ -118,7 +118,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { let t = self.infcx.shallow_resolve(t); if t.has_infer_types() { - if let ty::Infer(infer_ty) = t.sty { + if let ty::Infer(infer_ty) = t.kind { // Since we called `shallow_resolve` above, this must // be an (as yet...) unresolved inference variable. let ty_var_span = @@ -188,7 +188,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { // defaulted tuples. } else { let t = self.infcx.shallow_resolve(t); - match t.sty { + match t.kind { ty::Infer(ty::TyVar(vid)) => { self.err = Some(FixupError::UnresolvedTy(vid)); self.tcx().types.err diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index cd1d206b5fca1..21c847e80f413 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -1,13 +1,11 @@ use super::SubregionOrigin; -use super::combine::{CombineFields, RelationDir, const_unification_error}; +use super::combine::{CombineFields, RelationDir}; use crate::traits::Obligation; -use crate::ty::{self, Ty, TyCtxt, InferConst}; +use crate::ty::{self, Ty, TyCtxt}; use crate::ty::TyVar; use crate::ty::fold::TypeFoldable; use crate::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; -use crate::infer::unify_key::replace_if_possible; -use crate::mir::interpret::ConstValue; use std::mem; /// Ensures `a` is made a subtype of `b`. Returns `a` on success. @@ -73,7 +71,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { let infcx = self.fields.infcx; let a = infcx.type_variables.borrow_mut().replace_if_possible(a); let b = infcx.type_variables.borrow_mut().replace_if_possible(b); - match (&a.sty, &b.sty) { + match (&a.kind, &b.kind) { (&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => { // Shouldn't have any LBR here, so we can safely put // this under a binder below without fear of accidental @@ -130,7 +128,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { // FIXME -- we have more fine-grained information available // from the "cause" field, we could perhaps give more tailored // error messages. - let origin = SubregionOrigin::Subtype(self.fields.trace.clone()); + let origin = SubregionOrigin::Subtype(box self.fields.trace.clone()); self.fields.infcx.borrow_region_constraints() .make_subregion(origin, a, b); @@ -142,41 +140,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>, ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - debug!("{}.consts({:?}, {:?})", self.tag(), a, b); - if a == b { return Ok(a); } - - let infcx = self.fields.infcx; - let a = replace_if_possible(infcx.const_unification_table.borrow_mut(), a); - let b = replace_if_possible(infcx.const_unification_table.borrow_mut(), b); - - // Consts can only be equal or unequal to each other: there's no subtyping - // relation, so we're just going to perform equating here instead. - let a_is_expected = self.a_is_expected(); - match (a.val, b.val) { - (ConstValue::Infer(InferConst::Var(a_vid)), - ConstValue::Infer(InferConst::Var(b_vid))) => { - infcx.const_unification_table - .borrow_mut() - .unify_var_var(a_vid, b_vid) - .map_err(|e| const_unification_error(a_is_expected, e))?; - return Ok(a); - } - - (ConstValue::Infer(InferConst::Var(a_id)), _) => { - self.fields.infcx.unify_const_variable(a_is_expected, a_id, b)?; - return Ok(a); - } - - (_, ConstValue::Infer(InferConst::Var(b_id))) => { - self.fields.infcx.unify_const_variable(!a_is_expected, b_id, a)?; - return Ok(a); - } - - _ => {} - } - - self.fields.infcx.super_combine_consts(self, a, b)?; - Ok(a) + self.fields.infcx.super_combine_consts(self, a, b) } fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index e30e86998a8c6..ce1b54bb1c81d 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -234,14 +234,20 @@ impl<'tcx> TypeVariableTable<'tcx> { /// Retrieves the type to which `vid` has been instantiated, if /// any. pub fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { - self.eq_relations.probe_value(vid) + self.inlined_probe(vid) + } + + /// An always-inlined variant of `probe`, for very hot call sites. + #[inline(always)] + pub fn inlined_probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { + self.eq_relations.inlined_probe_value(vid) } /// If `t` is a type-inference variable, and it has been /// instantiated, then return the with which it was /// instantiated. Otherwise, returns `t`. pub fn replace_if_possible(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.sty { + match t.kind { ty::Infer(ty::TyVar(v)) => { match self.probe(v) { TypeVariableValue::Unknown { .. } => t, diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 8e0581b41ef7a..197ca191a5d06 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -35,7 +35,6 @@ #![feature(const_transmute)] #![feature(core_intrinsics)] #![feature(drain_filter)] -#![feature(inner_deref)] #![cfg_attr(windows, feature(libc))] #![feature(never_type)] #![feature(exhaustive_patterns)] @@ -45,7 +44,6 @@ #![feature(non_exhaustive)] #![feature(optin_builtin_traits)] #![feature(range_is_empty)] -#![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] #![feature(specialization)] #![feature(unboxed_closures)] @@ -60,13 +58,13 @@ #![feature(crate_visibility_modifier)] #![feature(proc_macro_hygiene)] #![feature(log_syntax)] -#![feature(mem_take)] +#![feature(associated_type_bounds)] +#![feature(rustc_attrs)] #![recursion_limit="512"] #[macro_use] extern crate bitflags; extern crate getopts; -#[macro_use] extern crate lazy_static; #[macro_use] extern crate scoped_tls; #[cfg(windows)] extern crate libc; @@ -86,8 +84,6 @@ mod tests; #[macro_use] mod macros; -// N.B., this module needs to be declared first so diagnostics are -// registered before they are used. pub mod error_codes; #[macro_use] @@ -95,7 +91,6 @@ pub mod query; #[macro_use] pub mod arena; -pub mod cfg; pub mod dep_graph; pub mod hir; pub mod ich; @@ -103,18 +98,14 @@ pub mod infer; pub mod lint; pub mod middle { - pub mod borrowck; pub mod expr_use_visitor; pub mod cstore; - pub mod dead; pub mod dependency_format; - pub mod entry; + pub mod diagnostic_items; pub mod exported_symbols; pub mod free_region; - pub mod intrinsicck; pub mod lib_features; pub mod lang_items; - pub mod liveness; pub mod mem_categorization; pub mod privacy; pub mod reachable; @@ -140,6 +131,3 @@ pub mod util { // Allows macros to refer to this crate as `::rustc` extern crate self as rustc; - -// Build the diagnostics array at the end so that the metadata includes error use sites. -__build_diagnostic_array! { librustc, DIAGNOSTICS } diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 6d9a6bb77dd55..5ca474a8b1d91 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -7,7 +7,7 @@ use crate::lint::{LintPass, LateLintPass, LintArray}; use crate::middle::stability; use crate::session::Session; -use errors::{Applicability, DiagnosticBuilder}; +use errors::{Applicability, DiagnosticBuilder, pluralise}; use syntax::ast; use syntax::source_map::Span; use syntax::symbol::Symbol; @@ -368,6 +368,12 @@ pub mod parser { Allow, "possible meta-variable misuse at macro definition" } + + declare_lint! { + pub INCOMPLETE_INCLUDE, + Deny, + "trailing content in included file" + } } declare_lint! { @@ -395,6 +401,12 @@ declare_lint! { "reservation of a two-phased borrow conflicts with other shared borrows" } +declare_lint! { + pub SOFT_UNSTABLE, + Deny, + "a feature gate that doesn't break dependent crates" +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -460,6 +472,7 @@ declare_lint_pass! { NESTED_IMPL_TRAIT, MUTABLE_BORROW_RESERVATION_CONFLICT, INDIRECT_STRUCTURAL_MATCH, + SOFT_UNSTABLE, ] } @@ -517,7 +530,7 @@ pub(crate) fn add_elided_lifetime_in_path_suggestion( }; db.span_suggestion( replace_span, - &format!("indicate the anonymous lifetime{}", if n >= 2 { "s" } else { "" }), + &format!("indicate the anonymous lifetime{}", pluralise!(n)), suggestion, Applicability::MachineApplicable ); diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index de812410e8bd8..fa73a3c6c4628 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -16,32 +16,32 @@ use self::TargetLint::*; -use std::slice; -use rustc_data_structures::sync::{ReadGuard, Lock, ParallelIterator, join, par_iter}; +use crate::hir; +use crate::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use crate::hir::intravisit as hir_visit; +use crate::hir::intravisit::Visitor; +use crate::hir::map::{definitions::DisambiguatedDefPathData, DefPathData}; use crate::lint::{EarlyLintPass, LateLintPass, EarlyLintPassObject, LateLintPassObject}; use crate::lint::{LintArray, Level, Lint, LintId, LintPass, LintBuffer}; use crate::lint::builtin::BuiltinLintDiagnostics; use crate::lint::levels::{LintLevelSets, LintLevelsBuilder}; use crate::middle::privacy::AccessLevels; -use rustc_serialize::{Decoder, Decodable, Encoder, Encodable}; use crate::session::{config, early_error, Session}; -use crate::ty::{self, print::Printer, subst::Kind, TyCtxt, Ty}; +use crate::ty::{self, print::Printer, subst::GenericArg, TyCtxt, Ty}; use crate::ty::layout::{LayoutError, LayoutOf, TyLayout}; use crate::util::nodemap::FxHashMap; use crate::util::common::time; +use errors::DiagnosticBuilder; +use std::slice; use std::default::Default as StdDefault; +use rustc_data_structures::sync::{ReadGuard, Lock, ParallelIterator, join, par_iter}; +use rustc_serialize::{Decoder, Decodable, Encoder, Encodable}; use syntax::ast; use syntax::edition; -use syntax_pos::{MultiSpan, Span, symbol::{LocalInternedString, Symbol}}; -use errors::DiagnosticBuilder; -use crate::hir; -use crate::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use crate::hir::intravisit as hir_visit; -use crate::hir::intravisit::Visitor; -use crate::hir::map::{definitions::DisambiguatedDefPathData, DefPathData}; use syntax::util::lev_distance::find_best_match_for_name; use syntax::visit as ast_visit; +use syntax_pos::{MultiSpan, Span, symbol::Symbol}; /// Information about the registered lints. /// @@ -405,7 +405,7 @@ impl LintStore { pub fn check_lint_name( &self, lint_name: &str, - tool_name: Option, + tool_name: Option, ) -> CheckLintNameResult<'_> { let complete_name = if let Some(tool_name) = tool_name { format!("{}::{}", tool_name, lint_name) @@ -829,7 +829,7 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> { trait_ref: Option>, ) -> Result { if trait_ref.is_none() { - if let ty::Adt(def, substs) = self_ty.sty { + if let ty::Adt(def, substs) = self_ty.kind { return self.print_def_path(def.did, substs); } } @@ -882,7 +882,7 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> { fn path_generic_args( self, print_prefix: impl FnOnce(Self) -> Result, - _args: &[Kind<'tcx>], + _args: &[GenericArg<'tcx>], ) -> Result { print_prefix(self) } @@ -966,10 +966,10 @@ for LateContextAndPass<'a, 'tcx, T> { self.context.tables = old_tables; } - fn visit_arg(&mut self, arg: &'tcx hir::Arg) { - self.with_lint_attrs(arg.hir_id, &arg.attrs, |cx| { - lint_callback!(cx, check_arg, arg); - hir_visit::walk_arg(cx, arg); + fn visit_param(&mut self, param: &'tcx hir::Param) { + self.with_lint_attrs(param.hir_id, ¶m.attrs, |cx| { + lint_callback!(cx, check_param, param); + hir_visit::walk_param(cx, param); }); } @@ -981,7 +981,7 @@ for LateContextAndPass<'a, 'tcx, T> { fn visit_item(&mut self, it: &'tcx hir::Item) { let generics = self.context.generics.take(); - self.context.generics = it.node.generics(); + self.context.generics = it.kind.generics(); self.with_lint_attrs(it.hir_id, &it.attrs, |cx| { cx.with_param_env(it.hir_id, |cx| { lint_callback!(cx, check_item, it); @@ -1040,13 +1040,13 @@ for LateContextAndPass<'a, 'tcx, T> { fn visit_variant_data(&mut self, s: &'tcx hir::VariantData, - name: ast::Name, - g: &'tcx hir::Generics, - item_id: hir::HirId, + _: ast::Name, + _: &'tcx hir::Generics, + _: hir::HirId, _: Span) { - lint_callback!(self, check_struct_def, s, name, g, item_id); + lint_callback!(self, check_struct_def, s); hir_visit::walk_struct_def(self, s); - lint_callback!(self, check_struct_def_post, s, name, g, item_id); + lint_callback!(self, check_struct_def_post, s); } fn visit_struct_field(&mut self, s: &'tcx hir::StructField) { @@ -1060,10 +1060,10 @@ for LateContextAndPass<'a, 'tcx, T> { v: &'tcx hir::Variant, g: &'tcx hir::Generics, item_id: hir::HirId) { - self.with_lint_attrs(v.node.id, &v.node.attrs, |cx| { - lint_callback!(cx, check_variant, v, g); + self.with_lint_attrs(v.id, &v.attrs, |cx| { + lint_callback!(cx, check_variant, v); hir_visit::walk_variant(cx, v, g, item_id); - lint_callback!(cx, check_variant_post, v, g); + lint_callback!(cx, check_variant_post, v); }) } @@ -1163,10 +1163,10 @@ for LateContextAndPass<'a, 'tcx, T> { } impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> { - fn visit_arg(&mut self, arg: &'a ast::Arg) { - self.with_lint_attrs(arg.id, &arg.attrs, |cx| { - run_early_pass!(cx, check_arg, arg); - ast_visit::walk_arg(cx, arg); + fn visit_param(&mut self, param: &'a ast::Param) { + self.with_lint_attrs(param.id, ¶m.attrs, |cx| { + run_early_pass!(cx, check_param, param); + ast_visit::walk_param(cx, param); }); } @@ -1214,18 +1214,13 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> run_early_pass!(self, check_fn_post, fk, decl, span, id); } - fn visit_variant_data(&mut self, - s: &'a ast::VariantData, - ident: ast::Ident, - g: &'a ast::Generics, - item_id: ast::NodeId, - _: Span) { - run_early_pass!(self, check_struct_def, s, ident, g, item_id); + fn visit_variant_data(&mut self, s: &'a ast::VariantData) { + run_early_pass!(self, check_struct_def, s); if let Some(ctor_hir_id) = s.ctor_id() { self.check_id(ctor_hir_id); } ast_visit::walk_struct_def(self, s); - run_early_pass!(self, check_struct_def_post, s, ident, g, item_id); + run_early_pass!(self, check_struct_def_post, s); } fn visit_struct_field(&mut self, s: &'a ast::StructField) { @@ -1235,11 +1230,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> }) } - fn visit_variant(&mut self, v: &'a ast::Variant, g: &'a ast::Generics, item_id: ast::NodeId) { - self.with_lint_attrs(item_id, &v.node.attrs, |cx| { - run_early_pass!(cx, check_variant, v, g); - ast_visit::walk_variant(cx, v, g, item_id); - run_early_pass!(cx, check_variant_post, v, g); + fn visit_variant(&mut self, v: &'a ast::Variant) { + self.with_lint_attrs(v.id, &v.attrs, |cx| { + run_early_pass!(cx, check_variant, v); + ast_visit::walk_variant(cx, v); + run_early_pass!(cx, check_variant_post, v); }) } @@ -1345,7 +1340,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> // part of `walk_mac`, and (b) we should be calling // `visit_path`, *but* that would require a `NodeId`, and I // want to get #53686 fixed quickly. -nmatsakis - ast_visit::walk_path(self, &mac.node.path); + ast_visit::walk_path(self, &mac.path); run_early_pass!(self, check_mac, mac); } @@ -1355,7 +1350,7 @@ struct LateLintPassObjects<'a> { lints: &'a mut [LateLintPassObject], } -#[cfg_attr(not(bootstrap), allow(rustc::lint_pass_impl_without_macro))] +#[allow(rustc::lint_pass_impl_without_macro)] impl LintPass for LateLintPassObjects<'_> { fn name(&self) -> &'static str { panic!() @@ -1515,7 +1510,7 @@ pub fn check_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>( time(tcx.sess, "module lints", || { // Run per-module lints par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| { - tcx.ensure().lint_mod(tcx.hir().local_def_id_from_node_id(module)); + tcx.ensure().lint_mod(tcx.hir().local_def_id(module)); }); }); }); @@ -1525,7 +1520,7 @@ struct EarlyLintPassObjects<'a> { lints: &'a mut [EarlyLintPassObject], } -#[cfg_attr(not(bootstrap), allow(rustc::lint_pass_impl_without_macro))] +#[allow(rustc::lint_pass_impl_without_macro)] impl LintPass for EarlyLintPassObjects<'_> { fn name(&self) -> &'static str { panic!() diff --git a/src/librustc/lint/internal.rs b/src/librustc/lint/internal.rs index 0b514f5927d30..a08722e940295 100644 --- a/src/librustc/lint/internal.rs +++ b/src/librustc/lint/internal.rs @@ -9,7 +9,6 @@ use errors::Applicability; use rustc_data_structures::fx::FxHashMap; use syntax::ast::{Ident, Item, ItemKind}; use syntax::symbol::{sym, Symbol}; -use syntax_pos::ExpnInfo; declare_tool_lint! { pub rustc::DEFAULT_HASH_TYPES, @@ -23,7 +22,7 @@ pub struct DefaultHashTypes { impl DefaultHashTypes { // we are allowed to use `HashMap` and `HashSet` as identifiers for implementing the lint itself - #[cfg_attr(not(bootstrap), allow(rustc::default_hash_types))] + #[allow(rustc::default_hash_types)] pub fn new() -> Self { let mut map = FxHashMap::default(); map.insert(sym::HashMap, sym::FxHashMap); @@ -95,7 +94,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyTyKind { } fn check_ty(&mut self, cx: &LateContext<'_, '_>, ty: &'tcx Ty) { - match &ty.node { + match &ty.kind { TyKind::Path(qpath) => { if let QPath::Resolved(_, path) = qpath { if let Some(last) = path.segments.iter().last() { @@ -108,7 +107,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyTyKind { .help("try using `Ty` instead") .emit(); } else { - if ty.span.ctxt().outer_expn_info().is_some() { + if ty.span.from_expansion() { return; } if let Some(t) = is_ty_or_ty_ctxt(cx, ty) { @@ -160,29 +159,23 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyTyKind { } fn lint_ty_kind_usage(cx: &LateContext<'_, '_>, segment: &PathSegment) -> bool { - if segment.ident.name == sym::TyKind { - if let Some(res) = segment.res { - if let Some(did) = res.opt_def_id() { - return cx.match_def_path(did, TYKIND_PATH); - } + if let Some(res) = segment.res { + if let Some(did) = res.opt_def_id() { + return cx.tcx.is_diagnostic_item(sym::TyKind, did); } } false } -const TYKIND_PATH: &[Symbol] = &[sym::rustc, sym::ty, sym::sty, sym::TyKind]; -const TY_PATH: &[Symbol] = &[sym::rustc, sym::ty, sym::Ty]; -const TYCTXT_PATH: &[Symbol] = &[sym::rustc, sym::ty, sym::context, sym::TyCtxt]; - fn is_ty_or_ty_ctxt(cx: &LateContext<'_, '_>, ty: &Ty) -> Option { - match &ty.node { + match &ty.kind { TyKind::Path(qpath) => { if let QPath::Resolved(_, path) = qpath { let did = path.res.opt_def_id()?; - if cx.match_def_path(did, TY_PATH) { + if cx.tcx.is_diagnostic_item(sym::Ty, did) { return Some(format!("Ty{}", gen_args(path.segments.last().unwrap()))); - } else if cx.match_def_path(did, TYCTXT_PATH) { + } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) { return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap()))); } } @@ -225,33 +218,23 @@ declare_lint_pass!(LintPassImpl => [LINT_PASS_IMPL_WITHOUT_MACRO]); impl EarlyLintPass for LintPassImpl { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if let ItemKind::Impl(_, _, _, _, Some(lint_pass), _, _) = &item.node { + if let ItemKind::Impl(_, _, _, _, Some(lint_pass), _, _) = &item.kind { if let Some(last) = lint_pass.path.segments.last() { if last.ident.name == sym::LintPass { - match &lint_pass.path.span.ctxt().outer_expn_info() { - Some(info) if is_lint_pass_expansion(info) => {} - _ => { - cx.struct_span_lint( - LINT_PASS_IMPL_WITHOUT_MACRO, - lint_pass.path.span, - "implementing `LintPass` by hand", - ) - .help("try using `declare_lint_pass!` or `impl_lint_pass!` instead") - .emit(); - } + let expn_data = lint_pass.path.span.ctxt().outer_expn_data(); + let call_site = expn_data.call_site; + if expn_data.kind.descr() != sym::impl_lint_pass && + call_site.ctxt().outer_expn_data().kind.descr() != sym::declare_lint_pass { + cx.struct_span_lint( + LINT_PASS_IMPL_WITHOUT_MACRO, + lint_pass.path.span, + "implementing `LintPass` by hand", + ) + .help("try using `declare_lint_pass!` or `impl_lint_pass!` instead") + .emit(); } } } } } } - -fn is_lint_pass_expansion(expn_info: &ExpnInfo) -> bool { - if expn_info.kind.descr() == sym::impl_lint_pass { - true - } else if let Some(info) = expn_info.call_site.ctxt().outer_expn_info() { - info.kind.descr() == sym::declare_lint_pass - } else { - false - } -} diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 139f4343117af..28afe9730a034 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -8,8 +8,7 @@ use crate::lint::{self, Lint, LintId, Level, LintSource}; use crate::session::Session; use crate::util::nodemap::FxHashMap; use errors::{Applicability, DiagnosticBuilder}; -use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, - StableHasher, StableHasherResult}; +use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher}; use syntax::ast; use syntax::attr; use syntax::feature_gate; @@ -218,7 +217,7 @@ impl<'a> LintLevelsBuilder<'a> { let mut reason = None; let tail_li = &metas[metas.len()-1]; if let Some(item) = tail_li.meta_item() { - match item.node { + match item.kind { ast::MetaItemKind::Word => {} // actual lint names handled later ast::MetaItemKind::NameValue(ref name_value) => { if item.path == sym::reason { @@ -226,7 +225,7 @@ impl<'a> LintLevelsBuilder<'a> { metas = &metas[0..metas.len()-1]; // FIXME (#55112): issue unused-attributes lint if we thereby // don't have any lint names (`#[level(reason = "foo")]`) - if let ast::LitKind::Str(rationale, _) = name_value.node { + if let ast::LitKind::Str(rationale, _) = name_value.kind { if !self.sess.features_untracked().lint_reasons { feature_gate::emit_feature_err( &self.sess.parse_sess, @@ -264,7 +263,7 @@ impl<'a> LintLevelsBuilder<'a> { let mut err = bad_attr(sp); let mut add_label = true; if let Some(item) = li.meta_item() { - if let ast::MetaItemKind::NameValue(_) = item.node { + if let ast::MetaItemKind::NameValue(_) = item.kind { if item.path == sym::reason { err.span_label(sp, "reason in lint attribute must come last"); add_label = false; @@ -291,7 +290,7 @@ impl<'a> LintLevelsBuilder<'a> { continue; } - Some(tool_ident.as_str()) + Some(tool_ident.name) } else { None }; @@ -526,9 +525,7 @@ impl LintLevelMap { impl<'a> HashStable> for LintLevelMap { #[inline] - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let LintLevelMap { ref sets, ref id_to_set, @@ -567,9 +564,7 @@ impl<'a> HashStable> for LintLevelMap { impl HashStable for LintId { #[inline] - fn hash_stable(&self, - hcx: &mut HCX, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { self.lint_name_raw().hash_stable(hcx, hasher); } } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 8ddf4603490a1..b31efc24e52d1 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -28,6 +28,7 @@ use crate::hir::intravisit; use crate::hir; use crate::lint::builtin::BuiltinLintDiagnostics; use crate::lint::builtin::parser::{ILL_FORMED_ATTRIBUTE_INPUT, META_VARIABLE_MISUSE}; +use crate::lint::builtin::parser::INCOMPLETE_INCLUDE; use crate::session::{Session, DiagnosticMessageId}; use crate::ty::TyCtxt; use crate::ty::query::Providers; @@ -83,6 +84,7 @@ impl Lint { match lint_id { BufferedEarlyLintId::IllFormedAttributeInput => ILL_FORMED_ATTRIBUTE_INPUT, BufferedEarlyLintId::MetaVariableMisuse => META_VARIABLE_MISUSE, + BufferedEarlyLintId::IncompleteInclude => INCOMPLETE_INCLUDE, } } @@ -206,7 +208,7 @@ macro_rules! declare_lint_pass { macro_rules! late_lint_methods { ($macro:path, $args:tt, [$hir:tt]) => ( $macro!($args, [$hir], [ - fn check_arg(a: &$hir hir::Arg); + fn check_param(a: &$hir hir::Param); fn check_body(a: &$hir hir::Body); fn check_body_post(a: &$hir hir::Body); fn check_name(a: Span, b: ast::Name); @@ -248,21 +250,11 @@ macro_rules! late_lint_methods { fn check_trait_item_post(a: &$hir hir::TraitItem); fn check_impl_item(a: &$hir hir::ImplItem); fn check_impl_item_post(a: &$hir hir::ImplItem); - fn check_struct_def( - a: &$hir hir::VariantData, - b: ast::Name, - c: &$hir hir::Generics, - d: hir::HirId - ); - fn check_struct_def_post( - a: &$hir hir::VariantData, - b: ast::Name, - c: &$hir hir::Generics, - d: hir::HirId - ); + fn check_struct_def(a: &$hir hir::VariantData); + fn check_struct_def_post(a: &$hir hir::VariantData); fn check_struct_field(a: &$hir hir::StructField); - fn check_variant(a: &$hir hir::Variant, b: &$hir hir::Generics); - fn check_variant_post(a: &$hir hir::Variant, b: &$hir hir::Generics); + fn check_variant(a: &$hir hir::Variant); + fn check_variant_post(a: &$hir hir::Variant); fn check_lifetime(a: &$hir hir::Lifetime); fn check_path(a: &$hir hir::Path, b: hir::HirId); fn check_attribute(a: &$hir ast::Attribute); @@ -359,7 +351,7 @@ macro_rules! declare_combined_late_lint_pass { macro_rules! early_lint_methods { ($macro:path, $args:tt) => ( $macro!($args, [ - fn check_arg(a: &ast::Arg); + fn check_param(a: &ast::Param); fn check_ident(a: ast::Ident); fn check_crate(a: &ast::Crate); fn check_crate_post(a: &ast::Crate); @@ -395,21 +387,11 @@ macro_rules! early_lint_methods { fn check_trait_item_post(a: &ast::TraitItem); fn check_impl_item(a: &ast::ImplItem); fn check_impl_item_post(a: &ast::ImplItem); - fn check_struct_def( - a: &ast::VariantData, - b: ast::Ident, - c: &ast::Generics, - d: ast::NodeId - ); - fn check_struct_def_post( - a: &ast::VariantData, - b: ast::Ident, - c: &ast::Generics, - d: ast::NodeId - ); + fn check_struct_def(a: &ast::VariantData); + fn check_struct_def_post(a: &ast::VariantData); fn check_struct_field(a: &ast::StructField); - fn check_variant(a: &ast::Variant, b: &ast::Generics); - fn check_variant_post(a: &ast::Variant, b: &ast::Generics); + fn check_variant(a: &ast::Variant); + fn check_variant_post(a: &ast::Variant); fn check_lifetime(a: &ast::Lifetime); fn check_path(a: &ast::Path, b: ast::NodeId); fn check_attribute(a: &ast::Attribute); @@ -666,6 +648,30 @@ pub fn struct_lint_level<'a>(sess: &'a Session, (Level::Forbid, None) => sess.struct_err(msg), }; + // Check for future incompatibility lints and issue a stronger warning. + let lints = sess.lint_store.borrow(); + let lint_id = LintId::of(lint); + let future_incompatible = lints.future_incompatible(lint_id); + + // If this code originates in a foreign macro, aka something that this crate + // did not itself author, then it's likely that there's nothing this crate + // can do about it. We probably want to skip the lint entirely. + if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) { + // Any suggestions made here are likely to be incorrect, so anything we + // emit shouldn't be automatically fixed by rustfix. + err.allow_suggestions(false); + + // If this is a future incompatible lint it'll become a hard error, so + // we have to emit *something*. Also allow lints to whitelist themselves + // on a case-by-case basis for emission in a foreign macro. + if future_incompatible.is_none() && !lint.report_in_external_macro { + err.cancel(); + // Don't continue further, since we don't want to have + // `diag_span_note_once` called for a diagnostic that isn't emitted. + return err; + } + } + let name = lint.name_lower(); match src { LintSource::Default => { @@ -715,10 +721,6 @@ pub fn struct_lint_level<'a>(sess: &'a Session, err.code(DiagnosticId::Lint(name)); - // Check for future incompatibility lints and issue a stronger warning. - let lints = sess.lint_store.borrow(); - let lint_id = LintId::of(lint); - let future_incompatible = lints.future_incompatible(lint_id); if let Some(future_incompatible) = future_incompatible { const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \ @@ -743,22 +745,6 @@ pub fn struct_lint_level<'a>(sess: &'a Session, err.note(&citation); } - // If this code originates in a foreign macro, aka something that this crate - // did not itself author, then it's likely that there's nothing this crate - // can do about it. We probably want to skip the lint entirely. - if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) { - // Any suggestions made here are likely to be incorrect, so anything we - // emit shouldn't be automatically fixed by rustfix. - err.allow_suggestions(false); - - // If this is a future incompatible lint it'll become a hard error, so - // we have to emit *something*. Also allow lints to whitelist themselves - // on a case-by-case basis for emission in a foreign macro. - if future_incompatible.is_none() && !lint.report_in_external_macro { - err.cancel() - } - } - return err } @@ -812,9 +798,9 @@ impl intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> { intravisit::NestedVisitorMap::All(&self.tcx.hir()) } - fn visit_arg(&mut self, arg: &'tcx hir::Arg) { - self.with_lint_attrs(arg.hir_id, &arg.attrs, |builder| { - intravisit::walk_arg(builder, arg); + fn visit_param(&mut self, param: &'tcx hir::Param) { + self.with_lint_attrs(param.hir_id, ¶m.attrs, |builder| { + intravisit::walk_param(builder, param); }); } @@ -846,7 +832,7 @@ impl intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> { v: &'tcx hir::Variant, g: &'tcx hir::Generics, item_id: hir::HirId) { - self.with_lint_attrs(v.node.id, &v.node.attrs, |builder| { + self.with_lint_attrs(v.id, &v.attrs, |builder| { intravisit::walk_variant(builder, v, g, item_id); }) } @@ -885,23 +871,18 @@ pub fn provide(providers: &mut Providers<'_>) { /// This is used to test whether a lint should not even begin to figure out whether it should /// be reported on the current node. pub fn in_external_macro(sess: &Session, span: Span) -> bool { - let info = match span.ctxt().outer_expn_info() { - Some(info) => info, - // no ExpnInfo means this span doesn't come from a macro - None => return false, - }; - - match info.kind { + let expn_data = span.ctxt().outer_expn_data(); + match expn_data.kind { ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false, - ExpnKind::Desugaring(_) => true, // well, it's "external" + ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" ExpnKind::Macro(MacroKind::Bang, _) => { - if info.def_site.is_dummy() { - // dummy span for the def_site means it's an external macro + if expn_data.def_site.is_dummy() { + // Dummy span for the `def_site` means it's an external macro. return true; } - match sess.source_map().span_to_snippet(info.def_site) { + match sess.source_map().span_to_snippet(expn_data.def_site) { Ok(code) => !code.starts_with("macro_rules"), - // no snippet = external macro or compiler-builtin expansion + // No snippet means external macro or compiler-builtin expansion. Err(_) => true, } } @@ -909,12 +890,10 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool { } } -/// Returns whether `span` originates in a derive macro's expansion +/// Returns `true` if `span` originates in a derive-macro's expansion. pub fn in_derive_expansion(span: Span) -> bool { - if let Some(info) = span.ctxt().outer_expn_info() { - if let ExpnKind::Macro(MacroKind::Derive, _) = info.kind { - return true; - } + if let ExpnKind::Macro(MacroKind::Derive, _) = span.ctxt().outer_expn_data().kind { + return true; } false } diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 09fa924efc7ab..256a08d7e90c3 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -97,9 +97,9 @@ macro_rules! impl_stable_hash_for { where $($T: ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>>),* { #[inline] - fn hash_stable(&self, - __ctx: &mut $crate::ich::StableHashingContext<'a>, - __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + fn hash_stable(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { use $enum_path::*; ::std::mem::discriminant(self).hash_stable(__ctx, __hasher); @@ -128,9 +128,9 @@ macro_rules! impl_stable_hash_for { where $($T: ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>>),* { #[inline] - fn hash_stable(&self, - __ctx: &mut $crate::ich::StableHashingContext<'a>, - __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + fn hash_stable(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { let $struct_name { $(ref $field),* } = *self; @@ -153,9 +153,9 @@ macro_rules! impl_stable_hash_for { where $($T: ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>>),* { #[inline] - fn hash_stable(&self, - __ctx: &mut $crate::ich::StableHashingContext<'a>, - __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + fn hash_stable(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { let $struct_name ( $(ref $field),* ) = *self; @@ -173,9 +173,9 @@ macro_rules! impl_stable_hash_for_spanned { impl HashStable> for ::syntax::source_map::Spanned<$T> { #[inline] - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { self.node.hash_stable(hcx, hasher); self.span.hash_stable(hcx, hasher); } diff --git a/src/librustc/middle/borrowck.rs b/src/librustc/middle/borrowck.rs deleted file mode 100644 index 60c24eeae7b64..0000000000000 --- a/src/librustc/middle/borrowck.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::ich::StableHashingContext; - -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, - StableHasherResult}; - -#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] -pub enum SignalledError { SawSomeError, NoErrorsSeen } - -impl Default for SignalledError { - fn default() -> SignalledError { - SignalledError::NoErrorsSeen - } -} - -impl_stable_hash_for!(enum self::SignalledError { SawSomeError, NoErrorsSeen }); - -#[derive(Debug, Default, RustcEncodable, RustcDecodable)] -pub struct BorrowCheckResult { - pub signalled_any_error: SignalledError, -} - -impl<'a> HashStable> for BorrowCheckResult { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - let BorrowCheckResult { - ref signalled_any_error, - } = *self; - signalled_any_error.hash_stable(hcx, hasher); - } -} diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 5a580dfa420b3..065959ed09fd1 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -87,7 +87,7 @@ pub enum LinkagePreference { RequireStatic, } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable)] pub enum NativeLibraryKind { /// native static library (.a archive) @@ -96,11 +96,13 @@ pub enum NativeLibraryKind { NativeStaticNobundle, /// macOS-specific NativeFramework, + /// Windows dynamic library without import library. + NativeRawDylib, /// default way to specify a dynamic library NativeUnknown, } -#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] pub struct NativeLibrary { pub kind: NativeLibraryKind, pub name: Option, @@ -126,10 +128,17 @@ pub struct ExternCrate { /// used to select the extern with the shortest path pub path_len: usize, + /// Crate that depends on this crate + pub dependency_of: CrateNum, +} + +impl ExternCrate { /// If true, then this crate is the crate named by the extern /// crate referenced above. If false, then this crate is a dep /// of the crate. - pub direct: bool, + pub fn is_direct(&self) -> bool { + self.dependency_of == LOCAL_CRATE + } } #[derive(Copy, Clone, Debug, HashStable)] @@ -141,9 +150,7 @@ pub enum ExternCrateSource { /// such ids DefId, ), - // Crate is loaded by `use`. - Use, - /// Crate is implicitly loaded by an absolute path. + /// Crate is implicitly loaded by a path resolving through extern prelude. Path, } @@ -178,8 +185,7 @@ pub trait MetadataLoader { -> Result; } -/// A store of Rust crates, through with their metadata -/// can be accessed. +/// A store of Rust crates, through which their metadata can be accessed. /// /// Note that this trait should probably not be expanding today. All new /// functionality should be driven through queries instead! diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index 96b99fe4cdce2..8b2bf55ccc120 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -1,64 +1,10 @@ -//! Resolution of mixing rlibs and dylibs +//! Type definitions for learning about the dependency formats of all upstream +//! crates (rlibs/dylibs/oh my). //! -//! When producing a final artifact, such as a dynamic library, the compiler has -//! a choice between linking an rlib or linking a dylib of all upstream -//! dependencies. The linking phase must guarantee, however, that a library only -//! show up once in the object file. For example, it is illegal for library A to -//! be statically linked to B and C in separate dylibs, and then link B and C -//! into a crate D (because library A appears twice). -//! -//! The job of this module is to calculate what format each upstream crate -//! should be used when linking each output type requested in this session. This -//! generally follows this set of rules: -//! -//! 1. Each library must appear exactly once in the output. -//! 2. Each rlib contains only one library (it's just an object file) -//! 3. Each dylib can contain more than one library (due to static linking), -//! and can also bring in many dynamic dependencies. -//! -//! With these constraints in mind, it's generally a very difficult problem to -//! find a solution that's not "all rlibs" or "all dylibs". I have suspicions -//! that NP-ness may come into the picture here... -//! -//! The current selection algorithm below looks mostly similar to: -//! -//! 1. If static linking is required, then require all upstream dependencies -//! to be available as rlibs. If not, generate an error. -//! 2. If static linking is requested (generating an executable), then -//! attempt to use all upstream dependencies as rlibs. If any are not -//! found, bail out and continue to step 3. -//! 3. Static linking has failed, at least one library must be dynamically -//! linked. Apply a heuristic by greedily maximizing the number of -//! dynamically linked libraries. -//! 4. Each upstream dependency available as a dynamic library is -//! registered. The dependencies all propagate, adding to a map. It is -//! possible for a dylib to add a static library as a dependency, but it -//! is illegal for two dylibs to add the same static library as a -//! dependency. The same dylib can be added twice. Additionally, it is -//! illegal to add a static dependency when it was previously found as a -//! dylib (and vice versa) -//! 5. After all dynamic dependencies have been traversed, re-traverse the -//! remaining dependencies and add them statically (if they haven't been -//! added already). -//! -//! While not perfect, this algorithm should help support use-cases such as leaf -//! dependencies being static while the larger tree of inner dependencies are -//! all dynamic. This isn't currently very well battle tested, so it will likely -//! fall short in some use cases. -//! -//! Currently, there is no way to specify the preference of linkage with a -//! particular library (other than a global dynamic/static switch). -//! Additionally, the algorithm is geared towards finding *any* solution rather -//! than finding a number of solutions (there are normally quite a few). - -use crate::hir::def_id::CrateNum; +//! For all the gory details, see the provider of the `dependency_formats` +//! query. use crate::session::config; -use crate::ty::TyCtxt; -use crate::middle::cstore::{self, DepKind}; -use crate::middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic}; -use crate::util::nodemap::FxHashMap; -use rustc_target::spec::PanicStrategy; /// A list of dependencies for a certain crate type. /// @@ -71,324 +17,12 @@ pub type DependencyList = Vec; /// A mapping of all required dependencies for a particular flavor of output. /// /// This is local to the tcx, and is generally relevant to one session. -pub type Dependencies = FxHashMap; +pub type Dependencies = Vec<(config::CrateType, DependencyList)>; -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug, HashStable)] pub enum Linkage { NotLinked, IncludedFromDylib, Static, Dynamic, } - -pub fn calculate(tcx: TyCtxt<'_>) { - let sess = &tcx.sess; - let fmts = sess.crate_types.borrow().iter().map(|&ty| { - let linkage = calculate_type(tcx, ty); - verify_ok(tcx, &linkage); - (ty, linkage) - }).collect::>(); - sess.abort_if_errors(); - sess.dependency_formats.set(fmts); -} - -fn calculate_type(tcx: TyCtxt<'_>, ty: config::CrateType) -> DependencyList { - let sess = &tcx.sess; - - if !sess.opts.output_types.should_codegen() { - return Vec::new(); - } - - let preferred_linkage = match ty { - // cdylibs must have all static dependencies. - config::CrateType::Cdylib => Linkage::Static, - - // Generating a dylib without `-C prefer-dynamic` means that we're going - // to try to eagerly statically link all dependencies. This is normally - // done for end-product dylibs, not intermediate products. - config::CrateType::Dylib if !sess.opts.cg.prefer_dynamic => Linkage::Static, - config::CrateType::Dylib => Linkage::Dynamic, - - // If the global prefer_dynamic switch is turned off, or the final - // executable will be statically linked, prefer static crate linkage. - config::CrateType::Executable if !sess.opts.cg.prefer_dynamic || - sess.crt_static() => Linkage::Static, - config::CrateType::Executable => Linkage::Dynamic, - - // proc-macro crates are mostly cdylibs, but we also need metadata. - config::CrateType::ProcMacro => Linkage::Static, - - // No linkage happens with rlibs, we just needed the metadata (which we - // got long ago), so don't bother with anything. - config::CrateType::Rlib => Linkage::NotLinked, - - // staticlibs must have all static dependencies. - config::CrateType::Staticlib => Linkage::Static, - }; - - if preferred_linkage == Linkage::NotLinked { - // If the crate is not linked, there are no link-time dependencies. - return Vec::new(); - } - - if preferred_linkage == Linkage::Static { - // Attempt static linkage first. For dylibs and executables, we may be - // able to retry below with dynamic linkage. - if let Some(v) = attempt_static(tcx) { - return v; - } - - // Staticlibs, cdylibs, and static executables must have all static - // dependencies. If any are not found, generate some nice pretty errors. - if ty == config::CrateType::Cdylib || ty == config::CrateType::Staticlib || - (ty == config::CrateType::Executable && sess.crt_static() && - !sess.target.target.options.crt_static_allows_dylibs) { - for &cnum in tcx.crates().iter() { - if tcx.dep_kind(cnum).macros_only() { continue } - let src = tcx.used_crate_source(cnum); - if src.rlib.is_some() { continue } - sess.err(&format!("crate `{}` required to be available in rlib format, \ - but was not found in this form", - tcx.crate_name(cnum))); - } - return Vec::new(); - } - } - - let mut formats = FxHashMap::default(); - - // Sweep all crates for found dylibs. Add all dylibs, as well as their - // dependencies, ensuring there are no conflicts. The only valid case for a - // dependency to be relied upon twice is for both cases to rely on a dylib. - for &cnum in tcx.crates().iter() { - if tcx.dep_kind(cnum).macros_only() { continue } - let name = tcx.crate_name(cnum); - let src = tcx.used_crate_source(cnum); - if src.dylib.is_some() { - info!("adding dylib: {}", name); - add_library(tcx, cnum, RequireDynamic, &mut formats); - let deps = tcx.dylib_dependency_formats(cnum); - for &(depnum, style) in deps.iter() { - info!("adding {:?}: {}", style, tcx.crate_name(depnum)); - add_library(tcx, depnum, style, &mut formats); - } - } - } - - // Collect what we've got so far in the return vector. - let last_crate = tcx.crates().len(); - let mut ret = (1..last_crate+1).map(|cnum| { - match formats.get(&CrateNum::new(cnum)) { - Some(&RequireDynamic) => Linkage::Dynamic, - Some(&RequireStatic) => Linkage::IncludedFromDylib, - None => Linkage::NotLinked, - } - }).collect::>(); - - // Run through the dependency list again, and add any missing libraries as - // static libraries. - // - // If the crate hasn't been included yet and it's not actually required - // (e.g., it's an allocator) then we skip it here as well. - for &cnum in tcx.crates().iter() { - let src = tcx.used_crate_source(cnum); - if src.dylib.is_none() && - !formats.contains_key(&cnum) && - tcx.dep_kind(cnum) == DepKind::Explicit { - assert!(src.rlib.is_some() || src.rmeta.is_some()); - info!("adding staticlib: {}", tcx.crate_name(cnum)); - add_library(tcx, cnum, RequireStatic, &mut formats); - ret[cnum.as_usize() - 1] = Linkage::Static; - } - } - - // We've gotten this far because we're emitting some form of a final - // artifact which means that we may need to inject dependencies of some - // form. - // - // Things like allocators and panic runtimes may not have been activated - // quite yet, so do so here. - activate_injected_dep(*sess.injected_panic_runtime.get(), &mut ret, - &|cnum| tcx.is_panic_runtime(cnum)); - - // When dylib B links to dylib A, then when using B we must also link to A. - // It could be the case, however, that the rlib for A is present (hence we - // found metadata), but the dylib for A has since been removed. - // - // For situations like this, we perform one last pass over the dependencies, - // making sure that everything is available in the requested format. - for (cnum, kind) in ret.iter().enumerate() { - let cnum = CrateNum::new(cnum + 1); - let src = tcx.used_crate_source(cnum); - match *kind { - Linkage::NotLinked | - Linkage::IncludedFromDylib => {} - Linkage::Static if src.rlib.is_some() => continue, - Linkage::Dynamic if src.dylib.is_some() => continue, - kind => { - let kind = match kind { - Linkage::Static => "rlib", - _ => "dylib", - }; - sess.err(&format!("crate `{}` required to be available in {} format, \ - but was not found in this form", - tcx.crate_name(cnum), kind)); - } - } - } - - ret -} - -fn add_library( - tcx: TyCtxt<'_>, - cnum: CrateNum, - link: LinkagePreference, - m: &mut FxHashMap, -) { - match m.get(&cnum) { - Some(&link2) => { - // If the linkages differ, then we'd have two copies of the library - // if we continued linking. If the linkages are both static, then we - // would also have two copies of the library (static from two - // different locations). - // - // This error is probably a little obscure, but I imagine that it - // can be refined over time. - if link2 != link || link == RequireStatic { - tcx.sess.struct_err(&format!("cannot satisfy dependencies so `{}` only \ - shows up once", tcx.crate_name(cnum))) - .help("having upstream crates all available in one format \ - will likely make this go away") - .emit(); - } - } - None => { m.insert(cnum, link); } - } -} - -fn attempt_static(tcx: TyCtxt<'_>) -> Option { - let sess = &tcx.sess; - let crates = cstore::used_crates(tcx, RequireStatic); - if !crates.iter().by_ref().all(|&(_, ref p)| p.is_some()) { - return None - } - - // All crates are available in an rlib format, so we're just going to link - // everything in explicitly so long as it's actually required. - let last_crate = tcx.crates().len(); - let mut ret = (1..last_crate+1).map(|cnum| { - if tcx.dep_kind(CrateNum::new(cnum)) == DepKind::Explicit { - Linkage::Static - } else { - Linkage::NotLinked - } - }).collect::>(); - - // Our allocator/panic runtime may not have been linked above if it wasn't - // explicitly linked, which is the case for any injected dependency. Handle - // that here and activate them. - activate_injected_dep(*sess.injected_panic_runtime.get(), &mut ret, - &|cnum| tcx.is_panic_runtime(cnum)); - - Some(ret) -} - -// Given a list of how to link upstream dependencies so far, ensure that an -// injected dependency is activated. This will not do anything if one was -// transitively included already (e.g., via a dylib or explicitly so). -// -// If an injected dependency was not found then we're guaranteed the -// metadata::creader module has injected that dependency (not listed as -// a required dependency) in one of the session's field. If this field is not -// set then this compilation doesn't actually need the dependency and we can -// also skip this step entirely. -fn activate_injected_dep(injected: Option, - list: &mut DependencyList, - replaces_injected: &dyn Fn(CrateNum) -> bool) { - for (i, slot) in list.iter().enumerate() { - let cnum = CrateNum::new(i + 1); - if !replaces_injected(cnum) { - continue - } - if *slot != Linkage::NotLinked { - return - } - } - if let Some(injected) = injected { - let idx = injected.as_usize() - 1; - assert_eq!(list[idx], Linkage::NotLinked); - list[idx] = Linkage::Static; - } -} - -// After the linkage for a crate has been determined we need to verify that -// there's only going to be one allocator in the output. -fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { - let sess = &tcx.sess; - if list.len() == 0 { - return - } - let mut panic_runtime = None; - for (i, linkage) in list.iter().enumerate() { - if let Linkage::NotLinked = *linkage { - continue - } - let cnum = CrateNum::new(i + 1); - - if tcx.is_panic_runtime(cnum) { - if let Some((prev, _)) = panic_runtime { - let prev_name = tcx.crate_name(prev); - let cur_name = tcx.crate_name(cnum); - sess.err(&format!("cannot link together two \ - panic runtimes: {} and {}", - prev_name, cur_name)); - } - panic_runtime = Some((cnum, tcx.panic_strategy(cnum))); - } - } - - // If we found a panic runtime, then we know by this point that it's the - // only one, but we perform validation here that all the panic strategy - // compilation modes for the whole DAG are valid. - if let Some((cnum, found_strategy)) = panic_runtime { - let desired_strategy = sess.panic_strategy(); - - // First up, validate that our selected panic runtime is indeed exactly - // our same strategy. - if found_strategy != desired_strategy { - sess.err(&format!("the linked panic runtime `{}` is \ - not compiled with this crate's \ - panic strategy `{}`", - tcx.crate_name(cnum), - desired_strategy.desc())); - } - - // Next up, verify that all other crates are compatible with this panic - // strategy. If the dep isn't linked, we ignore it, and if our strategy - // is abort then it's compatible with everything. Otherwise all crates' - // panic strategy must match our own. - for (i, linkage) in list.iter().enumerate() { - if let Linkage::NotLinked = *linkage { - continue - } - if desired_strategy == PanicStrategy::Abort { - continue - } - let cnum = CrateNum::new(i + 1); - let found_strategy = tcx.panic_strategy(cnum); - let is_compiler_builtins = tcx.is_compiler_builtins(cnum); - if is_compiler_builtins || desired_strategy == found_strategy { - continue - } - - sess.err(&format!("the crate `{}` is compiled with the \ - panic strategy `{}` which is \ - incompatible with this crate's \ - strategy of `{}`", - tcx.crate_name(cnum), - found_strategy.desc(), - desired_strategy.desc())); - } - } -} diff --git a/src/librustc/middle/diagnostic_items.rs b/src/librustc/middle/diagnostic_items.rs new file mode 100644 index 0000000000000..dfae169b27824 --- /dev/null +++ b/src/librustc/middle/diagnostic_items.rs @@ -0,0 +1,123 @@ +//! Detecting diagnostic items. +//! +//! Diagnostic items are items that are not language-inherent, but can reasonably be expected to +//! exist for diagnostic purposes. This allows diagnostic authors to refer to specific items +//! directly, without having to guess module paths and crates. +//! Examples are: +//! +//! * Traits like `Debug`, that have no bearing on language semantics +//! +//! * Compiler internal types like `Ty` and `TyCtxt` + +use crate::hir::def_id::{DefId, LOCAL_CRATE}; +use crate::ty::TyCtxt; +use crate::util::nodemap::FxHashMap; + +use syntax::ast; +use syntax::symbol::{Symbol, sym}; +use crate::hir::itemlikevisit::ItemLikeVisitor; +use crate::hir; + +struct DiagnosticItemCollector<'tcx> { + // items from this crate + items: FxHashMap, + tcx: TyCtxt<'tcx>, +} + +impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> { + fn visit_item(&mut self, item: &hir::Item) { + self.observe_item(&item.attrs, item.hir_id); + } + + fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { + self.observe_item(&trait_item.attrs, trait_item.hir_id); + } + + fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { + self.observe_item(&impl_item.attrs, impl_item.hir_id); + } +} + +impl<'tcx> DiagnosticItemCollector<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> DiagnosticItemCollector<'tcx> { + DiagnosticItemCollector { + tcx, + items: Default::default(), + } + } + + fn observe_item(&mut self, attrs: &[ast::Attribute], hir_id: hir::HirId) { + if let Some(name) = extract(attrs) { + let def_id = self.tcx.hir().local_def_id(hir_id); + // insert into our table + collect_item(self.tcx, &mut self.items, name, def_id); + } + } +} + +fn collect_item( + tcx: TyCtxt<'_>, + items: &mut FxHashMap, + name: Symbol, + item_def_id: DefId, +) { + // Check for duplicates. + if let Some(original_def_id) = items.insert(name, item_def_id) { + if original_def_id != item_def_id { + let mut err = match tcx.hir().span_if_local(item_def_id) { + Some(span) => tcx.sess.struct_span_err( + span, + &format!("duplicate diagnostic item found: `{}`.", name)), + None => tcx.sess.struct_err(&format!( + "duplicate diagnostic item in crate `{}`: `{}`.", + tcx.crate_name(item_def_id.krate), + name)), + }; + if let Some(span) = tcx.hir().span_if_local(original_def_id) { + span_note!(&mut err, span, "first defined here."); + } else { + err.note(&format!("first defined in crate `{}`.", + tcx.crate_name(original_def_id.krate))); + } + err.emit(); + } + } +} + +/// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes. +fn extract(attrs: &[ast::Attribute]) -> Option { + attrs.iter().find_map(|attr| { + if attr.check_name(sym::rustc_diagnostic_item) { + attr.value_str() + } else { + None + } + }) +} + +/// Traverse and collect the diagnostic items in the current +pub fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> &'tcx FxHashMap { + // Initialize the collector. + let mut collector = DiagnosticItemCollector::new(tcx); + + // Collect diagnostic items in this crate. + tcx.hir().krate().visit_all_item_likes(&mut collector); + + tcx.arena.alloc(collector.items) +} + + +/// Traverse and collect all the diagnostic items in all crates. +pub fn collect_all<'tcx>(tcx: TyCtxt<'tcx>) -> &'tcx FxHashMap { + // Initialize the collector. + let mut collector = FxHashMap::default(); + + // Collect diagnostic items in other crates. + for &cnum in tcx.crates().iter().chain(std::iter::once(&LOCAL_CRATE)) { + for (&name, &def_id) in tcx.diagnostic_items(cnum).iter() { + collect_item(tcx, &mut collector, name, def_id); + } + } + + tcx.arena.alloc(collector) +} diff --git a/src/librustc/middle/exported_symbols.rs b/src/librustc/middle/exported_symbols.rs index 202788093046a..4d14299751c3d 100644 --- a/src/librustc/middle/exported_symbols.rs +++ b/src/librustc/middle/exported_symbols.rs @@ -1,7 +1,6 @@ use crate::hir::def_id::{DefId, LOCAL_CRATE}; use crate::ich::StableHashingContext; -use rustc_data_structures::stable_hasher::{StableHasher, HashStable, - StableHasherResult}; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use std::cmp; use std::mem; use crate::ty::{self, TyCtxt}; @@ -94,9 +93,7 @@ pub fn metadata_symbol_name(tcx: TyCtxt<'_>) -> String { } impl<'a, 'tcx> HashStable> for ExportedSymbol<'tcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { ExportedSymbol::NonGeneric(def_id) => { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a274d7bbee5f7..bb7ac5d8dbe1a 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -2,25 +2,20 @@ //! normal visitor, which just walks the entire body in one shot, the //! `ExprUseVisitor` determines how expressions are being used. -pub use self::LoanCause::*; pub use self::ConsumeMode::*; -pub use self::MoveReason::*; -pub use self::MatchMode::*; -use self::TrackMatchMode::*; use self::OverloadedCallType::*; -use crate::hir::def::{CtorOf, Res, DefKind}; +use crate::hir::def::Res; use crate::hir::def_id::DefId; use crate::hir::ptr::P; use crate::infer::InferCtxt; use crate::middle::mem_categorization as mc; use crate::middle::region; -use crate::ty::{self, DefIdTree, TyCtxt, adjustment}; +use crate::ty::{self, TyCtxt, adjustment}; use crate::hir::{self, PatKind}; use std::rc::Rc; use syntax_pos::Span; -use crate::util::nodemap::ItemLocalSet; /////////////////////////////////////////////////////////////////////////// // The Delegate trait @@ -30,161 +25,19 @@ use crate::util::nodemap::ItemLocalSet; pub trait Delegate<'tcx> { // The value found at `cmt` is either copied or moved, depending // on mode. - fn consume(&mut self, - consume_id: hir::HirId, - consume_span: Span, - cmt: &mc::cmt_<'tcx>, - mode: ConsumeMode); - - // The value found at `cmt` has been determined to match the - // pattern binding `matched_pat`, and its subparts are being - // copied or moved depending on `mode`. Note that `matched_pat` - // is called on all variant/structs in the pattern (i.e., the - // interior nodes of the pattern's tree structure) while - // consume_pat is called on the binding identifiers in the pattern - // (which are leaves of the pattern's tree structure). - // - // Note that variants/structs and identifiers are disjoint; thus - // `matched_pat` and `consume_pat` are never both called on the - // same input pattern structure (though of `consume_pat` can be - // called on a subpart of an input passed to `matched_pat). - fn matched_pat(&mut self, - matched_pat: &hir::Pat, - cmt: &mc::cmt_<'tcx>, - mode: MatchMode); - - // The value found at `cmt` is either copied or moved via the - // pattern binding `consume_pat`, depending on mode. - fn consume_pat(&mut self, - consume_pat: &hir::Pat, - cmt: &mc::cmt_<'tcx>, - mode: ConsumeMode); - - // The value found at `borrow` is being borrowed at the point - // `borrow_id` for the region `loan_region` with kind `bk`. - fn borrow(&mut self, - borrow_id: hir::HirId, - borrow_span: Span, - cmt: &mc::cmt_<'tcx>, - loan_region: ty::Region<'tcx>, - bk: ty::BorrowKind, - loan_cause: LoanCause); - - // The local variable `id` is declared but not initialized. - fn decl_without_init(&mut self, - id: hir::HirId, - span: Span); + fn consume(&mut self, cmt: &mc::cmt_<'tcx>, mode: ConsumeMode); - // The path at `cmt` is being assigned to. - fn mutate(&mut self, - assignment_id: hir::HirId, - assignment_span: Span, - assignee_cmt: &mc::cmt_<'tcx>, - mode: MutateMode); - - // A nested closure or generator - only one layer deep. - fn nested_body(&mut self, _body_id: hir::BodyId) {} -} + // The value found at `cmt` is being borrowed with kind `bk`. + fn borrow(&mut self, cmt: &mc::cmt_<'tcx>, bk: ty::BorrowKind); -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum LoanCause { - ClosureCapture(Span), - AddrOf, - AutoRef, - AutoUnsafe, - RefBinding, - OverloadedOperator, - ClosureInvocation, - ForLoop, - MatchDiscriminant + // The path at `cmt` is being assigned to. + fn mutate(&mut self, assignee_cmt: &mc::cmt_<'tcx>); } #[derive(Copy, Clone, PartialEq, Debug)] pub enum ConsumeMode { Copy, // reference to x where x has a type that copies - Move(MoveReason), // reference to x where x has a type that moves -} - -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum MoveReason { - DirectRefMove, - PatBindingMove, - CaptureMove, -} - -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum MatchMode { - NonBindingMatch, - BorrowingMatch, - CopyingMatch, - MovingMatch, -} - -#[derive(Copy, Clone, PartialEq, Debug)] -enum TrackMatchMode { - Unknown, - Definite(MatchMode), - Conflicting, -} - -impl TrackMatchMode { - // Builds up the whole match mode for a pattern from its constituent - // parts. The lattice looks like this: - // - // Conflicting - // / \ - // / \ - // Borrowing Moving - // \ / - // \ / - // Copying - // | - // NonBinding - // | - // Unknown - // - // examples: - // - // * `(_, some_int)` pattern is Copying, since - // NonBinding + Copying => Copying - // - // * `(some_int, some_box)` pattern is Moving, since - // Copying + Moving => Moving - // - // * `(ref x, some_box)` pattern is Conflicting, since - // Borrowing + Moving => Conflicting - // - // Note that the `Unknown` and `Conflicting` states are - // represented separately from the other more interesting - // `Definite` states, which simplifies logic here somewhat. - fn lub(&mut self, mode: MatchMode) { - *self = match (*self, mode) { - // Note that clause order below is very significant. - (Unknown, new) => Definite(new), - (Definite(old), new) if old == new => Definite(old), - - (Definite(old), NonBindingMatch) => Definite(old), - (Definite(NonBindingMatch), new) => Definite(new), - - (Definite(old), CopyingMatch) => Definite(old), - (Definite(CopyingMatch), new) => Definite(new), - - (Definite(_), _) => Conflicting, - (Conflicting, _) => *self, - }; - } - - fn match_mode(&self) -> MatchMode { - match *self { - Unknown => NonBindingMatch, - Definite(mode) => mode, - Conflicting => { - // Conservatively return MovingMatch to let the - // compiler continue to make progress. - MovingMatch - } - } - } + Move, // reference to x where x has a type that moves } #[derive(Copy, Clone, PartialEq, Debug)] @@ -261,9 +114,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { /// - `param_env` --- parameter environment for trait lookups (esp. pertaining to `Copy`) /// - `region_scope_tree` --- region scope tree for the code being analyzed /// - `tables` --- typeck results for the code being analyzed - /// - `rvalue_promotable_map` --- if you care about rvalue promotion, then provide - /// the map here (it can be computed with `tcx.rvalue_promotable_map(def_id)`). - /// `None` means that rvalues will be given more conservative lifetimes. /// /// See also `with_infer`, which is used *during* typeck. pub fn new( @@ -273,15 +123,13 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, region_scope_tree: &'a region::ScopeTree, tables: &'a ty::TypeckTables<'tcx>, - rvalue_promotable_map: Option<&'tcx ItemLocalSet>, ) -> Self { ExprUseVisitor { mc: mc::MemCategorizationContext::new(tcx, param_env, body_owner, region_scope_tree, - tables, - rvalue_promotable_map), + tables), delegate, param_env, } @@ -313,23 +161,16 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { pub fn consume_body(&mut self, body: &hir::Body) { debug!("consume_body(body={:?})", body); - for arg in &body.arguments { - let arg_ty = return_if_err!(self.mc.pat_ty_adjusted(&arg.pat)); - debug!("consume_body: arg_ty = {:?}", arg_ty); - - let fn_body_scope_r = - self.tcx().mk_region(ty::ReScope( - region::Scope { - id: body.value.hir_id.local_id, - data: region::ScopeData::Node - })); - let arg_cmt = Rc::new(self.mc.cat_rvalue( - arg.hir_id, - arg.pat.span, - fn_body_scope_r, // Args live only as long as the fn body. - arg_ty)); - - self.walk_irrefutable_pat(arg_cmt, &arg.pat); + for param in &body.params { + let param_ty = return_if_err!(self.mc.pat_ty_adjusted(¶m.pat)); + debug!("consume_body: param_ty = {:?}", param_ty); + + let param_cmt = Rc::new(self.mc.cat_rvalue( + param.hir_id, + param.pat.span, + param_ty)); + + self.walk_irrefutable_pat(param_cmt, ¶m.pat); } self.consume_expr(&body.value); @@ -339,15 +180,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.mc.tcx } - fn delegate_consume(&mut self, - consume_id: hir::HirId, - consume_span: Span, - cmt: &mc::cmt_<'tcx>) { - debug!("delegate_consume(consume_id={}, cmt={:?})", - consume_id, cmt); + fn delegate_consume(&mut self, cmt: &mc::cmt_<'tcx>) { + debug!("delegate_consume(cmt={:?})", cmt); - let mode = copy_or_move(&self.mc, self.param_env, cmt, DirectRefMove); - self.delegate.consume(consume_id, consume_span, cmt, mode); + let mode = copy_or_move(&self.mc, self.param_env, cmt); + self.delegate.consume(cmt, mode); } fn consume_exprs(&mut self, exprs: &[hir::Expr]) { @@ -360,30 +197,21 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { debug!("consume_expr(expr={:?})", expr); let cmt = return_if_err!(self.mc.cat_expr(expr)); - self.delegate_consume(expr.hir_id, expr.span, &cmt); + self.delegate_consume(&cmt); self.walk_expr(expr); } - fn mutate_expr(&mut self, - span: Span, - assignment_expr: &hir::Expr, - expr: &hir::Expr, - mode: MutateMode) { + fn mutate_expr(&mut self, expr: &hir::Expr) { let cmt = return_if_err!(self.mc.cat_expr(expr)); - self.delegate.mutate(assignment_expr.hir_id, span, &cmt, mode); + self.delegate.mutate(&cmt); self.walk_expr(expr); } - fn borrow_expr(&mut self, - expr: &hir::Expr, - r: ty::Region<'tcx>, - bk: ty::BorrowKind, - cause: LoanCause) { - debug!("borrow_expr(expr={:?}, r={:?}, bk={:?})", - expr, r, bk); + fn borrow_expr(&mut self, expr: &hir::Expr, bk: ty::BorrowKind) { + debug!("borrow_expr(expr={:?}, bk={:?})", expr, bk); let cmt = return_if_err!(self.mc.cat_expr(expr)); - self.delegate.borrow(expr.hir_id, expr.span, &cmt, r, bk, cause); + self.delegate.borrow(&cmt, bk); self.walk_expr(expr) } @@ -397,28 +225,28 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.walk_adjustment(expr); - match expr.node { + match expr.kind { hir::ExprKind::Path(_) => { } hir::ExprKind::Type(ref subexpr, _) => { - self.walk_expr(&subexpr) + self.walk_expr(subexpr) } hir::ExprKind::Unary(hir::UnDeref, ref base) => { // *base - self.select_from_expr(&base); + self.select_from_expr(base); } hir::ExprKind::Field(ref base, _) => { // base.f - self.select_from_expr(&base); + self.select_from_expr(base); } hir::ExprKind::Index(ref lhs, ref rhs) => { // lhs[rhs] - self.select_from_expr(&lhs); - self.consume_expr(&rhs); + self.select_from_expr(lhs); + self.consume_expr(rhs); } hir::ExprKind::Call(ref callee, ref args) => { // callee(args) - self.walk_callee(expr, &callee); + self.walk_callee(expr, callee); self.consume_exprs(args); } @@ -436,14 +264,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { hir::ExprKind::Match(ref discr, ref arms, _) => { let discr_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&discr))); - let r = self.tcx().lifetimes.re_empty; - self.borrow_expr(&discr, r, ty::ImmBorrow, MatchDiscriminant); + self.borrow_expr(&discr, ty::ImmBorrow); // treatment of the discriminant is handled while walking the arms. for arm in arms { - let mode = self.arm_move_mode(discr_cmt.clone(), arm); - let mode = mode.match_mode(); - self.walk_arm(discr_cmt.clone(), arm, mode); + self.walk_arm(discr_cmt.clone(), arm); } } @@ -454,11 +279,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { hir::ExprKind::AddrOf(m, ref base) => { // &base // make sure that the thing we are pointing out stays valid // for the lifetime `scope_r` of the resulting ptr: - let expr_ty = return_if_err!(self.mc.expr_ty(expr)); - if let ty::Ref(r, _, _) = expr_ty.sty { - let bk = ty::BorrowKind::from_mutbl(m); - self.borrow_expr(&base, r, bk, AddrOf); - } + let bk = ty::BorrowKind::from_mutbl(m); + self.borrow_expr(&base, bk); } hir::ExprKind::InlineAsm(ref ia, ref outputs, ref inputs) => { @@ -466,16 +288,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { if o.is_indirect { self.consume_expr(output); } else { - self.mutate_expr( - output.span, - expr, - output, - if o.is_rw { - MutateMode::WriteAndRead - } else { - MutateMode::JustWrite - }, - ); + self.mutate_expr(output); } } self.consume_exprs(inputs); @@ -486,65 +299,64 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { hir::ExprKind::Err => {} hir::ExprKind::Loop(ref blk, _, _) => { - self.walk_block(&blk); + self.walk_block(blk); } hir::ExprKind::Unary(_, ref lhs) => { - self.consume_expr(&lhs); + self.consume_expr(lhs); } hir::ExprKind::Binary(_, ref lhs, ref rhs) => { - self.consume_expr(&lhs); - self.consume_expr(&rhs); + self.consume_expr(lhs); + self.consume_expr(rhs); } hir::ExprKind::Block(ref blk, _) => { - self.walk_block(&blk); + self.walk_block(blk); } hir::ExprKind::Break(_, ref opt_expr) | hir::ExprKind::Ret(ref opt_expr) => { if let Some(ref expr) = *opt_expr { - self.consume_expr(&expr); + self.consume_expr(expr); } } hir::ExprKind::Assign(ref lhs, ref rhs) => { - self.mutate_expr(expr.span, expr, &lhs, MutateMode::JustWrite); - self.consume_expr(&rhs); + self.mutate_expr(lhs); + self.consume_expr(rhs); } hir::ExprKind::Cast(ref base, _) => { - self.consume_expr(&base); + self.consume_expr(base); } hir::ExprKind::DropTemps(ref expr) => { - self.consume_expr(&expr); + self.consume_expr(expr); } hir::ExprKind::AssignOp(_, ref lhs, ref rhs) => { if self.mc.tables.is_method_call(expr) { self.consume_expr(lhs); } else { - self.mutate_expr(expr.span, expr, &lhs, MutateMode::WriteAndRead); + self.mutate_expr(lhs); } - self.consume_expr(&rhs); + self.consume_expr(rhs); } hir::ExprKind::Repeat(ref base, _) => { - self.consume_expr(&base); + self.consume_expr(base); } - hir::ExprKind::Closure(_, _, body_id, fn_decl_span, _) => { - self.delegate.nested_body(body_id); + hir::ExprKind::Closure(_, _, _, fn_decl_span, _) => { self.walk_captures(expr, fn_decl_span); } hir::ExprKind::Box(ref base) => { - self.consume_expr(&base); + self.consume_expr(base); } hir::ExprKind::Yield(ref value, _) => { - self.consume_expr(&value); + self.consume_expr(value); } } } @@ -553,31 +365,19 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { let callee_ty = return_if_err!(self.mc.expr_ty_adjusted(callee)); debug!("walk_callee: callee={:?} callee_ty={:?}", callee, callee_ty); - match callee_ty.sty { + match callee_ty.kind { ty::FnDef(..) | ty::FnPtr(_) => { self.consume_expr(callee); } ty::Error => { } _ => { if let Some(def_id) = self.mc.tables.type_dependent_def_id(call.hir_id) { - let call_scope = region::Scope { - id: call.hir_id.local_id, - data: region::ScopeData::Node - }; match OverloadedCallType::from_method_id(self.tcx(), def_id) { FnMutOverloadedCall => { - let call_scope_r = self.tcx().mk_region(ty::ReScope(call_scope)); - self.borrow_expr(callee, - call_scope_r, - ty::MutBorrow, - ClosureInvocation); + self.borrow_expr(callee, ty::MutBorrow); } FnOverloadedCall => { - let call_scope_r = self.tcx().mk_region(ty::ReScope(call_scope)); - self.borrow_expr(callee, - call_scope_r, - ty::ImmBorrow, - ClosureInvocation); + self.borrow_expr(callee, ty::ImmBorrow); } FnOnceOverloadedCall => self.consume_expr(callee), } @@ -590,13 +390,13 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } fn walk_stmt(&mut self, stmt: &hir::Stmt) { - match stmt.node { + match stmt.kind { hir::StmtKind::Local(ref local) => { self.walk_local(&local); } hir::StmtKind::Item(_) => { - // we don't visit nested items in this visitor, + // We don't visit nested items in this visitor, // only the fn body we were given. } @@ -608,22 +408,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } fn walk_local(&mut self, local: &hir::Local) { - match local.init { - None => { - local.pat.each_binding(|_, hir_id, span, _| { - self.delegate.decl_without_init(hir_id, span); - }) - } - - Some(ref expr) => { - // Variable declarations with - // initializers are considered - // "assigns", which is handled by - // `walk_pat`: - self.walk_expr(&expr); - let init_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&expr))); - self.walk_irrefutable_pat(init_cmt, &local.pat); - } + if let Some(ref expr) = local.init { + // Variable declarations with + // initializers are considered + // "assigns", which is handled by + // `walk_pat`: + self.walk_expr(&expr); + let init_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&expr))); + self.walk_irrefutable_pat(init_cmt, &local.pat); } } @@ -658,7 +450,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // Select just those fields of the `with` // expression that will actually be used - match with_cmt.ty.sty { + match with_cmt.ty.kind { ty::Adt(adt, substs) if adt.is_struct() => { // Consume those fields of the with expression that are needed. for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() { @@ -673,7 +465,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { with_field.ident, with_field.ty(self.tcx(), substs) ); - self.delegate_consume(with_expr.hir_id, with_expr.span, &cmt_field); + self.delegate_consume(&cmt_field); } } } @@ -708,7 +500,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { adjustment::Adjust::Pointer(_) => { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. - self.delegate_consume(expr.hir_id, expr.span, &cmt); + self.delegate_consume(&cmt); } adjustment::Adjust::Deref(None) => {} @@ -720,7 +512,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // this is an autoref of `x`. adjustment::Adjust::Deref(Some(ref deref)) => { let bk = ty::BorrowKind::from_mutbl(deref.mutbl); - self.delegate.borrow(expr.hir_id, expr.span, &cmt, deref.region, bk, AutoRef); + self.delegate.borrow(&cmt, bk); } adjustment::Adjust::Borrow(ref autoref) => { @@ -744,13 +536,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { autoref); match *autoref { - adjustment::AutoBorrow::Ref(r, m) => { - self.delegate.borrow(expr.hir_id, - expr.span, - cmt_base, - r, - ty::BorrowKind::from_mutbl(m.into()), - AutoRef); + adjustment::AutoBorrow::Ref(_, m) => { + self.delegate.borrow(cmt_base, ty::BorrowKind::from_mutbl(m.into())); } adjustment::AutoBorrow::RawPtr(m) => { @@ -758,37 +545,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { expr.hir_id, cmt_base); - // Converting from a &T to *T (or &mut T to *mut T) is - // treated as borrowing it for the enclosing temporary - // scope. - let r = self.tcx().mk_region(ty::ReScope( - region::Scope { - id: expr.hir_id.local_id, - data: region::ScopeData::Node - })); - - self.delegate.borrow(expr.hir_id, - expr.span, - cmt_base, - r, - ty::BorrowKind::from_mutbl(m), - AutoUnsafe); - } - } - } - fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm) -> TrackMatchMode { - let mut mode = Unknown; - for pat in &arm.pats { - self.determine_pat_move_mode(discr_cmt.clone(), &pat, &mut mode); + self.delegate.borrow(cmt_base, ty::BorrowKind::from_mutbl(m)); + } } - mode } - fn walk_arm(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm, mode: MatchMode) { - for pat in &arm.pats { - self.walk_pat(discr_cmt.clone(), &pat, mode); - } + fn walk_arm(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm) { + self.walk_pat(discr_cmt.clone(), &arm.pat); if let Some(hir::Guard::If(ref e)) = arm.guard { self.consume_expr(e) @@ -800,55 +564,22 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or /// let binding, and *not* a match arm or nested pat.) fn walk_irrefutable_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat) { - let mut mode = Unknown; - self.determine_pat_move_mode(cmt_discr.clone(), pat, &mut mode); - let mode = mode.match_mode(); - self.walk_pat(cmt_discr, pat, mode); + self.walk_pat(cmt_discr, pat); } - /// Identifies any bindings within `pat` and accumulates within - /// `mode` whether the overall pattern/match structure is a move, - /// copy, or borrow. - fn determine_pat_move_mode(&mut self, - cmt_discr: mc::cmt<'tcx>, - pat: &hir::Pat, - mode: &mut TrackMatchMode) { - debug!("determine_pat_move_mode cmt_discr={:?} pat={:?}", cmt_discr, pat); - - return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| { - if let PatKind::Binding(..) = pat.node { - let bm = *self.mc.tables.pat_binding_modes() - .get(pat.hir_id) - .expect("missing binding mode"); - match bm { - ty::BindByReference(..) => - mode.lub(BorrowingMatch), - ty::BindByValue(..) => { - match copy_or_move(&self.mc, self.param_env, &cmt_pat, PatBindingMove) { - Copy => mode.lub(CopyingMatch), - Move(..) => mode.lub(MovingMatch), - } - } - } - } - })); - } - /// The core driver for walking a pattern; `match_mode` must be - /// established up front, e.g., via `determine_pat_move_mode` (see - /// also `walk_irrefutable_pat` for patterns that stand alone). - fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: MatchMode) { + /// The core driver for walking a pattern + fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat) { debug!("walk_pat(cmt_discr={:?}, pat={:?})", cmt_discr, pat); let tcx = self.tcx(); let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self; return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| { - if let PatKind::Binding(_, canonical_id, ..) = pat.node { + if let PatKind::Binding(_, canonical_id, ..) = pat.kind { debug!( - "walk_pat: binding cmt_pat={:?} pat={:?} match_mode={:?}", + "walk_pat: binding cmt_pat={:?} pat={:?}", cmt_pat, pat, - match_mode, ); if let Some(&bm) = mc.tables.pat_binding_modes().get(pat.hir_id) { debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); @@ -861,21 +592,19 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // binding being produced. let def = Res::Local(canonical_id); if let Ok(ref binding_cmt) = mc.cat_res(pat.hir_id, pat.span, pat_ty, def) { - delegate.mutate(pat.hir_id, pat.span, binding_cmt, MutateMode::Init); + delegate.mutate(binding_cmt); } // It is also a borrow or copy/move of the value being matched. match bm { ty::BindByReference(m) => { - if let ty::Ref(r, _, _) = pat_ty.sty { - let bk = ty::BorrowKind::from_mutbl(m); - delegate.borrow(pat.hir_id, pat.span, &cmt_pat, r, bk, RefBinding); - } + let bk = ty::BorrowKind::from_mutbl(m); + delegate.borrow(&cmt_pat, bk); } ty::BindByValue(..) => { - let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove); + let mode = copy_or_move(mc, param_env, &cmt_pat); debug!("walk_pat binding consuming pat"); - delegate.consume_pat(pat, &cmt_pat, mode); + delegate.consume(&cmt_pat, mode); } } } else { @@ -883,45 +612,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } } })); - - // Do a second pass over the pattern, calling `matched_pat` on - // the interior nodes (enum variants and structs), as opposed - // to the above loop's visit of than the bindings that form - // the leaves of the pattern tree structure. - return_if_err!(mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| { - let qpath = match pat.node { - PatKind::Path(ref qpath) | - PatKind::TupleStruct(ref qpath, ..) | - PatKind::Struct(ref qpath, ..) => qpath, - _ => return - }; - let res = mc.tables.qpath_res(qpath, pat.hir_id); - match res { - Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_did) => { - let variant_did = mc.tcx.parent(variant_ctor_did).unwrap(); - let downcast_cmt = mc.cat_downcast_if_needed(pat, cmt_pat, variant_did); - - debug!("variantctor downcast_cmt={:?} pat={:?}", downcast_cmt, pat); - delegate.matched_pat(pat, &downcast_cmt, match_mode); - } - Res::Def(DefKind::Variant, variant_did) => { - let downcast_cmt = mc.cat_downcast_if_needed(pat, cmt_pat, variant_did); - - debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat); - delegate.matched_pat(pat, &downcast_cmt, match_mode); - } - Res::Def(DefKind::Struct, _) - | Res::Def(DefKind::Ctor(..), _) - | Res::Def(DefKind::Union, _) - | Res::Def(DefKind::TyAlias, _) - | Res::Def(DefKind::AssocTy, _) - | Res::SelfTy(..) => { - debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat); - delegate.matched_pat(pat, &cmt_pat, match_mode); - } - _ => {} - } - })); } fn walk_captures(&mut self, closure_expr: &hir::Expr, fn_decl_span: Span) { @@ -929,7 +619,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id); if let Some(upvars) = self.tcx().upvars(closure_def_id) { - for (&var_id, upvar) in upvars.iter() { + for &var_id in upvars.keys() { let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_id }, closure_expr_id: closure_def_id.to_local(), @@ -940,19 +630,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { var_id)); match upvar_capture { ty::UpvarCapture::ByValue => { - let mode = copy_or_move(&self.mc, - self.param_env, - &cmt_var, - CaptureMove); - self.delegate.consume(closure_expr.hir_id, upvar.span, &cmt_var, mode); + let mode = copy_or_move(&self.mc, self.param_env, &cmt_var); + self.delegate.consume(&cmt_var, mode); } ty::UpvarCapture::ByRef(upvar_borrow) => { - self.delegate.borrow(closure_expr.hir_id, - fn_decl_span, - &cmt_var, - upvar_borrow.region, - upvar_borrow.kind, - ClosureCapture(upvar.span)); + self.delegate.borrow(&cmt_var, upvar_borrow.kind); } } } @@ -975,10 +657,9 @@ fn copy_or_move<'a, 'tcx>( mc: &mc::MemCategorizationContext<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, cmt: &mc::cmt_<'tcx>, - move_reason: MoveReason, ) -> ConsumeMode { if !mc.type_is_copy_modulo_regions(param_env, cmt.ty, cmt.span) { - Move(move_reason) + Move } else { Copy } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index c5c8639324358..cab929389d6a4 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -3,10 +3,8 @@ //! Language items are items that represent concepts intrinsic to the language //! itself. Examples are: //! -//! * Traits that specify "kinds"; e.g., "Sync", "Send". -//! -//! * Traits that represent operators; e.g., "Add", "Sub", "Index". -//! +//! * Traits that specify "kinds"; e.g., `Sync`, `Send`. +//! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`. //! * Functions called by the compiler itself. pub use self::LangItem::*; @@ -15,6 +13,7 @@ use crate::hir::def_id::DefId; use crate::hir::check_attr::Target; use crate::ty::{self, TyCtxt}; use crate::middle::weak_lang_items; +use crate::middle::cstore::ExternCrate; use crate::util::nodemap::FxHashMap; use syntax::ast; @@ -151,11 +150,11 @@ impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> { } fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) { - // at present, lang items are always items, not trait items + // At present, lang items are always items, not trait items. } fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { - // at present, lang items are always items, not impl items + // At present, lang items are always items, not impl items. } } @@ -184,16 +183,39 @@ impl LanguageItemCollector<'tcx> { E0152, "duplicate lang item found: `{}`.", name), - None => self.tcx.sess.struct_err(&format!( - "duplicate lang item in crate `{}`: `{}`.", - self.tcx.crate_name(item_def_id.krate), - name)), + None => { + match self.tcx.extern_crate(item_def_id) { + Some(ExternCrate {dependency_of, ..}) => { + self.tcx.sess.struct_err(&format!( + "duplicate lang item in crate `{}` (which `{}` depends on): `{}`.", + self.tcx.crate_name(item_def_id.krate), + self.tcx.crate_name(*dependency_of), + name)) + }, + _ => { + self.tcx.sess.struct_err(&format!( + "duplicate lang item in crate `{}`: `{}`.", + self.tcx.crate_name(item_def_id.krate), + name)) + } + } + }, }; if let Some(span) = self.tcx.hir().span_if_local(original_def_id) { span_note!(&mut err, span, "first defined here."); } else { - err.note(&format!("first defined in crate `{}`.", + match self.tcx.extern_crate(original_def_id) { + Some(ExternCrate {dependency_of, ..}) => { + err.note(&format!( + "first defined in crate `{}` (which `{}` depends on).", + self.tcx.crate_name(original_def_id.krate), + self.tcx.crate_name(*dependency_of))); + }, + _ => { + err.note(&format!("first defined in crate `{}`.", self.tcx.crate_name(original_def_id.krate))); + } + } } err.emit(); } @@ -204,7 +226,7 @@ impl LanguageItemCollector<'tcx> { } } -/// Extract the first `lang = "$name"` out of a list of attributes. +/// Extracts the first `lang = "$name"` out of a list of attributes. /// The attributes `#[panic_handler]` and `#[alloc_error_handler]` /// are also extracted out when found. pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { @@ -216,7 +238,7 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { })) } -/// Traverse and collect all the lang items in all crates. +/// Traverses and collects all the lang items in all crates. pub fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> LanguageItems { // Initialize the collector. let mut collector = LanguageItemCollector::new(tcx); @@ -246,6 +268,7 @@ pub fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> LanguageItems { language_item_table! { // Variant name, Name, Method name, Target; + BoolImplItem, "bool", bool_impl, Target::Impl; CharImplItem, "char", char_impl, Target::Impl; StrImplItem, "str", str_impl, Target::Impl; SliceImplItem, "slice", slice_impl, Target::Impl; @@ -367,9 +390,7 @@ language_item_table! { MaybeUninitLangItem, "maybe_uninit", maybe_uninit, Target::Union; - DebugTraitLangItem, "debug_trait", debug_trait, Target::Trait; - - // Align offset for stride != 1, must not panic. + // Align offset for stride != 1; must not panic. AlignOffsetLangItem, "align_offset", align_offset_fn, Target::Fn; TerminationTraitLangItem, "termination", termination, Target::Trait; @@ -380,10 +401,14 @@ language_item_table! { impl<'tcx> TyCtxt<'tcx> { /// Returns the `DefId` for a given `LangItem`. - /// If not found, fatally abort compilation. - pub fn require_lang_item(&self, lang_item: LangItem) -> DefId { + /// If not found, fatally aborts compilation. + pub fn require_lang_item(&self, lang_item: LangItem, span: Option) -> DefId { self.lang_items().require(lang_item).unwrap_or_else(|msg| { - self.sess.fatal(&msg) + if let Some(span) = span { + self.sess.span_fatal(span, &msg) + } else { + self.sess.fatal(&msg) + } }) } } diff --git a/src/librustc/middle/lib_features.rs b/src/librustc/middle/lib_features.rs index 0d6d016e50701..2d726fcd17612 100644 --- a/src/librustc/middle/lib_features.rs +++ b/src/librustc/middle/lib_features.rs @@ -59,7 +59,7 @@ impl LibFeatureCollector<'tcx> { attr.check_name(**stab_attr) }) { let meta_item = attr.meta(); - if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta_item { + if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta_item { let mut feature = None; let mut since = None; for meta in metas { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 77d6f3932445b..8f79b8aa29529 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -79,12 +79,11 @@ use std::fmt; use std::hash::{Hash, Hasher}; use rustc_data_structures::fx::FxIndexMap; use std::rc::Rc; -use crate::util::nodemap::ItemLocalSet; #[derive(Clone, Debug, PartialEq)] pub enum Categorization<'tcx> { - Rvalue(ty::Region<'tcx>), // temporary val, argument is its scope - ThreadLocal(ty::Region<'tcx>), // value that cannot move, but still restricted in scope + Rvalue, // temporary val + ThreadLocal, // value that cannot move, but still restricted in scope StaticItem, Upvar(Upvar), // upvar referenced by closure env Local(hir::HirId), // local variable @@ -219,7 +218,6 @@ pub struct MemCategorizationContext<'a, 'tcx> { pub upvars: Option<&'tcx FxIndexMap>, pub region_scope_tree: &'a region::ScopeTree, pub tables: &'a ty::TypeckTables<'tcx>, - rvalue_promotable_map: Option<&'tcx ItemLocalSet>, infcx: Option<&'a InferCtxt<'a, 'tcx>>, } @@ -271,7 +269,7 @@ impl MutabilityCategory { id: hir::HirId, ) -> MutabilityCategory { let ret = match tcx.hir().get(id) { - Node::Binding(p) => match p.node { + Node::Binding(p) => match p.kind { PatKind::Binding(..) => { let bm = *tables.pat_binding_modes() .get(p.hir_id) @@ -335,7 +333,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { body_owner: DefId, region_scope_tree: &'a region::ScopeTree, tables: &'a ty::TypeckTables<'tcx>, - rvalue_promotable_map: Option<&'tcx ItemLocalSet>, ) -> MemCategorizationContext<'a, 'tcx> { MemCategorizationContext { tcx, @@ -343,7 +340,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { upvars: tcx.upvars(body_owner), region_scope_tree, tables, - rvalue_promotable_map, infcx: None, param_env, } @@ -369,19 +365,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { ) -> MemCategorizationContext<'a, 'tcx> { let tcx = infcx.tcx; - // Subtle: we can't do rvalue promotion analysis until the - // typeck phase is complete, which means that you can't trust - // the rvalue lifetimes that result, but that's ok, since we - // don't need to know those during type inference. - let rvalue_promotable_map = None; - MemCategorizationContext { tcx, body_owner, upvars: tcx.upvars(body_owner), region_scope_tree, tables, - rvalue_promotable_map, infcx: Some(infcx), param_env, } @@ -486,7 +475,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // This code detects whether we are looking at a `ref x`, // and if so, figures out what the type *being borrowed* is. - let ret_ty = match pat.node { + let ret_ty = match pat.kind { PatKind::Binding(..) => { let bm = *self.tables .pat_binding_modes() @@ -577,7 +566,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { debug!("cat_expr: id={} expr={:?}", expr.hir_id, expr); let expr_ty = self.expr_ty(expr)?; - match expr.node { + match expr.kind { hir::ExprKind::Unary(hir::UnDeref, ref e_base) => { if self.tables.is_method_call(expr) { self.cat_overloaded_place(expr, e_base, NoteNone) @@ -664,8 +653,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { .any(|attr| attr.check_name(sym::thread_local)); let cat = if is_thread_local { - let re = self.temporary_scope(hir_id.local_id); - Categorization::ThreadLocal(re) + Categorization::ThreadLocal } else { Categorization::StaticItem }; @@ -738,18 +726,20 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { LocalDefId::from_def_id(closure_expr_def_id), ); let ty = self.node_ty(fn_hir_id)?; - let kind = match ty.sty { + let kind = match ty.kind { ty::Generator(..) => ty::ClosureKind::FnOnce, - ty::Closure(closure_def_id, closure_substs) => { + ty::Closure(closure_def_id, substs) => { match self.infcx { // During upvar inference we may not know the // closure kind, just use the LATTICE_BOTTOM value. Some(infcx) => - infcx.closure_kind(closure_def_id, closure_substs) - .unwrap_or(ty::ClosureKind::LATTICE_BOTTOM), + infcx.closure_kind( + closure_def_id, + substs + ).unwrap_or(ty::ClosureKind::LATTICE_BOTTOM), None => - closure_substs.closure_kind(closure_def_id, self.tcx.global_tcx()), + substs.as_closure().kind(closure_def_id, self.tcx), } } _ => span_bug!(span, "unexpected type for fn in mem_categorization: {:?}", ty), @@ -876,16 +866,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { ret } - /// Returns the lifetime of a temporary created by expr with id `id`. - /// This could be `'static` if `id` is part of a constant expression. - pub fn temporary_scope(&self, id: hir::ItemLocalId) -> ty::Region<'tcx> { - let scope = self.region_scope_tree.temporary_scope(id); - self.tcx.mk_region(match scope { - Some(scope) => ty::ReScope(scope), - None => ty::ReStatic - }) - } - pub fn cat_rvalue_node(&self, hir_id: hir::HirId, span: Span, @@ -894,28 +874,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { debug!("cat_rvalue_node(id={:?}, span={:?}, expr_ty={:?})", hir_id, span, expr_ty); - let promotable = self.rvalue_promotable_map.as_ref().map(|m| m.contains(&hir_id.local_id)) - .unwrap_or(false); - - debug!("cat_rvalue_node: promotable = {:?}", promotable); - - // Always promote `[T; 0]` (even when e.g., borrowed mutably). - let promotable = match expr_ty.sty { - ty::Array(_, len) if len.try_eval_usize(self.tcx, self.param_env) == Some(0) => true, - _ => promotable, - }; - - debug!("cat_rvalue_node: promotable = {:?} (2)", promotable); - - // Compute maximum lifetime of this rvalue. This is 'static if - // we can promote to a constant, otherwise equal to enclosing temp - // lifetime. - let re = if promotable { - self.tcx.lifetimes.re_static - } else { - self.temporary_scope(hir_id.local_id) - }; - let ret = self.cat_rvalue(hir_id, span, re, expr_ty); + let ret = self.cat_rvalue(hir_id, span, expr_ty); debug!("cat_rvalue_node ret {:?}", ret); ret } @@ -923,12 +882,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { pub fn cat_rvalue(&self, cmt_hir_id: hir::HirId, span: Span, - temp_scope: ty::Region<'tcx>, expr_ty: Ty<'tcx>) -> cmt_<'tcx> { let ret = cmt_ { hir_id: cmt_hir_id, span:span, - cat:Categorization::Rvalue(temp_scope), + cat:Categorization::Rvalue, mutbl:McDeclared, ty:expr_ty, note: NoteNone @@ -974,7 +932,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { let place_ty = self.expr_ty(expr)?; let base_ty = self.expr_ty_adjusted(base)?; - let (region, mutbl) = match base_ty.sty { + let (region, mutbl) = match base_ty.kind { ty::Ref(region, _, mutbl) => (region, mutbl), _ => span_bug!(expr.span, "cat_overloaded_place: base is not a reference") }; @@ -1004,7 +962,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { } }; - let ptr = match base_cmt.ty.sty { + let ptr = match base_cmt.ty.kind { ty::Adt(def, ..) if def.is_box() => Unique, ty::RawPtr(ref mt) => UnsafePtr(mt.mutbl), ty::Ref(r, _, mutbl) => { @@ -1212,7 +1170,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // that (where the `ref` on `x` is implied). op(cmt.clone(), pat); - match pat.node { + match pat.kind { PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => { let res = self.tables.qpath_res(qpath, pat.hir_id); let (cmt, expected_len) = match res { @@ -1230,7 +1188,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), _) | Res::SelfCtor(..) => { let ty = self.pat_ty_unadjusted(&pat)?; - match ty.sty { + match ty.kind { ty::Adt(adt_def, _) => { (cmt, adt_def.non_enum_variant().fields.len()) } @@ -1282,11 +1240,17 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { }; for fp in field_pats { - let field_ty = self.pat_ty_adjusted(&fp.node.pat)?; // see (*2) - let f_index = self.tcx.field_index(fp.node.hir_id, self.tables); + let field_ty = self.pat_ty_adjusted(&fp.pat)?; // see (*2) + let f_index = self.tcx.field_index(fp.hir_id, self.tables); let cmt_field = Rc::new(self.cat_field(pat, cmt.clone(), f_index, - fp.node.ident, field_ty)); - self.cat_pattern_(cmt_field, &fp.node.pat, op)?; + fp.ident, field_ty)); + self.cat_pattern_(cmt_field, &fp.pat, op)?; + } + } + + PatKind::Or(ref pats) => { + for pat in pats { + self.cat_pattern_(cmt.clone(), &pat, op)?; } } @@ -1297,7 +1261,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { PatKind::Tuple(ref subpats, ddpos) => { // (p1, ..., pN) let ty = self.pat_ty_unadjusted(&pat)?; - let expected_len = match ty.sty { + let expected_len = match ty.kind { ty::Tuple(ref tys) => tys.len(), _ => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty), }; @@ -1370,9 +1334,9 @@ impl<'tcx> cmt_<'tcx> { //! determines how long the value in `self` remains live. match self.cat { - Categorization::Rvalue(..) | + Categorization::Rvalue | Categorization::StaticItem | - Categorization::ThreadLocal(..) | + Categorization::ThreadLocal | Categorization::Local(..) | Categorization::Deref(_, UnsafePtr(..)) | Categorization::Deref(_, BorrowedPtr(..)) | @@ -1403,8 +1367,8 @@ impl<'tcx> cmt_<'tcx> { b.freely_aliasable() } - Categorization::Rvalue(..) | - Categorization::ThreadLocal(..) | + Categorization::Rvalue | + Categorization::ThreadLocal | Categorization::Local(..) | Categorization::Upvar(..) | Categorization::Deref(_, UnsafePtr(..)) => { // yes, it's aliasable, but... @@ -1451,10 +1415,10 @@ impl<'tcx> cmt_<'tcx> { Categorization::StaticItem => { "static item".into() } - Categorization::ThreadLocal(..) => { + Categorization::ThreadLocal => { "thread-local static item".into() } - Categorization::Rvalue(..) => { + Categorization::Rvalue => { "non-place".into() } Categorization::Local(vid) => { diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 76d8a6738f087..8be64bf64b5e9 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -32,7 +32,10 @@ fn item_might_be_inlined(tcx: TyCtxt<'tcx>, item: &hir::Item, attrs: CodegenFnAt return true } - match item.node { + match item.kind { + hir::ItemKind::Fn(_, header, ..) if header.is_const() => { + return true; + } hir::ItemKind::Impl(..) | hir::ItemKind::Fn(..) => { let generics = tcx.generics_of(tcx.hir().local_def_id(item.hir_id)); @@ -52,6 +55,11 @@ fn method_might_be_inlined( if codegen_fn_attrs.requests_inline() || generics.requires_monomorphization(tcx) { return true } + if let hir::ImplItemKind::Method(method_sig, _) = &impl_item.kind { + if method_sig.header.is_const() { + return true + } + } if let Some(impl_hir_id) = tcx.hir().as_local_hir_id(impl_src) { match tcx.hir().find(impl_hir_id) { Some(Node::Item(item)) => @@ -92,7 +100,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> { } fn visit_expr(&mut self, expr: &'tcx hir::Expr) { - let res = match expr.node { + let res = match expr.kind { hir::ExprKind::Path(ref qpath) => { Some(self.tables.qpath_res(qpath, expr.hir_id)) } @@ -149,14 +157,14 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { match self.tcx.hir().find(hir_id) { Some(Node::Item(item)) => { - match item.node { + match item.kind { hir::ItemKind::Fn(..) => item_might_be_inlined(self.tcx, &item, self.tcx.codegen_fn_attrs(def_id)), _ => false, } } Some(Node::TraitItem(trait_method)) => { - match trait_method.node { + match trait_method.kind { hir::TraitItemKind::Const(_, ref default) => default.is_some(), hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => true, hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) | @@ -164,7 +172,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { } } Some(Node::ImplItem(impl_item)) => { - match impl_item.node { + match impl_item.kind { hir::ImplItemKind::Const(..) => true, hir::ImplItemKind::Method(..) => { let attrs = self.tcx.codegen_fn_attrs(def_id); @@ -179,7 +187,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // type of the impl require inlining, this method // does too. let impl_hir_id = self.tcx.hir().as_local_hir_id(impl_did).unwrap(); - match self.tcx.hir().expect_item(impl_hir_id).node { + match self.tcx.hir().expect_item(impl_hir_id).kind { hir::ItemKind::Impl(..) => { let generics = self.tcx.generics_of(impl_did); generics.requires_monomorphization(self.tcx) @@ -217,7 +225,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // If we are building an executable, only explicitly extern // types need to be exported. if let Node::Item(item) = *node { - let reachable = if let hir::ItemKind::Fn(_, header, ..) = item.node { + let reachable = if let hir::ItemKind::Fn(_, header, ..) = item.kind { header.abi != Abi::Rust } else { false @@ -241,7 +249,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { match *node { Node::Item(item) => { - match item.node { + match item.kind { hir::ItemKind::Fn(.., body) => { let def_id = self.tcx.hir().local_def_id(item.hir_id); if item_might_be_inlined(self.tcx, @@ -278,7 +286,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { } } Node::TraitItem(trait_method) => { - match trait_method.node { + match trait_method.kind { hir::TraitItemKind::Const(_, None) | hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) => { // Keep going, nothing to get exported @@ -291,7 +299,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { } } Node::ImplItem(impl_item) => { - match impl_item.node { + match impl_item.kind { hir::ImplItemKind::Const(_, body) => { self.visit_nested_body(body); } @@ -305,7 +313,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::ImplItemKind::TyAlias(_) => {} } } - Node::Expr(&hir::Expr { node: hir::ExprKind::Closure(.., body, _, _), .. }) => { + Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(.., body, _, _), .. }) => { self.visit_nested_body(body); } // Nothing to recurse on for these @@ -353,7 +361,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx } // We need only trait impls here, not inherent impls, and only non-exported ones - if let hir::ItemKind::Impl(.., Some(ref trait_ref), _, ref impl_item_refs) = item.node { + if let hir::ItemKind::Impl(.., Some(ref trait_ref), _, ref impl_item_refs) = item.kind { if !self.access_levels.is_reachable(item.hir_id) { self.worklist.extend(impl_item_refs.iter().map(|ii_ref| ii_ref.id.hir_id)); diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 88c19715811d7..9ff205228a566 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -6,29 +6,27 @@ //! //! [rustc guide]: https://rust-lang.github.io/rustc-guide/mir/borrowck.html +use crate::hir; +use crate::hir::Node; +use crate::hir::def_id::DefId; +use crate::hir::intravisit::{self, Visitor, NestedVisitorMap}; +use crate::hir::{Block, Arm, Pat, PatKind, Stmt, Expr, Local}; use crate::ich::{StableHashingContext, NodeIdHashingMode}; use crate::util::nodemap::{FxHashMap, FxHashSet}; -use crate::ty; +use crate::ty::{self, DefIdTree, TyCtxt}; +use crate::ty::query::Providers; -use std::mem; -use std::fmt; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_index::vec::Idx; use rustc_macros::HashStable; use syntax::source_map; use syntax_pos::{Span, DUMMY_SP}; -use crate::ty::{DefIdTree, TyCtxt}; -use crate::ty::query::Providers; -use crate::hir; -use crate::hir::Node; -use crate::hir::def_id::DefId; -use crate::hir::intravisit::{self, Visitor, NestedVisitorMap}; -use crate::hir::{Block, Arm, Pat, PatKind, Stmt, Expr, Local}; -use rustc_data_structures::indexed_vec::Idx; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, - StableHasherResult}; +use std::fmt; +use std::mem; -/// Scope represents a statically-describable scope that can be -/// used to bound the lifetime/region for values. +/// Represents a statically-describable scope that can be used to +/// bound the lifetime/region for values. /// /// `Node(node_id)`: Any AST node that has any scope at all has the /// `Node(node_id)` scope. Other variants represent special cases not @@ -133,7 +131,7 @@ pub enum ScopeData { Remainder(FirstStatementIndex) } -newtype_index! { +rustc_index::newtype_index! { /// Represents a subscope of `block` for a binding that is introduced /// by `block.stmts[first_statement_index]`. Such subscopes represent /// a suffix of the block. Note that each subscope does not include @@ -225,7 +223,7 @@ pub struct ScopeTree { /// have lifetime parameters free in this body. root_parent: Option, - /// `parent_map` maps from a scope ID to the enclosing scope id; + /// Maps from a scope ID to the enclosing scope id; /// this is usually corresponding to the lexical nesting, though /// in the case of closures the parent scope is the innermost /// conditional expression or repeating block. (Note that the @@ -233,17 +231,17 @@ pub struct ScopeTree { /// the closure itself.) parent_map: FxHashMap, - /// `var_map` maps from a variable or binding ID to the block in - /// which that variable is declared. + /// Maps from a variable or binding ID to the block in which that + /// variable is declared. var_map: FxHashMap, - /// maps from a `NodeId` to the associated destruction scope (if any) + /// Maps from a `NodeId` to the associated destruction scope (if any). destruction_scopes: FxHashMap, - /// `rvalue_scopes` includes entries for those expressions whose cleanup scope is - /// larger than the default. The map goes from the expression id - /// to the cleanup scope id. For rvalues not present in this - /// table, the appropriate cleanup scope is the innermost + /// `rvalue_scopes` includes entries for those expressions whose + /// cleanup scope is larger than the default. The map goes from the + /// expression ID to the cleanup scope id. For rvalues not present in + /// this table, the appropriate cleanup scope is the innermost /// enclosing statement, conditional expression, or repeating /// block (see `terminating_scopes`). /// In constants, None is used to indicate that certain expressions @@ -318,7 +316,7 @@ pub struct ScopeTree { /// 4. By `2.` and `3.`, `D` is *statically* storage-dead at `U`, /// QED. /// - /// I don't think this property relies on `3.` in an essential way - it + /// This property ought to not on (3) in an essential way -- it /// is probably still correct even if we have "unrestricted" terminating /// scopes. However, why use the complicated proof when a simple one /// works? @@ -341,20 +339,20 @@ pub struct ScopeTree { #[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)] pub struct YieldData { - /// `Span` of the yield. + /// The `Span` of the yield. pub span: Span, - /// The number of expressions and patterns appearing before the `yield` in the body + 1. + /// The number of expressions and patterns appearing before the `yield` in the body plus one. pub expr_and_pat_count: usize, pub source: hir::YieldSource, } #[derive(Debug, Copy, Clone)] pub struct Context { - /// the root of the current region tree. This is typically the id + /// The root of the current region tree. This is typically the id /// of the innermost fn body. Each fn forms its own disjoint tree /// in the region hierarchy. These fn bodies are themselves /// arranged into a tree. See the "Modeling closures" section of - /// the README in infer::region_constraints for more + /// the README in `infer::region_constraints` for more /// details. root_id: Option, @@ -369,15 +367,15 @@ pub struct Context { struct RegionResolutionVisitor<'tcx> { tcx: TyCtxt<'tcx>, - // The number of expressions and patterns visited in the current body + // The number of expressions and patterns visited in the current body. expr_and_pat_count: usize, // When this is `true`, we record the `Scopes` we encounter // when processing a Yield expression. This allows us to fix // up their indices. pessimistic_yield: bool, - // Stores scopes when pessimistic_yield is true. + // Stores scopes when `pessimistic_yield` is `true`. fixup_scopes: Vec, - // Generated scope tree: + // The generated scope tree. scope_tree: ScopeTree, cx: Context, @@ -411,7 +409,7 @@ struct ExprLocatorVisitor { expr_and_pat_count: usize, } -// This visitor has to have the same visit_expr calls as RegionResolutionVisitor +// This visitor has to have the same `visit_expr` calls as `RegionResolutionVisitor` // since `expr_count` is compared against the results there. impl<'tcx> Visitor<'tcx> for ExprLocatorVisitor { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { @@ -456,7 +454,7 @@ impl<'tcx> ScopeTree { assert!(prev.is_none()); } - // record the destruction scopes for later so we can query them + // Record the destruction scopes for later so we can query them. if let ScopeData::Destruction = child.data { self.destruction_scopes.insert(child.item_local_id(), child); } @@ -478,7 +476,7 @@ impl<'tcx> ScopeTree { self.destruction_scopes.get(&n).cloned() } - /// Records that `sub_closure` is defined within `sup_closure`. These ids + /// Records that `sub_closure` is defined within `sup_closure`. These IDs /// should be the ID of the block that is the fn body, which is /// also the root of the region hierarchy for that fn. fn record_closure_parent(&mut self, @@ -505,14 +503,14 @@ impl<'tcx> ScopeTree { self.rvalue_scopes.insert(var, lifetime); } + /// Returns the narrowest scope that encloses `id`, if any. pub fn opt_encl_scope(&self, id: Scope) -> Option { - //! Returns the narrowest scope that encloses `id`, if any. self.parent_map.get(&id).cloned().map(|(p, _)| p) } + /// Returns the narrowest scope that encloses `id`, if any. #[allow(dead_code)] // used in cfg pub fn encl_scope(&self, id: Scope) -> Scope { - //! Returns the narrowest scope that encloses `id`, if any. self.opt_encl_scope(id).unwrap() } @@ -522,16 +520,15 @@ impl<'tcx> ScopeTree { bug!("no enclosing scope for id {:?}", var_id)) } + /// Returns the scope when the temp created by `expr_id` will be cleaned up. pub fn temporary_scope(&self, expr_id: hir::ItemLocalId) -> Option { - //! Returns the scope when temp created by expr_id will be cleaned up - - // check for a designated rvalue scope + // Check for a designated rvalue scope. if let Some(&s) = self.rvalue_scopes.get(&expr_id) { debug!("temporary_scope({:?}) = {:?} [custom]", expr_id, s); return s; } - // else, locate the innermost terminating scope + // Otherwise, locate the innermost terminating scope // if there's one. Static items, for instance, won't // have an enclosing scope, hence no scope will be // returned. @@ -552,9 +549,8 @@ impl<'tcx> ScopeTree { return None; } + /// Returns the lifetime of the variable `id`. pub fn var_region(&self, id: hir::ItemLocalId) -> ty::RegionKind { - //! Returns the lifetime of the variable `id`. - let scope = ty::ReScope(self.var_scope(id)); debug!("var_region({:?}) = {:?}", id, scope); scope @@ -589,7 +585,7 @@ impl<'tcx> ScopeTree { return true; } - /// Returns the ID of the innermost containing body + /// Returns the ID of the innermost containing body. pub fn containing_body(&self, mut scope: Scope) -> Option { loop { if let ScopeData::CallSite = scope.data { @@ -800,7 +796,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h // index information.) for (i, statement) in blk.stmts.iter().enumerate() { - match statement.node { + match statement.kind { hir::StmtKind::Local(..) | hir::StmtKind::Item(..) => { // Each declaration introduces a subscope for bindings @@ -854,7 +850,7 @@ fn resolve_pat<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, pat: &'tcx hir visitor.record_child_scope(Scope { id: pat.hir_id.local_id, data: ScopeData::Node }); // If this is a binding then record the lifetime of that binding. - if let PatKind::Binding(..) = pat.node { + if let PatKind::Binding(..) = pat.kind { record_var_lifetime(visitor, pat.hir_id.local_id, pat.span); } @@ -897,7 +893,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h let mut terminating = |id: hir::ItemLocalId| { terminating_scopes.insert(id); }; - match expr.node { + match expr.kind { // Conditional or repeating scopes are always terminating // scopes, meaning that temporaries cannot outlive them. // This ensures fixed size stacks. @@ -1000,7 +996,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h // properly, we can't miss any types. - match expr.node { + match expr.kind { // Manually recurse over closures, because they are the only // case of nested bodies that share the parent environment. hir::ExprKind::Closure(.., body, _, _) => { @@ -1057,7 +1053,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h debug!("resolve_expr post-increment {}, expr = {:?}", visitor.expr_and_pat_count, expr); - if let hir::ExprKind::Yield(_, source) = &expr.node { + if let hir::ExprKind::Yield(_, source) = &expr.kind { // Mark this expr's scope and all parent scopes as containing `yield`. let mut scope = Scope { id: expr.hir_id.local_id, data: ScopeData::Node }; loop { @@ -1140,7 +1136,7 @@ fn resolve_local<'tcx>( // Rule A. `let (ref x, ref y) = (foo().x, 44)`. The rvalue `(22, 44)` // would have an extended lifetime, but not `foo()`. // - // Rule B. `let x = &foo().x`. The rvalue ``foo()` would have extended + // Rule B. `let x = &foo().x`. The rvalue `foo()` would have extended // lifetime. // // In some cases, multiple rules may apply (though not to the same @@ -1202,12 +1198,12 @@ fn resolve_local<'tcx>( // In the former case (the implicit ref version), the temporary is created by the // & expression, and its lifetime would be extended to the end of the block (due // to a different rule, not the below code). - match pat.node { + match pat.kind { PatKind::Binding(hir::BindingAnnotation::Ref, ..) | PatKind::Binding(hir::BindingAnnotation::RefMut, ..) => true, PatKind::Struct(_, ref field_pats, _) => { - field_pats.iter().any(|fp| is_binding_pat(&fp.node.pat)) + field_pats.iter().any(|fp| is_binding_pat(&fp.pat)) } PatKind::Slice(ref pats1, ref pats2, ref pats3) => { @@ -1244,7 +1240,7 @@ fn resolve_local<'tcx>( expr: &hir::Expr, blk_id: Option, ) { - match expr.node { + match expr.kind { hir::ExprKind::AddrOf(_, ref subexpr) => { record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id); record_rvalue_scope(visitor, &subexpr, blk_id); @@ -1304,7 +1300,7 @@ fn resolve_local<'tcx>( // outer expression. visitor.scope_tree.record_rvalue_scope(expr.hir_id.local_id, blk_scope); - match expr.node { + match expr.kind { hir::ExprKind::AddrOf(_, ref subexpr) | hir::ExprKind::Unary(hir::UnDeref, ref subexpr) | hir::ExprKind::Field(ref subexpr, _) | @@ -1383,8 +1379,8 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { // The arguments and `self` are parented to the fn. self.cx.var_parent = self.cx.parent.take(); - for argument in &body.arguments { - self.visit_pat(&argument.pat); + for param in &body.params { + self.visit_pat(¶m.pat); } // The body of the every fn is a root scope. @@ -1495,9 +1491,7 @@ pub fn provide(providers: &mut Providers<'_>) { } impl<'a> HashStable> for ScopeTree { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ScopeTree { root_body, root_parent, diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index f8f01f79e1db4..31d250fa08215 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -5,6 +5,8 @@ //! used between functions, and they operate in a purely top-down //! way. Therefore, we break lifetime name resolution into a separate pass. +// ignore-tidy-filelength + use crate::hir::def::{Res, DefKind}; use crate::hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use crate::hir::map::Map; @@ -15,7 +17,7 @@ use crate::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; use crate::rustc::lint; use crate::session::Session; use crate::util::nodemap::{DefIdMap, FxHashMap, FxHashSet, HirIdMap, HirIdSet}; -use errors::{Applicability, DiagnosticBuilder}; +use errors::{Applicability, DiagnosticBuilder, pluralise}; use rustc_macros::HashStable; use std::borrow::Cow; use std::cell::Cell; @@ -457,7 +459,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } fn visit_item(&mut self, item: &'tcx hir::Item) { - match item.node { + match item.kind { hir::ItemKind::Fn(ref decl, _, ref generics, _) => { self.visit_early_late(None, decl, generics, |this| { intravisit::walk_item(this, item); @@ -502,12 +504,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { | hir::ItemKind::Impl(_, _, _, 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 { + let track_lifetime_uses = match item.kind { hir::ItemKind::Impl(..) => true, _ => false, }; // These kinds of items have only early-bound lifetime parameters. - let mut index = if sub_items_have_self_param(&item.node) { + let mut index = if sub_items_have_self_param(&item.kind) { 1 // Self comes before lifetimes } else { 0 @@ -539,7 +541,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) { - match item.node { + match item.kind { hir::ForeignItemKind::Fn(ref decl, _, ref generics) => { self.visit_early_late(None, decl, generics, |this| { intravisit::walk_foreign_item(this, item); @@ -556,7 +558,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty) { debug!("visit_ty: id={:?} ty={:?}", ty.hir_id, ty); - match ty.node { + debug!("visit_ty: ty.kind={:?}", ty.kind); + match ty.kind { hir::TyKind::BareFn(ref c) => { let next_early_index = self.next_early_index(); let was_in_fn_syntax = self.is_in_fn_syntax; @@ -585,11 +588,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { self.is_in_fn_syntax = was_in_fn_syntax; } hir::TyKind::TraitObject(ref bounds, ref lifetime) => { + debug!("visit_ty: TraitObject(bounds={:?}, lifetime={:?})", bounds, lifetime); for bound in bounds { self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); } match lifetime.name { LifetimeName::Implicit => { + // For types like `dyn Foo`, we should + // generate a special form of elided. + span_bug!( + ty.span, + "object-lifetime-default expected, not implict", + ); + } + LifetimeName::ImplicitObjectLifetimeDefault => { // If the user does not write *anything*, we // use the object lifetime defaulting // rules. So e.g., `Box` becomes @@ -625,8 +637,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // `type MyAnonTy<'b> = impl MyTrait<'b>;` // ^ ^ this gets resolved in the scope of // the opaque_ty generics - let (generics, bounds) = match self.tcx.hir().expect_item(item_id.id).node - { + let (generics, bounds) = match self.tcx.hir().expect_item(item_id.id).kind { // Named opaque `impl Trait` types are reached via `TyKind::Path`. // This arm is for `impl Trait` in the types of statics, constants and locals. hir::ItemKind::OpaqueTy(hir::OpaqueTy { @@ -753,20 +764,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }); } } - hir::TyKind::CVarArgs(ref lt) => { - // Resolve the generated lifetime for the C-variadic arguments. - // The lifetime is generated in AST -> HIR lowering. - if lt.name.is_elided() { - self.resolve_elided_lifetimes(vec![lt]) - } - } _ => intravisit::walk_ty(self, ty), } } fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { use self::hir::TraitItemKind::*; - match trait_item.node { + match trait_item.kind { Method(ref sig, _) => { let tcx = self.tcx; self.visit_early_late( @@ -818,7 +822,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { use self::hir::ImplItemKind::*; - match impl_item.node { + match impl_item.kind { Method(ref sig, _) => { let tcx = self.tcx; self.visit_early_late( @@ -897,6 +901,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { + debug!("visit_lifetime(lifetime_ref={:?})", lifetime_ref); if lifetime_ref.is_elided() { self.resolve_elided_lifetimes(vec![lifetime_ref]); return; @@ -1201,7 +1206,7 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body) { } fn expression_label(ex: &hir::Expr) -> Option { - if let hir::ExprKind::Loop(_, Some(label), _) = ex.node { + if let hir::ExprKind::Loop(_, Some(label), _) = ex.kind { Some(label.ident) } else { None @@ -1250,7 +1255,7 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body) { fn compute_object_lifetime_defaults(tcx: TyCtxt<'_>) -> HirIdMap> { let mut map = HirIdMap::default(); for item in tcx.hir().krate().items.values() { - match item.node { + match item.kind { hir::ItemKind::Struct(_, ref generics) | hir::ItemKind::Union(_, ref generics) | hir::ItemKind::Enum(_, ref generics) @@ -1339,7 +1344,7 @@ fn object_lifetime_defaults_for_item( continue; } - let res = match data.bounded_ty.node { + let res = match data.bounded_ty.kind { hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.res, _ => continue, }; @@ -1474,7 +1479,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let mut elide_use = None; let mut find_arg_use_span = |inputs: &hir::HirVec| { for input in inputs { - match input.node { + match input.kind { hir::TyKind::Rptr(lt, _) => { if lt.name.ident() == name { // include the trailing whitespace between the lifetime and type names @@ -1512,12 +1517,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { { match parent { Node::Item(item) => { - if let hir::ItemKind::Fn(decl, _, _, _) = &item.node { + if let hir::ItemKind::Fn(decl, _, _, _) = &item.kind { find_arg_use_span(&decl.inputs); } }, Node::ImplItem(impl_item) => { - if let hir::ImplItemKind::Method(sig, _) = &impl_item.node { + if let hir::ImplItemKind::Method(sig, _) = &impl_item.kind { find_arg_use_span(&sig.decl.inputs); } } @@ -1720,10 +1725,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let mut index = 0; if let Some(parent_id) = parent_id { let parent = self.tcx.hir().expect_item(parent_id); - if sub_items_have_self_param(&parent.node) { + if sub_items_have_self_param(&parent.kind) { index += 1; // Self comes before lifetimes } - match parent.node { + match parent.kind { hir::ItemKind::Trait(_, _, ref generics, ..) | hir::ItemKind::Impl(_, _, _, ref generics, ..) => { index += generics.params.len() as u32; @@ -1854,15 +1859,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let fn_id = self.tcx.hir().body_owner(body_id); match self.tcx.hir().get(fn_id) { Node::Item(&hir::Item { - node: hir::ItemKind::Fn(..), + kind: hir::ItemKind::Fn(..), .. }) | Node::TraitItem(&hir::TraitItem { - node: hir::TraitItemKind::Method(..), + kind: hir::TraitItemKind::Method(..), .. }) | Node::ImplItem(&hir::ImplItem { - node: hir::ImplItemKind::Method(..), + kind: hir::ImplItemKind::Method(..), .. }) => { let scope = self.tcx.hir().local_def_id(fn_id); @@ -1911,6 +1916,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } fn visit_segment_args(&mut self, res: Res, depth: usize, generic_args: &'tcx hir::GenericArgs) { + debug!( + "visit_segment_args(res={:?}, depth={:?}, generic_args={:?})", + res, + depth, + generic_args, + ); + if generic_args.parenthesized { let was_in_fn_syntax = self.is_in_fn_syntax; self.is_in_fn_syntax = true; @@ -1964,6 +1976,23 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { _ => None, }; + debug!("visit_segment_args: type_def_id={:?}", type_def_id); + + // Compute a vector of defaults, one for each type parameter, + // per the rules given in RFCs 599 and 1156. Example: + // + // ```rust + // struct Foo<'a, T: 'a, U> { } + // ``` + // + // If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default + // `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound) + // and `dyn Baz` to `dyn Baz + 'static` (because there is no + // such bound). + // + // Therefore, we would compute `object_lifetime_defaults` to a + // vector like `['x, 'static]`. Note that the vector only + // includes type parameters. let object_lifetime_defaults = type_def_id.map_or(vec![], |def_id| { let in_body = { let mut scope = self.scope; @@ -2003,6 +2032,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { .collect() }) }; + debug!("visit_segment_args: unsubst={:?}", unsubst); unsubst .iter() .map(|set| match *set { @@ -2023,6 +2053,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { .collect() }); + debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults); + let mut i = 0; for arg in &generic_args.args { match arg { @@ -2045,8 +2077,49 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } + // Hack: when resolving the type `XX` in binding like `dyn + // Foo<'b, Item = XX>`, the current object-lifetime default + // would be to examine the trait `Foo` to check whether it has + // a lifetime bound declared on `Item`. e.g., if `Foo` is + // declared like so, then the default object lifetime bound in + // `XX` should be `'b`: + // + // ```rust + // trait Foo<'a> { + // type Item: 'a; + // } + // ``` + // + // but if we just have `type Item;`, then it would be + // `'static`. However, we don't get all of this logic correct. + // + // Instead, we do something hacky: if there are no lifetime parameters + // to the trait, then we simply use a default object lifetime + // bound of `'static`, because there is no other possibility. On the other hand, + // if there ARE lifetime parameters, then we require the user to give an + // explicit bound for now. + // + // This is intended to leave room for us to implement the + // correct behavior in the future. + let has_lifetime_parameter = generic_args + .args + .iter() + .any(|arg| match arg { + GenericArg::Lifetime(_) => true, + _ => false, + }); + + // Resolve lifetimes found in the type `XX` from `Item = XX` bindings. for b in &generic_args.bindings { - self.visit_assoc_type_binding(b); + let scope = Scope::ObjectLifetimeDefault { + lifetime: if has_lifetime_parameter { + None + } else { + Some(Region::Static) + }, + s: self.scope, + }; + self.with(scope, |_, this| this.visit_assoc_type_binding(b)); } } @@ -2084,18 +2157,18 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let body = match self.tcx.hir().get(parent) { // `fn` definitions and methods. Node::Item(&hir::Item { - node: hir::ItemKind::Fn(.., body), + kind: hir::ItemKind::Fn(.., body), .. }) => Some(body), Node::TraitItem(&hir::TraitItem { - node: hir::TraitItemKind::Method(_, ref m), + kind: hir::TraitItemKind::Method(_, ref m), .. }) => { if let hir::ItemKind::Trait(.., ref trait_items) = self.tcx .hir() .expect_item(self.tcx.hir().get_parent_item(parent)) - .node + .kind { assoc_item_kind = trait_items .iter() @@ -2109,13 +2182,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } Node::ImplItem(&hir::ImplItem { - node: hir::ImplItemKind::Method(_, body), + kind: hir::ImplItemKind::Method(_, body), .. }) => { if let hir::ItemKind::Impl(.., ref self_ty, ref impl_items) = self.tcx .hir() .expect_item(self.tcx.hir().get_parent_item(parent)) - .node + .kind { impl_self = Some(self_ty); assoc_item_kind = impl_items @@ -2189,8 +2262,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } fn visit_ty(&mut self, ty: &'a hir::Ty) { - if let hir::TyKind::Rptr(lifetime_ref, ref mt) = ty.node { - if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.node + if let hir::TyKind::Rptr(lifetime_ref, ref mt) = ty.kind { + if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.kind { if self.is_self_ty(path.res) { if let Some(lifetime) = self.map.defs.get(&lifetime_ref.hir_id) { @@ -2205,7 +2278,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let mut visitor = SelfVisitor { map: self.map, - impl_self: impl_self.map(|ty| &ty.node), + impl_self: impl_self.map(|ty| &ty.kind), lifetime: Set1::Empty, }; visitor.visit_ty(&inputs[0]); @@ -2283,10 +2356,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } fn visit_ty(&mut self, ty: &hir::Ty) { - if let hir::TyKind::BareFn(_) = ty.node { + if let hir::TyKind::BareFn(_) = ty.kind { self.outer_index.shift_in(1); } - match ty.node { + match ty.kind { hir::TyKind::TraitObject(ref bounds, ref lifetime) => { for bound in bounds { self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); @@ -2298,12 +2371,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.visit_lifetime(lifetime); } } - hir::TyKind::CVarArgs(_) => {} _ => { intravisit::walk_ty(self, ty); } } - if let hir::TyKind::BareFn(_) = ty.node { + if let hir::TyKind::BareFn(_) = ty.kind { self.outer_index.shift_out(1); } } @@ -2347,6 +2419,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } fn resolve_elided_lifetimes(&mut self, lifetime_refs: Vec<&'tcx hir::Lifetime>) { + debug!("resolve_elided_lifetimes(lifetime_refs={:?})", lifetime_refs); + if lifetime_refs.is_empty() { return; } @@ -2474,7 +2548,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } = info; let help_name = if let Some(ident) = parent.and_then(|body| { - self.tcx.hir().body(body).arguments[index].pat.simple_ident() + self.tcx.hir().body(body).params[index].pat.simple_ident() }) { format!("`{}`", ident) } else { @@ -2539,6 +2613,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) { + debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref); let mut late_depth = 0; let mut scope = self.scope; let lifetime = loop { @@ -2638,6 +2713,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => { self.resolve_lifetime_ref(lt); } + hir::LifetimeName::ImplicitObjectLifetimeDefault => { + self.tcx.sess.delay_span_bug( + lt.span, + "lowering generated `ImplicitObjectLifetimeDefault` \ + outside of an object type", + ) + } hir::LifetimeName::Error => { // No need to do anything, error already reported. } @@ -2900,7 +2982,7 @@ fn insert_late_bound_lifetimes( } fn visit_ty(&mut self, ty: &'v hir::Ty) { - match ty.node { + match ty.kind { hir::TyKind::Path(hir::QPath::Resolved(Some(_), _)) | hir::TyKind::Path(hir::QPath::TypeRelative(..)) => { // ignore lifetimes appearing in associated type @@ -2956,7 +3038,7 @@ pub fn report_missing_lifetime_specifiers( span, E0106, "missing lifetime specifier{}", - if count > 1 { "s" } else { "" } + pluralise!(count) ) } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 5ab762ab225f9..302c11f309d90 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -199,8 +199,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let name = attr.name_or_empty(); if [sym::unstable, sym::stable, sym::rustc_deprecated].contains(&name) { attr::mark_used(attr); - self.tcx.sess.span_err(attr.span, "stability attributes may not be used \ - outside of the standard library"); + struct_span_err!( + self.tcx.sess, + attr.span, + E0734, + "stability attributes may not be used outside of the standard library", + ).emit(); } } @@ -246,7 +250,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn visit_item(&mut self, i: &'tcx Item) { let orig_in_trait_impl = self.in_trait_impl; let mut kind = AnnotationKind::Required; - match i.node { + match i.kind { // Inherent impls and foreign modules serve only as containers for other items, // they don't have their own stability. They still can be annotated as unstable // and propagate this unstability to children, but this annotation is completely @@ -290,10 +294,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: HirId) { - self.annotate(var.node.id, &var.node.attrs, var.span, AnnotationKind::Required, + self.annotate(var.id, &var.attrs, var.span, AnnotationKind::Required, |v| { - if let Some(ctor_hir_id) = var.node.data.ctor_hir_id() { - v.annotate(ctor_hir_id, &var.node.attrs, var.span, AnnotationKind::Required, + if let Some(ctor_hir_id) = var.data.ctor_hir_id() { + v.annotate(ctor_hir_id, &var.attrs, var.span, AnnotationKind::Required, |_| {}); } @@ -344,14 +348,14 @@ impl<'a, 'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'a, 'tcx> { } fn visit_item(&mut self, i: &'tcx Item) { - match i.node { + match i.kind { // Inherent impls and foreign modules serve only as containers for other items, // they don't have their own stability. They still can be annotated as unstable // and propagate this unstability to children, but this annotation is completely // optional. They inherit stability from their parents when unannotated. hir::ItemKind::Impl(.., None, _, _) | hir::ItemKind::ForeignMod(..) => {} - _ => self.check_missing_stability(i.hir_id, i.span, i.node.descriptive_variant()) + _ => self.check_missing_stability(i.hir_id, i.span, i.kind.descriptive_variant()) } intravisit::walk_item(self, i) @@ -372,7 +376,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'a, 'tcx> { } fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: HirId) { - self.check_missing_stability(var.node.id, var.span, "variant"); + self.check_missing_stability(var.id, var.span, "variant"); intravisit::walk_variant(self, var, g, item_id); } @@ -382,7 +386,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'a, 'tcx> { } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem) { - self.check_missing_stability(i.hir_id, i.span, i.node.descriptive_variant()); + self.check_missing_stability(i.hir_id, i.span, i.kind.descriptive_variant()); intravisit::walk_foreign_item(self, i); } @@ -438,6 +442,7 @@ impl<'tcx> Index<'tcx> { level: attr::StabilityLevel::Unstable { reason: Some(Symbol::intern(reason)), issue: 27812, + is_soft: false, }, feature: sym::rustc_private, rustc_depr: None, @@ -480,7 +485,13 @@ pub fn provide(providers: &mut Providers<'_>) { } pub fn report_unstable( - sess: &Session, feature: Symbol, reason: Option, issue: u32, span: Span + sess: &Session, + feature: Symbol, + reason: Option, + issue: u32, + is_soft: bool, + span: Span, + soft_handler: impl FnOnce(&'static lint::Lint, Span, &str), ) { let msg = match reason { Some(r) => format!("use of unstable library feature '{}': {}", feature, r), @@ -505,7 +516,13 @@ pub fn report_unstable( let error_id = (DiagnosticMessageId::StabilityId(issue), span_key, msg.clone()); let fresh = sess.one_time_diagnostics.borrow_mut().insert(error_id); if fresh { - emit_feature_err(&sess.parse_sess, feature, span, GateIssue::Library(Some(issue)), &msg); + if is_soft { + soft_handler(lint::builtin::SOFT_UNSTABLE, span, &msg) + } else { + emit_feature_err( + &sess.parse_sess, feature, span, GateIssue::Library(Some(issue)), &msg + ); + } } } @@ -621,6 +638,7 @@ pub enum EvalResult { feature: Symbol, reason: Option, issue: u32, + is_soft: bool, }, /// The item does not have the `#[stable]` or `#[unstable]` marker assigned. Unmarked, @@ -720,7 +738,9 @@ impl<'tcx> TyCtxt<'tcx> { } match stability { - Some(&Stability { level: attr::Unstable { reason, issue }, feature, .. }) => { + Some(&Stability { + level: attr::Unstable { reason, issue, is_soft }, feature, .. + }) => { if span.allows_unstable(feature) { debug!("stability: skipping span={:?} since it is internal", span); return EvalResult::Allow; @@ -744,7 +764,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - EvalResult::Deny { feature, reason, issue } + EvalResult::Deny { feature, reason, issue, is_soft } } Some(_) => { // Stable APIs are always ok to call and deprecated APIs are @@ -765,10 +785,12 @@ impl<'tcx> TyCtxt<'tcx> { /// Additionally, this function will also check if the item is deprecated. If so, and `id` is /// not `None`, a deprecated lint attached to `id` will be emitted. pub fn check_stability(self, def_id: DefId, id: Option, span: Span) { + let soft_handler = + |lint, span, msg: &_| self.lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, msg); match self.eval_stability(def_id, id, span) { EvalResult::Allow => {} - EvalResult::Deny { feature, reason, issue } => - report_unstable(self.sess, feature, reason, issue, span), + EvalResult::Deny { feature, reason, issue, is_soft } => + report_unstable(self.sess, feature, reason, issue, is_soft, span, soft_handler), EvalResult::Unmarked => { // The API could be uncallable for other reasons, for example when a private module // was referenced. @@ -787,7 +809,7 @@ impl Visitor<'tcx> for Checker<'tcx> { } fn visit_item(&mut self, item: &'tcx hir::Item) { - match item.node { + match item.kind { hir::ItemKind::ExternCrate(_) => { // compiler-generated `extern crate` items have a dummy span. if item.span.is_dummy() { return } diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 4fb88dadd1f44..fa5fa2257dbc8 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -116,8 +116,8 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, } impl<'a, 'tcx> Context<'a, 'tcx> { - fn register(&mut self, name: &str, span: Span) { - $(if name == stringify!($name) { + fn register(&mut self, name: Symbol, span: Span) { + $(if name == sym::$name { if self.items.$name().is_none() { self.items.missing.push(lang_items::$item); } @@ -136,7 +136,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { fn visit_foreign_item(&mut self, i: &hir::ForeignItem) { if let Some((lang_item, _)) = lang_items::extract(&i.attrs) { - self.register(&lang_item.as_str(), i.span); + self.register(lang_item, i.span); } intravisit::walk_foreign_item(self, i) } diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs index 3d33e249536c7..9b41366741876 100644 --- a/src/librustc/mir/cache.rs +++ b/src/librustc/mir/cache.rs @@ -1,6 +1,6 @@ -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::vec::IndexVec; use rustc_data_structures::sync::{RwLock, MappedReadGuard, ReadGuard}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; use crate::ich::StableHashingContext; use crate::mir::{Body, BasicBlock}; @@ -24,10 +24,8 @@ impl rustc_serialize::Decodable for Cache { } impl<'a> HashStable> for Cache { - fn hash_stable(&self, - _: &mut StableHashingContext<'a>, - _: &mut StableHasher) { - // do nothing + fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) { + // Do nothing. } } diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index ce04cca96e0f9..15e6cb6bcabae 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -4,30 +4,46 @@ use super::{ Pointer, InterpResult, AllocId, ScalarMaybeUndef, write_target_uint, read_target_uint, Scalar, }; +use crate::mir; use crate::ty::layout::{Size, Align}; + +use rustc_data_structures::sorted_map::SortedMap; +use rustc_target::abi::HasDataLayout; use syntax::ast::Mutability; use std::iter; -use crate::mir; use std::ops::{Range, Deref, DerefMut}; -use rustc_data_structures::sorted_map::SortedMap; -use rustc_target::abi::HasDataLayout; use std::borrow::Cow; -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] -pub struct Allocation { +// NOTE: When adding new fields, make sure to adjust the `Snapshot` impl in +// `src/librustc_mir/interpret/snapshot.rs`. +#[derive( + Clone, + Debug, + Eq, + PartialEq, + PartialOrd, + Ord, + Hash, + RustcEncodable, + RustcDecodable, + HashStable, +)] +pub struct Allocation { /// The actual bytes of the allocation. - /// Note that the bytes of a pointer represent the offset of the pointer - pub bytes: Vec, + /// Note that the bytes of a pointer represent the offset of the pointer. + bytes: Vec, /// Maps from byte addresses to extra data for each pointer. /// Only the first byte of a pointer is inserted into the map; i.e., /// every entry in this map applies to `pointer_size` consecutive bytes starting /// at the given offset. - pub relocations: Relocations, - /// Denotes undefined memory. Reading from undefined memory is forbidden in miri - pub undef_mask: UndefMask, + relocations: Relocations, + /// Denotes which part of this allocation is initialized. + undef_mask: UndefMask, + /// The size of the allocation. Currently, must always equal `bytes.len()`. + pub size: Size, /// The alignment of the allocation to detect unaligned reads. pub align: Align, - /// Whether the allocation is mutable. + /// `true` if the allocation is mutable. /// Also used by codegen to determine if a static should be put into mutable memory, /// which happens for `static mut` and `static` with interior mutability. pub mutability: Mutability, @@ -35,7 +51,6 @@ pub struct Allocation { pub extra: Extra, } - pub trait AllocationExtra: ::std::fmt::Debug + Clone { // There is no constructor in here because the constructor's type depends // on `MemoryKind`, and making things sufficiently generic leads to painful @@ -77,7 +92,7 @@ pub trait AllocationExtra: ::std::fmt::Debug + Clone { } } -// For Tag=() and no extra state, we have is a trivial implementation. +// For `Tag = ()` and no extra state, we have a trivial implementation. impl AllocationExtra<()> for () { } // The constructors are all without extra; the extra gets added by a machine hook later. @@ -85,11 +100,12 @@ impl Allocation { /// Creates a read-only allocation initialized by the given bytes pub fn from_bytes<'a>(slice: impl Into>, align: Align) -> Self { let bytes = slice.into().into_owned(); - let undef_mask = UndefMask::new(Size::from_bytes(bytes.len() as u64), true); + let size = Size::from_bytes(bytes.len() as u64); Self { bytes, relocations: Relocations::new(), - undef_mask, + undef_mask: UndefMask::new(size, true), + size, align, mutability: Mutability::Immutable, extra: (), @@ -106,6 +122,7 @@ impl Allocation { bytes: vec![0; size.bytes() as usize], relocations: Relocations::new(), undef_mask: UndefMask::new(size, false), + size, align, mutability: Mutability::Mutable, extra: (), @@ -113,9 +130,62 @@ impl Allocation { } } +impl Allocation<(), ()> { + /// Add Tag and Extra fields + pub fn with_tags_and_extra( + self, + mut tagger: impl FnMut(AllocId) -> T, + extra: E, + ) -> Allocation { + Allocation { + bytes: self.bytes, + size: self.size, + relocations: Relocations::from_presorted( + self.relocations.iter() + // The allocations in the relocations (pointers stored *inside* this allocation) + // all get the base pointer tag. + .map(|&(offset, ((), alloc))| { + let tag = tagger(alloc); + (offset, (tag, alloc)) + }) + .collect() + ), + undef_mask: self.undef_mask, + align: self.align, + mutability: self.mutability, + extra, + } + } +} + +/// Raw accessors. Provide access to otherwise private bytes. +impl Allocation { + pub fn len(&self) -> usize { + self.size.bytes() as usize + } + + /// Looks at a slice which may describe undefined bytes or describe a relocation. This differs + /// from `get_bytes_with_undef_and_ptr` in that it does no relocation checks (even on the + /// edges) at all. It further ignores `AllocationExtra` callbacks. + /// This must not be used for reads affecting the interpreter execution. + pub fn inspect_with_undef_and_ptr_outside_interpreter(&self, range: Range) -> &[u8] { + &self.bytes[range] + } + + /// Returns the undef mask. + pub fn undef_mask(&self) -> &UndefMask { + &self.undef_mask + } + + /// Returns the relocation list. + pub fn relocations(&self) -> &Relocations { + &self.relocations + } +} + impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx Allocation {} -/// Byte accessors +/// Byte accessors. impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { /// Just a small local helper function to avoid a bit of code repetition. /// Returns the range of this allocation that was meant. @@ -125,16 +195,16 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { offset: Size, size: Size ) -> Range { - let end = offset + size; // this does overflow checking + let end = offset + size; // This does overflow checking. assert_eq!( end.bytes() as usize as u64, end.bytes(), "cannot handle this access on this host architecture" ); let end = end.bytes() as usize; assert!( - end <= self.bytes.len(), + end <= self.len(), "Out-of-bounds access at offset {}, size {} in allocation of size {}", - offset.bytes(), size.bytes(), self.bytes.len() + offset.bytes(), size.bytes(), self.len() ); (offset.bytes() as usize)..end } @@ -162,7 +232,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { self.check_defined(ptr, size)?; self.check_relocations(cx, ptr, size)?; } else { - // We still don't want relocations on the *edges* + // We still don't want relocations on the *edges*. self.check_relocation_edges(cx, ptr, size)?; } @@ -171,7 +241,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { Ok(&self.bytes[range]) } - /// Check that these bytes are initialized and not pointer bytes, and then return them + /// Checks that these bytes are initialized and not pointer bytes, and then return them /// as a slice. /// /// It is the caller's responsibility to check bounds and alignment beforehand. @@ -223,7 +293,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { } } -/// Reading and writing +/// Reading and writing. impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { /// Reads bytes until a `0` is encountered. Will error if the end of the allocation is reached /// before a `0` is found. @@ -259,9 +329,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { allow_ptr_and_undef: bool, ) -> InterpResult<'tcx> { - // Check bounds and relocations on the edges + // Check bounds and relocations on the edges. self.get_bytes_with_undef_and_ptr(cx, ptr, size)?; - // Check undef and ptr + // Check undef and ptr. if !allow_ptr_and_undef { self.check_defined(ptr, size)?; self.check_relocations(cx, ptr, size)?; @@ -302,12 +372,12 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { Ok(()) } - /// Read a *non-ZST* scalar + /// Reads a *non-ZST* scalar. /// - /// zsts can't be read out of two reasons: - /// * byteorder cannot work with zero element buffers - /// * in oder to obtain a `Pointer` we need to check for ZSTness anyway due to integer pointers - /// being valid for ZSTs + /// ZSTs can't be read for two reasons: + /// * byte-order cannot work with zero-element buffers; + /// * in order to obtain a `Pointer`, we need to check for ZSTness anyway due to integer + /// pointers being valid for ZSTs. /// /// It is the caller's responsibility to check bounds and alignment beforehand. pub fn read_scalar( @@ -317,20 +387,20 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { size: Size ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // get_bytes_unchecked tests relocation edges + // `get_bytes_unchecked` tests relocation edges. let bytes = self.get_bytes_with_undef_and_ptr(cx, ptr, size)?; // Undef check happens *after* we established that the alignment is correct. - // We must not return Ok() for unaligned pointers! + // We must not return `Ok()` for unaligned pointers! if self.check_defined(ptr, size).is_err() { - // this inflates undefined bytes to the entire scalar, even if only a few - // bytes are undefined + // This inflates undefined bytes to the entire scalar, even if only a few + // bytes are undefined. return Ok(ScalarMaybeUndef::Undef); } - // Now we do the actual reading + // Now we do the actual reading. let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap(); - // See if we got a pointer + // See if we got a pointer. if size != cx.data_layout().pointer_size { - // *Now* better make sure that the inside also is free of relocations. + // *Now*, we better make sure that the inside is free of relocations too. self.check_relocations(cx, ptr, size)?; } else { match self.relocations.get(&ptr.offset) { @@ -345,7 +415,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { Ok(ScalarMaybeUndef::Scalar(Scalar::from_uint(bits, size))) } - /// Read a pointer-sized scalar. + /// Reads a pointer-sized scalar. /// /// It is the caller's responsibility to check bounds and alignment beforehand. pub fn read_ptr_sized( @@ -357,12 +427,12 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { self.read_scalar(cx, ptr, cx.data_layout().pointer_size) } - /// Write a *non-ZST* scalar + /// Writes a *non-ZST* scalar. /// - /// zsts can't be read out of two reasons: - /// * byteorder cannot work with zero element buffers - /// * in oder to obtain a `Pointer` we need to check for ZSTness anyway due to integer pointers - /// being valid for ZSTs + /// ZSTs can't be read for two reasons: + /// * byte-order cannot work with zero-element buffers; + /// * in order to obtain a `Pointer`, we need to check for ZSTness anyway due to integer + /// pointers being valid for ZSTs. /// /// It is the caller's responsibility to check bounds and alignment beforehand. pub fn write_scalar( @@ -390,7 +460,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { let dst = self.get_bytes_mut(cx, ptr, type_size)?; write_target_uint(endian, dst, bytes).unwrap(); - // See if we have to also write a relocation + // See if we have to also write a relocation. match val { Scalar::Ptr(val) => { self.relocations.insert( @@ -404,7 +474,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { Ok(()) } - /// Write a pointer-sized scalar. + /// Writes a pointer-sized scalar. /// /// It is the caller's responsibility to check bounds and alignment beforehand. pub fn write_ptr_sized( @@ -419,10 +489,10 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { } } -/// Relocations +/// Relocations. impl<'tcx, Tag: Copy, Extra> Allocation { - /// Returns all relocations overlapping with the given ptr-offset pair. - pub fn relocations( + /// Returns all relocations overlapping with the given pointer-offset pair. + pub fn get_relocations( &self, cx: &impl HasDataLayout, ptr: Pointer, @@ -431,7 +501,7 @@ impl<'tcx, Tag: Copy, Extra> Allocation { // We have to go back `pointer_size - 1` bytes, as that one would still overlap with // the beginning of this range. let start = ptr.offset.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1); - let end = ptr.offset + size; // this does overflow checking + let end = ptr.offset + size; // This does overflow checking. self.relocations.range(Size::from_bytes(start)..end) } @@ -443,7 +513,7 @@ impl<'tcx, Tag: Copy, Extra> Allocation { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if self.relocations(cx, ptr, size).is_empty() { + if self.get_relocations(cx, ptr, size).is_empty() { Ok(()) } else { throw_unsup!(ReadPointerAsBytes) @@ -465,7 +535,7 @@ impl<'tcx, Tag: Copy, Extra> Allocation { // Find the start and end of the given range and its outermost relocations. let (first, last) = { // Find all relocations overlapping the given range. - let relocations = self.relocations(cx, ptr, size); + let relocations = self.get_relocations(cx, ptr, size); if relocations.is_empty() { return Ok(()); } @@ -491,7 +561,7 @@ impl<'tcx, Tag: Copy, Extra> Allocation { Ok(()) } - /// Error if there are relocations overlapping with the edges of the + /// Errors if there are relocations overlapping with the edges of the /// given memory range. #[inline] fn check_relocation_edges( @@ -507,7 +577,7 @@ impl<'tcx, Tag: Copy, Extra> Allocation { } -/// Undefined bytes +/// Undefined bytes. impl<'tcx, Tag, Extra> Allocation { /// Checks that a range of bytes is defined. If not, returns the `ReadUndefBytes` /// error which will report the first byte which is undefined. @@ -536,9 +606,97 @@ impl<'tcx, Tag, Extra> Allocation { } } -/// Relocations +/// Run-length encoding of the undef mask. +/// Used to copy parts of a mask multiple times to another allocation. +pub struct AllocationDefinedness { + /// The definedness of the first range. + initial: bool, + /// The lengths of ranges that are run-length encoded. + /// The definedness of the ranges alternate starting with `initial`. + ranges: smallvec::SmallVec::<[u64; 1]>, +} + +/// Transferring the definedness mask to other allocations. +impl Allocation { + /// Creates a run-length encoding of the undef mask. + pub fn compress_undef_range( + &self, + src: Pointer, + size: Size, + ) -> AllocationDefinedness { + // Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`), + // a naive undef mask copying algorithm would repeatedly have to read the undef mask from + // the source and write it to the destination. Even if we optimized the memory accesses, + // we'd be doing all of this `repeat` times. + // Therefor we precompute a compressed version of the undef mask of the source value and + // then write it back `repeat` times without computing any more information from the source. + + // A precomputed cache for ranges of defined/undefined bits + // 0000010010001110 will become + // `[5, 1, 2, 1, 3, 3, 1]`, + // where each element toggles the state. + + let mut ranges = smallvec::SmallVec::<[u64; 1]>::new(); + let initial = self.undef_mask.get(src.offset); + let mut cur_len = 1; + let mut cur = initial; + + for i in 1..size.bytes() { + // FIXME: optimize to bitshift the current undef block's bits and read the top bit. + if self.undef_mask.get(src.offset + Size::from_bytes(i)) == cur { + cur_len += 1; + } else { + ranges.push(cur_len); + cur_len = 1; + cur = !cur; + } + } + + ranges.push(cur_len); + + AllocationDefinedness { ranges, initial, } + } + + /// Applies multiple instances of the run-length encoding to the undef mask. + pub fn mark_compressed_undef_range( + &mut self, + defined: &AllocationDefinedness, + dest: Pointer, + size: Size, + repeat: u64, + ) { + // An optimization where we can just overwrite an entire range of definedness bits if + // they are going to be uniformly `1` or `0`. + if defined.ranges.len() <= 1 { + self.undef_mask.set_range_inbounds( + dest.offset, + dest.offset + size * repeat, + defined.initial, + ); + return; + } + + for mut j in 0..repeat { + j *= size.bytes(); + j += dest.offset.bytes(); + let mut cur = defined.initial; + for range in &defined.ranges { + let old_j = j; + j += range; + self.undef_mask.set_range_inbounds( + Size::from_bytes(old_j), + Size::from_bytes(j), + cur, + ); + cur = !cur; + } + } + } +} + +/// Relocations. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] -pub struct Relocations(SortedMap); +pub struct Relocations(SortedMap); impl Relocations { pub fn new() -> Self { @@ -566,6 +724,59 @@ impl DerefMut for Relocations { } } +/// A partial, owned list of relocations to transfer into another allocation. +pub struct AllocationRelocations { + relative_relocations: Vec<(Size, (Tag, AllocId))>, +} + +impl Allocation { + pub fn prepare_relocation_copy( + &self, + cx: &impl HasDataLayout, + src: Pointer, + size: Size, + dest: Pointer, + length: u64, + ) -> AllocationRelocations { + let relocations = self.get_relocations(cx, src, size); + if relocations.is_empty() { + return AllocationRelocations { relative_relocations: Vec::new() }; + } + + let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize)); + + for i in 0..length { + new_relocations.extend( + relocations + .iter() + .map(|&(offset, reloc)| { + // compute offset for current repetition + let dest_offset = dest.offset + (i * size); + ( + // shift offsets from source allocation to destination allocation + offset + dest_offset - src.offset, + reloc, + ) + }) + ); + } + + AllocationRelocations { + relative_relocations: new_relocations, + } + } + + /// Applies a relocation copy. + /// The affected range, as defined in the parameters to `prepare_relocation_copy` is expected + /// to be clear of relocations. + pub fn mark_relocation_range( + &mut self, + relocations: AllocationRelocations, + ) { + self.relocations.insert_presorted(relocations.relative_relocations); + } +} + //////////////////////////////////////////////////////////////////////////////// // Undefined byte tracking //////////////////////////////////////////////////////////////////////////////// @@ -627,8 +838,8 @@ impl UndefMask { let (blocka, bita) = bit_index(start); let (blockb, bitb) = bit_index(end); if blocka == blockb { - // first set all bits but the first `bita` - // then unset the last `64 - bitb` bits + // First set all bits except the first `bita`, + // then unset the last `64 - bitb` bits. let range = if bitb == 0 { u64::max_value() << bita } else { @@ -643,24 +854,24 @@ impl UndefMask { } // across block boundaries if new_state { - // set bita..64 to 1 + // Set `bita..64` to `1`. self.blocks[blocka] |= u64::max_value() << bita; - // set 0..bitb to 1 + // Set `0..bitb` to `1`. if bitb != 0 { self.blocks[blockb] |= u64::max_value() >> (64 - bitb); } - // fill in all the other blocks (much faster than one bit at a time) + // Fill in all the other blocks (much faster than one bit at a time). for block in (blocka + 1) .. blockb { self.blocks[block] = u64::max_value(); } } else { - // set bita..64 to 0 + // Set `bita..64` to `0`. self.blocks[blocka] &= !(u64::max_value() << bita); - // set 0..bitb to 0 + // Set `0..bitb` to `0`. if bitb != 0 { self.blocks[blockb] &= !(u64::max_value() >> (64 - bitb)); } - // fill in all the other blocks (much faster than one bit at a time) + // Fill in all the other blocks (much faster than one bit at a time). for block in (blocka + 1) .. blockb { self.blocks[block] = 0; } @@ -697,7 +908,7 @@ impl UndefMask { let additional_blocks = amount.bytes() / Self::BLOCK_SIZE + 1; assert_eq!(additional_blocks as usize as u64, additional_blocks); self.blocks.extend( - // FIXME(oli-obk): optimize this by repeating `new_state as Block` + // FIXME(oli-obk): optimize this by repeating `new_state as Block`. iter::repeat(0).take(additional_blocks as usize), ); } diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index f53d2ffb6df54..71967b513a049 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -1,23 +1,21 @@ -use std::{fmt, env}; +use super::{RawConst, Pointer, CheckInAllocMsg, ScalarMaybeUndef}; use crate::hir; use crate::hir::map::definitions::DefPathData; use crate::mir; use crate::ty::{self, Ty, layout}; use crate::ty::layout::{Size, Align, LayoutError}; -use rustc_target::spec::abi::Abi; -use rustc_macros::HashStable; - -use super::{RawConst, Pointer, CheckInAllocMsg, ScalarMaybeUndef}; +use crate::ty::query::TyCtxtAt; use backtrace::Backtrace; - -use crate::ty::query::TyCtxtAt; use errors::DiagnosticBuilder; - +use rustc_macros::HashStable; +use rustc_target::spec::abi::Abi; use syntax_pos::{Pos, Span}; use syntax::symbol::Symbol; +use std::{fmt, env}; + #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)] pub enum ErrorHandled { /// Already reported a lint or an error for this evaluation. @@ -215,9 +213,18 @@ fn print_backtrace(backtrace: &mut Backtrace) { eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace); } +impl From for InterpErrorInfo<'tcx> { + fn from(err: ErrorHandled) -> Self { + match err { + ErrorHandled::Reported => err_inval!(ReferencedConstant), + ErrorHandled::TooGeneric => err_inval!(TooGeneric), + }.into() + } +} + impl<'tcx> From> for InterpErrorInfo<'tcx> { fn from(kind: InterpError<'tcx>) -> Self { - let backtrace = match env::var("RUST_CTFE_BACKTRACE") { + let backtrace = match env::var("RUSTC_CTFE_BACKTRACE") { // Matching `RUST_BACKTRACE` -- we treat "0" the same as "not present". Ok(ref val) if val != "0" => { let mut backtrace = Backtrace::new_unresolved(); @@ -315,6 +322,9 @@ impl fmt::Debug for PanicInfo { } } +/// Error information for when the program we executed turned out not to actually be a valid +/// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp +/// where we work on generic code or execution does not have all information available. #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] pub enum InvalidProgramInfo<'tcx> { /// Resolution can fail if we are in a too generic context. @@ -344,6 +354,7 @@ impl fmt::Debug for InvalidProgramInfo<'tcx> { } } +/// Error information for when the program caused Undefined Behavior. #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] pub enum UndefinedBehaviorInfo { /// Free-form case. Only for errors that are never caught! @@ -366,12 +377,23 @@ impl fmt::Debug for UndefinedBehaviorInfo { } } +/// Error information for when the program did something that might (or might not) be correct +/// to do according to the Rust spec, but due to limitations in the interpreter, the +/// operation could not be carried out. These limitations can differ between CTFE and the +/// Miri engine, e.g., CTFE does not support casting pointers to "real" integers. +/// +/// Currently, we also use this as fall-back error kind for errors that have not been +/// categorized yet. #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] pub enum UnsupportedOpInfo<'tcx> { /// Free-form case. Only for errors that are never caught! Unsupported(String), - // -- Everything below is not classified yet -- + /// FIXME(#64506) Error used to work around accessing projections of + /// uninhabited types. + UninhabitedValue, + + // -- Everything below is not categorized yet -- FunctionAbiMismatch(Abi, Abi), FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>), FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>), @@ -430,13 +452,13 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> { match self { PointerOutOfBounds { ptr, msg, allocation_size } => { write!(f, "{} failed: pointer must be in-bounds at offset {}, \ - but is outside bounds of allocation {} which has size {}", + but is outside bounds of allocation {} which has size {}", msg, ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes()) }, ValidationFailure(ref err) => { write!(f, "type validation failed: {}", err) } - NoMirFor(ref func) => write!(f, "no mir for `{}`", func), + NoMirFor(ref func) => write!(f, "no MIR for `{}`", func), FunctionAbiMismatch(caller_abi, callee_abi) => write!(f, "tried to call a function with ABI {:?} using caller ABI {:?}", callee_abi, caller_abi), @@ -451,9 +473,9 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> { FunctionArgCountMismatch => write!(f, "tried to call a function with incorrect number of arguments"), ReallocatedWrongMemoryKind(ref old, ref new) => - write!(f, "tried to reallocate memory from {} to {}", old, new), + write!(f, "tried to reallocate memory from `{}` to `{}`", old, new), DeallocatedWrongMemoryKind(ref old, ref new) => - write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new), + write!(f, "tried to deallocate `{}` memory but gave `{}` as the kind", old, new), InvalidChar(c) => write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c), AlignmentCheckFailed { required, has } => @@ -462,7 +484,7 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> { TypeNotPrimitive(ty) => write!(f, "expected primitive type, got {}", ty), PathNotFound(ref path) => - write!(f, "Cannot find path {:?}", path), + write!(f, "cannot find path {:?}", path), IncorrectAllocationInformation(size, size2, align, align2) => write!(f, "incorrect alloc info: expected size {} and align {}, \ got size {} and align {}", @@ -525,7 +547,7 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> { InvalidBoolOp(_) => write!(f, "invalid boolean operation"), UnterminatedCString(_) => - write!(f, "attempted to get length of a null terminated string, but no null \ + write!(f, "attempted to get length of a null-terminated string, but no null \ found before end of allocation"), ReadUndefBytes(_) => write!(f, "attempted to read undefined bytes"), @@ -534,10 +556,14 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> { not a power of two"), Unsupported(ref msg) => write!(f, "{}", msg), + UninhabitedValue => + write!(f, "tried to use an uninhabited value"), } } } +/// Error information for when the program exhausted the resources granted to it +/// by the interpreter. #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] pub enum ResourceExhaustionInfo { /// The stack grew too big. @@ -582,7 +608,7 @@ pub type InterpResult<'tcx, T = ()> = Result>; impl fmt::Display for InterpError<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Forward `Display` to `Debug` + // Forward `Display` to `Debug`. write!(f, "{:?}", self) } } diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 1ec95c29a4a6f..6c31d54e081c4 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -1,4 +1,4 @@ -//! An interpreter for MIR used in CTFE and by miri +//! An interpreter for MIR used in CTFE and by miri. #[macro_export] macro_rules! err_unsup { @@ -101,27 +101,27 @@ pub use self::error::{ InvalidProgramInfo, ResourceExhaustionInfo, UndefinedBehaviorInfo, }; -pub use self::value::{Scalar, ScalarMaybeUndef, RawConst, ConstValue}; +pub use self::value::{Scalar, ScalarMaybeUndef, RawConst, ConstValue, get_slice_bytes}; pub use self::allocation::{Allocation, AllocationExtra, Relocations, UndefMask}; pub use self::pointer::{Pointer, PointerArithmetic, CheckInAllocMsg}; -use std::fmt; use crate::mir; use crate::hir::def_id::DefId; -use crate::ty::{self, TyCtxt, Instance, subst::UnpackedKind}; +use crate::ty::{self, TyCtxt, Instance, subst::GenericArgKind}; +use crate::ty::codec::TyDecoder; use crate::ty::layout::{self, Size}; use std::io; +use std::fmt; +use std::num::NonZeroU32; +use std::sync::atomic::{AtomicU32, Ordering}; use rustc_serialize::{Encoder, Decodable, Encodable}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::{Lock as Mutex, HashMapExt}; +use rustc_data_structures::sync::{Lock, HashMapExt}; use rustc_data_structures::tiny_list::TinyList; use rustc_macros::HashStable; use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian}; -use crate::ty::codec::TyDecoder; -use std::sync::atomic::{AtomicU32, Ordering}; -use std::num::NonZeroU32; /// Uniquely identifies a specific constant or static. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable, HashStable)] @@ -152,8 +152,8 @@ pub fn specialized_encode_alloc_id<'tcx, E: Encoder>( tcx: TyCtxt<'tcx>, alloc_id: AllocId, ) -> Result<(), E::Error> { - let alloc: GlobalAlloc<'tcx> = - tcx.alloc_map.lock().get(alloc_id).expect("no value for AllocId"); + let alloc: GlobalAlloc<'tcx> = tcx.alloc_map.lock().get(alloc_id) + .expect("no value for given alloc ID"); match alloc { GlobalAlloc::Memory(alloc) => { trace!("encoding {:?} with {:#?}", alloc_id, alloc); @@ -166,8 +166,8 @@ pub fn specialized_encode_alloc_id<'tcx, E: Encoder>( fn_instance.encode(encoder)?; } GlobalAlloc::Static(did) => { - // referring to statics doesn't need to know about their allocations, - // just about its DefId + // References to statics doesn't need to know about their allocations, + // just about its `DefId`. AllocDiscriminant::Static.encode(encoder)?; did.encode(encoder)?; } @@ -187,19 +187,18 @@ enum State { } pub struct AllocDecodingState { - // For each AllocId we keep track of which decoding state it's currently in. - decoding_state: Vec>, + // For each `AllocId`, we keep track of which decoding state it's currently in. + decoding_state: Vec>, // The offsets of each allocation in the data stream. data_offsets: Vec, } impl AllocDecodingState { - pub fn new_decoding_session(&self) -> AllocDecodingSession<'_> { static DECODER_SESSION_ID: AtomicU32 = AtomicU32::new(0); let counter = DECODER_SESSION_ID.fetch_add(1, Ordering::SeqCst); - // Make sure this is never zero + // Make sure this is never zero. let session_id = DecodingSessionId::new((counter & 0x7FFFFFFF) + 1).unwrap(); AllocDecodingSession { @@ -208,10 +207,10 @@ impl AllocDecodingState { } } - pub fn new(data_offsets: Vec) -> AllocDecodingState { - let decoding_state = vec![Mutex::new(State::Empty); data_offsets.len()]; + pub fn new(data_offsets: Vec) -> Self { + let decoding_state = vec![Lock::new(State::Empty); data_offsets.len()]; - AllocDecodingState { + Self { decoding_state, data_offsets, } @@ -225,23 +224,23 @@ pub struct AllocDecodingSession<'s> { } impl<'s> AllocDecodingSession<'s> { - // Decodes an AllocId in a thread-safe way. + /// Decodes an `AllocId` in a thread-safe way. pub fn decode_alloc_id(&self, decoder: &mut D) -> Result where D: TyDecoder<'tcx>, { - // Read the index of the allocation + // Read the index of the allocation. let idx = decoder.read_u32()? as usize; let pos = self.state.data_offsets[idx] as usize; - // Decode the AllocDiscriminant now so that we know if we have to reserve an - // AllocId. + // Decode the `AllocDiscriminant` now so that we know if we have to reserve an + // `AllocId`. let (alloc_kind, pos) = decoder.with_position(pos, |decoder| { let alloc_kind = AllocDiscriminant::decode(decoder)?; Ok((alloc_kind, decoder.position())) })?; - // Check the decoding state, see if it's already decoded or if we should + // Check the decoding state to see if it's already decoded or if we should // decode it here. let alloc_id = { let mut entry = self.state.decoding_state[idx].lock(); @@ -251,11 +250,11 @@ impl<'s> AllocDecodingSession<'s> { return Ok(alloc_id); } ref mut entry @ State::Empty => { - // We are allowed to decode + // We are allowed to decode. match alloc_kind { AllocDiscriminant::Alloc => { // If this is an allocation, we need to reserve an - // AllocId so we can decode cyclic graphs. + // `AllocId` so we can decode cyclic graphs. let alloc_id = decoder.tcx().alloc_map.lock().reserve(); *entry = State::InProgress( TinyList::new_single(self.session_id), @@ -263,8 +262,8 @@ impl<'s> AllocDecodingSession<'s> { Some(alloc_id) }, AllocDiscriminant::Fn | AllocDiscriminant::Static => { - // Fns and statics cannot be cyclic and their AllocId - // is determined later by interning + // Fns and statics cannot be cyclic, and their `AllocId` + // is determined later by interning. *entry = State::InProgressNonAlloc( TinyList::new_single(self.session_id)); None @@ -273,9 +272,9 @@ impl<'s> AllocDecodingSession<'s> { } State::InProgressNonAlloc(ref mut sessions) => { if sessions.contains(&self.session_id) { - bug!("This should be unreachable") + bug!("this should be unreachable"); } else { - // Start decoding concurrently + // Start decoding concurrently. sessions.insert(self.session_id); None } @@ -285,7 +284,7 @@ impl<'s> AllocDecodingSession<'s> { // Don't recurse. return Ok(alloc_id) } else { - // Start decoding concurrently + // Start decoding concurrently. sessions.insert(self.session_id); Some(alloc_id) } @@ -293,20 +292,20 @@ impl<'s> AllocDecodingSession<'s> { } }; - // Now decode the actual data + // Now decode the actual data. let alloc_id = decoder.with_position(pos, |decoder| { match alloc_kind { AllocDiscriminant::Alloc => { - let allocation = <&'tcx Allocation as Decodable>::decode(decoder)?; - // We already have a reserved AllocId. + let alloc = <&'tcx Allocation as Decodable>::decode(decoder)?; + // We already have a reserved `AllocId`. let alloc_id = alloc_id.unwrap(); - trace!("decoded alloc {:?} {:#?}", alloc_id, allocation); - decoder.tcx().alloc_map.lock().set_alloc_id_same_memory(alloc_id, allocation); + trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc); + decoder.tcx().alloc_map.lock().set_alloc_id_same_memory(alloc_id, alloc); Ok(alloc_id) }, AllocDiscriminant::Fn => { assert!(alloc_id.is_none()); - trace!("creating fn alloc id"); + trace!("creating fn alloc ID"); let instance = ty::Instance::decode(decoder)?; trace!("decoded fn alloc instance: {:?}", instance); let alloc_id = decoder.tcx().alloc_map.lock().create_fn_alloc(instance); @@ -314,8 +313,9 @@ impl<'s> AllocDecodingSession<'s> { }, AllocDiscriminant::Static => { assert!(alloc_id.is_none()); - trace!("creating extern static alloc id at"); + trace!("creating extern static alloc ID"); let did = DefId::decode(decoder)?; + trace!("decoded static def-ID: {:?}", did); let alloc_id = decoder.tcx().alloc_map.lock().create_static_alloc(did); Ok(alloc_id) } @@ -340,7 +340,7 @@ impl fmt::Display for AllocId { /// a static, or a "real" allocation with some data in it. #[derive(Debug, Clone, Eq, PartialEq, Hash, RustcDecodable, RustcEncodable, HashStable)] pub enum GlobalAlloc<'tcx> { - /// The alloc ID is used as a function pointer + /// The alloc ID is used as a function pointer. Function(Instance<'tcx>), /// The alloc ID points to a "lazy" static variable that did not get computed (yet). /// This is also used to break the cycle in recursive statics. @@ -350,16 +350,17 @@ pub enum GlobalAlloc<'tcx> { } pub struct AllocMap<'tcx> { - /// Lets you know what an `AllocId` refers to. + /// Maps `AllocId`s to their corresponding allocations. alloc_map: FxHashMap>, /// Used to ensure that statics and functions only get one associated `AllocId`. /// Should never contain a `GlobalAlloc::Memory`! - /// FIXME: Should we just have two separate dedup maps for statics and functions each? + // + // FIXME: Should we just have two separate dedup maps for statics and functions each? dedup: FxHashMap, AllocId>, /// The `AllocId` to assign to the next requested ID. - /// Always incremented, never gets smaller. + /// Always incremented; never gets smaller. next_id: AllocId, } @@ -389,7 +390,7 @@ impl<'tcx> AllocMap<'tcx> { next } - /// Reserve a new ID *if* this allocation has not been dedup-reserved before. + /// Reserves a new ID *if* this allocation has not been dedup-reserved before. /// Should only be used for function pointers and statics, we don't want /// to dedup IDs for "real" memory! fn reserve_and_set_dedup(&mut self, alloc: GlobalAlloc<'tcx>) -> AllocId { @@ -425,22 +426,22 @@ impl<'tcx> AllocMap<'tcx> { // this for generic functions. Lifetime parameters are ignored. let is_generic = instance.substs.into_iter().any(|kind| { match kind.unpack() { - UnpackedKind::Lifetime(_) => false, + GenericArgKind::Lifetime(_) => false, _ => true, } }); if is_generic { - // Get a fresh ID + // Get a fresh ID. let id = self.reserve(); self.alloc_map.insert(id, GlobalAlloc::Function(instance)); id } else { - // Deduplicate + // Deduplicate. self.reserve_and_set_dedup(GlobalAlloc::Function(instance)) } } - /// Intern the `Allocation` and return a new `AllocId`, even if there's already an identical + /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical /// `Allocation` with a different `AllocId`. /// Statics with identical content will still point to the same `Allocation`, i.e., /// their data will be deduplicated through `Allocation` interning -- but they @@ -465,19 +466,27 @@ impl<'tcx> AllocMap<'tcx> { pub fn unwrap_memory(&self, id: AllocId) -> &'tcx Allocation { match self.get(id) { Some(GlobalAlloc::Memory(mem)) => mem, - _ => bug!("expected allocation id {} to point to memory", id), + _ => bug!("expected allocation ID {} to point to memory", id), + } + } + + /// Panics if the `AllocId` does not refer to a function + pub fn unwrap_fn(&self, id: AllocId) -> Instance<'tcx> { + match self.get(id) { + Some(GlobalAlloc::Function(instance)) => instance, + _ => bug!("expected allocation ID {} to point to a function", id), } } - /// Freeze an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to + /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to /// call this function twice, even with the same `Allocation` will ICE the compiler. pub fn set_alloc_id_memory(&mut self, id: AllocId, mem: &'tcx Allocation) { if let Some(old) = self.alloc_map.insert(id, GlobalAlloc::Memory(mem)) { - bug!("tried to set allocation id {}, but it was already existing as {:#?}", id, old); + bug!("tried to set allocation ID {}, but it was already existing as {:#?}", id, old); } } - /// Freeze an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called + /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called /// twice for the same `(AllocId, Allocation)` pair. fn set_alloc_id_same_memory(&mut self, id: AllocId, mem: &'tcx Allocation) { self.alloc_map.insert_same(id, GlobalAlloc::Memory(mem)); @@ -513,7 +522,7 @@ pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result // Methods to facilitate working with signed integers stored in a u128 //////////////////////////////////////////////////////////////////////////////// -/// Truncate `value` to `size` bits and then sign-extend it to 128 bits +/// Truncates `value` to `size` bits and then sign-extend it to 128 bits /// (i.e., if it is negative, fill with 1's on the left). #[inline] pub fn sign_extend(value: u128, size: Size) -> u128 { @@ -522,14 +531,14 @@ pub fn sign_extend(value: u128, size: Size) -> u128 { // Truncated until nothing is left. return 0; } - // sign extend + // Sign-extend it. let shift = 128 - size; - // shift the unsigned value to the left - // and back to the right as signed (essentially fills with FF on the left) + // Shift the unsigned value to the left, then shift back to the right as signed + // (essentially fills with FF on the left). (((value << shift) as i128) >> shift) as u128 } -/// Truncate `value` to `size` bits. +/// Truncates `value` to `size` bits. #[inline] pub fn truncate(value: u128, size: Size) -> u128 { let size = size.bits(); @@ -538,6 +547,6 @@ pub fn truncate(value: u128, size: Size) -> u128 { return 0; } let shift = 128 - size; - // truncate (shift left to drop out leftover values, shift right to fill with zeroes) + // Truncate (shift left to drop out leftover values, shift right to fill with zeroes). (value << shift) >> shift } diff --git a/src/librustc/mir/interpret/pointer.rs b/src/librustc/mir/interpret/pointer.rs index 0a99851337994..1bb4d9ea4d6d9 100644 --- a/src/librustc/mir/interpret/pointer.rs +++ b/src/librustc/mir/interpret/pointer.rs @@ -86,18 +86,17 @@ pub trait PointerArithmetic: layout::HasDataLayout { impl PointerArithmetic for T {} - -/// Pointer is generic over the type that represents a reference to Allocations, +/// `Pointer` is generic over the type that represents a reference to `Allocation`s, /// thus making it possible for the most convenient representation to be used in /// each context. /// -/// Defaults to the index based and loosely coupled AllocId. +/// Defaults to the index based and loosely coupled `AllocId`. /// /// Pointer is also generic over the `Tag` associated with each pointer, /// which is used to do provenance tracking during execution. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash, HashStable)] -pub struct Pointer { +pub struct Pointer { pub alloc_id: Id, pub offset: Size, pub tag: Tag, @@ -117,7 +116,7 @@ impl fmt::Debug for Pointer<(), Id> { } } -/// Produces a `Pointer` which points to the beginning of the Allocation +/// Produces a `Pointer` which points to the beginning of the `Allocation`. impl From for Pointer { #[inline(always)] fn from(alloc_id: AllocId) -> Self { @@ -189,8 +188,11 @@ impl<'tcx, Tag> Pointer { Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () } } + /// Test if the pointer is "inbounds" of an allocation of the given size. + /// A pointer is "inbounds" even if its offset is equal to the size; this is + /// a "one-past-the-end" pointer. #[inline(always)] - pub fn check_in_alloc( + pub fn check_inbounds_alloc( self, allocation_size: Size, msg: CheckInAllocMsg, diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 5381d46972440..bbf00cc23ae88 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -17,8 +17,8 @@ pub struct RawConst<'tcx> { pub ty: Ty<'tcx>, } -/// Represents a constant value in Rust. `Scalar` and `ScalarPair` are optimizations that -/// match the `LocalState` optimizations for easy conversions between `Value` and `ConstValue`. +/// Represents a constant value in Rust. `Scalar` and `Slice` are optimizations for +/// array length computations, enum discriminants and the pattern matching logic. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, HashStable)] pub enum ConstValue<'tcx> { @@ -91,7 +91,7 @@ impl<'tcx> ConstValue<'tcx> { /// of a simple value or a pointer into another `Allocation` #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash, HashStable)] -pub enum Scalar { +pub enum Scalar { /// The raw bytes of a simple value. Raw { /// The first `size` bytes of `data` are the value. @@ -343,14 +343,19 @@ impl<'tcx, Tag> Scalar { } } + #[inline(always)] + pub fn check_raw(data: u128, size: u8, target_size: Size) { + assert_eq!(target_size.bytes(), size as u64); + assert_ne!(size, 0, "you should never look at the bits of a ZST"); + Scalar::check_data(data, size); + } + /// Do not call this method! Use either `assert_bits` or `force_bits`. #[inline] pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> { match self { Scalar::Raw { data, size } => { - assert_eq!(target_size.bytes(), size as u64); - assert_ne!(size, 0, "you should never look at the bits of a ZST"); - Scalar::check_data(data, size); + Self::check_raw(data, size, target_size); Ok(data) } Scalar::Ptr(_) => throw_unsup!(ReadPointerAsBytes), @@ -359,7 +364,7 @@ impl<'tcx, Tag> Scalar { #[inline(always)] pub fn assert_bits(self, target_size: Size) -> u128 { - self.to_bits(target_size).expect("Expected Raw bits but got a Pointer") + self.to_bits(target_size).expect("expected Raw bits but got a Pointer") } /// Do not call this method! Use either `assert_ptr` or `force_ptr`. @@ -374,7 +379,7 @@ impl<'tcx, Tag> Scalar { #[inline(always)] pub fn assert_ptr(self) -> Pointer { - self.to_ptr().expect("Expected a Pointer but got Raw bits") + self.to_ptr().expect("expected a Pointer but got Raw bits") } /// Do not call this method! Dispatch based on the type instead. @@ -482,8 +487,8 @@ impl From> for Scalar { } } -#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)] -pub enum ScalarMaybeUndef { +#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, RustcEncodable, RustcDecodable)] +pub enum ScalarMaybeUndef { Scalar(Scalar), Undef, } @@ -530,7 +535,7 @@ impl<'tcx, Tag> ScalarMaybeUndef { pub fn not_undef(self) -> InterpResult<'static, Scalar> { match self { ScalarMaybeUndef::Scalar(scalar) => Ok(scalar), - ScalarMaybeUndef::Undef => throw_unsup!(ReadUndefBytes(Size::from_bytes(0))), + ScalarMaybeUndef::Undef => throw_unsup!(ReadUndefBytes(Size::ZERO)), } } @@ -611,3 +616,18 @@ impl_stable_hash_for!(enum crate::mir::interpret::ScalarMaybeUndef { Scalar(v), Undef }); + +/// Gets the bytes of a constant slice value. +pub fn get_slice_bytes<'tcx>(cx: &impl HasDataLayout, val: ConstValue<'tcx>) -> &'tcx [u8] { + if let ConstValue::Slice { data, start, end } = val { + let len = end - start; + data.get_bytes( + cx, + // invent a pointer, only the offset is relevant anyway + Pointer::new(AllocId(0), Size::from_bytes(start as u64)), + Size::from_bytes(len as u64), + ).unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err)) + } else { + bug!("expected const slice, but found another const value"); + } +} diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 1e2ec08301cf9..9ac1465cb0ba9 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -15,15 +15,16 @@ use crate::ty::layout::VariantIdx; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::{ - self, AdtDef, CanonicalUserTypeAnnotations, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt, + self, AdtDef, CanonicalUserTypeAnnotations, Region, Ty, TyCtxt, UserTypeAnnotationIndex, }; + use polonius_engine::Atom; -use rustc_data_structures::bit_set::BitMatrix; +use rustc_index::bit_set::BitMatrix; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::dominators::{dominators, Dominators}; use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors}; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_index::vec::{Idx, IndexVec}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::MappedReadGuard; use rustc_macros::HashStable; @@ -31,7 +32,6 @@ use rustc_serialize::{Encodable, Decodable}; use smallvec::SmallVec; use std::borrow::Cow; use std::fmt::{self, Debug, Display, Formatter, Write}; -use std::iter::FusedIterator; use std::ops::{Index, IndexMut}; use std::slice; use std::vec::IntoIter; @@ -70,7 +70,7 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> { /// The various "big phases" that MIR goes through. /// -/// Warning: ordering of variants is significant +/// Warning: ordering of variants is significant. #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum MirPhase { Build = 0, @@ -80,16 +80,16 @@ pub enum MirPhase { } impl MirPhase { - /// Gets the index of the current MirPhase within the set of all MirPhases. + /// Gets the index of the current MirPhase within the set of all `MirPhase`s. pub fn phase_index(&self) -> usize { *self as usize } } -/// Lowered representation of a single function. +/// The lowered representation of a single function. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Body<'tcx> { - /// List of basic blocks. References to basic block use a newtyped index type `BasicBlock` + /// A list of basic blocks. References to basic block use a newtyped index type `BasicBlock` /// that indexes into this vector. basic_blocks: IndexVec>, @@ -100,7 +100,7 @@ pub struct Body<'tcx> { /// us to see the difference and forego optimization on the inlined promoted items. pub phase: MirPhase, - /// List of source scopes; these are referenced by statements + /// A list of source scopes; these are referenced by statements /// and used for debuginfo. Indexed by a `SourceScope`. pub source_scopes: IndexVec, @@ -108,15 +108,10 @@ pub struct Body<'tcx> { /// needn't) be tracked across crates. pub source_scope_local_data: ClearCrossCrate>, - /// Rvalues promoted from this function, such as borrows of constants. - /// Each of them is the Body of a constant with the fn's type parameters - /// in scope, but a separate set of locals. - pub promoted: IndexVec>, - - /// Yields type of the function, if it is a generator. + /// The yield type of the function, if it is a generator. pub yield_ty: Option>, - /// Generator drop glue + /// Generator drop glue. pub generator_drop: Option>>, /// The layout of a generator. Produced by the state transformation. @@ -129,10 +124,10 @@ pub struct Body<'tcx> { /// variables and temporaries. pub local_decls: LocalDecls<'tcx>, - /// User type annotations + /// User type annotations. pub user_type_annotations: CanonicalUserTypeAnnotations<'tcx>, - /// Number of arguments this function takes. + /// The number of arguments this function takes. /// /// Starting at local 1, `arg_count` locals will be provided by the caller /// and can be assumed to be initialized. @@ -148,10 +143,11 @@ pub struct Body<'tcx> { /// Names and capture modes of all the closure upvars, assuming /// the first argument is either the closure or a reference to it. + // // NOTE(eddyb) This is *strictly* a temporary hack for codegen // debuginfo generation, and will be removed at some point. - // Do **NOT** use it for anything else, upvar information should not be - // in the MIR, please rely on local crate HIR or other side-channels. + // Do **NOT** use it for anything else; upvar information should not be + // in the MIR, so please rely on local crate HIR or other side-channels. pub __upvar_debuginfo_codegen_only_do_not_use: Vec, /// Mark this MIR of a const context other than const functions as having converted a `&&` or @@ -162,10 +158,10 @@ pub struct Body<'tcx> { /// List of places where control flow was destroyed. Used for error reporting. pub control_flow_destroyed: Vec<(Span, String)>, - /// A span representing this MIR, for error reporting + /// A span representing this MIR, for error reporting. pub span: Span, - /// A cache for various calculations + /// A cache for various calculations. cache: cache::Cache, } @@ -174,7 +170,6 @@ impl<'tcx> Body<'tcx> { basic_blocks: IndexVec>, source_scopes: IndexVec, source_scope_local_data: ClearCrossCrate>, - promoted: IndexVec>, yield_ty: Option>, local_decls: LocalDecls<'tcx>, user_type_annotations: CanonicalUserTypeAnnotations<'tcx>, @@ -183,7 +178,7 @@ impl<'tcx> Body<'tcx> { span: Span, control_flow_destroyed: Vec<(Span, String)>, ) -> Self { - // We need `arg_count` locals, and one for the return place + // We need `arg_count` locals, and one for the return place. assert!( local_decls.len() >= arg_count + 1, "expected at least {} locals, got {}", @@ -196,7 +191,6 @@ impl<'tcx> Body<'tcx> { basic_blocks, source_scopes, source_scope_local_data, - promoted, yield_ty, generator_drop: None, generator_layout: None, @@ -268,6 +262,12 @@ impl<'tcx> Body<'tcx> { dominators(self) } + /// Returns `true` if a cycle exists in the control-flow graph that is reachable from the + /// `START_BLOCK`. + pub fn is_cfg_cyclic(&self) -> bool { + graph::is_cyclic(self) + } + #[inline] pub fn local_kind(&self, local: Local) -> LocalKind { let index = local.as_usize(); @@ -391,12 +391,12 @@ impl<'tcx> Body<'tcx> { true } - /// Returns the return type, it always return first element from `local_decls` array + /// Returns the return type; it always return first element from `local_decls` array. pub fn return_ty(&self) -> Ty<'tcx> { self.local_decls[RETURN_PLACE].ty } - /// Gets the location of the terminator for the given block + /// Gets the location of the terminator for the given block. pub fn terminator_loc(&self, bb: BasicBlock) -> Location { Location { block: bb, statement_index: self[bb].statements.len() } } @@ -418,7 +418,6 @@ impl_stable_hash_for!(struct Body<'tcx> { basic_blocks, source_scopes, source_scope_local_data, - promoted, yield_ty, generator_drop, generator_layout, @@ -471,7 +470,7 @@ impl rustc_serialize::UseSpecializedDecodable for ClearCrossCrate< /// Most passes can work with it as a whole, within a single function. #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, HashStable)] pub struct SourceInfo { - /// Source span for the AST pertaining to this MIR entity. + /// The source span for the AST pertaining to this MIR entity. pub span: Span, /// The source scope, keeping track of which bindings can be @@ -582,7 +581,7 @@ impl BorrowKind { /////////////////////////////////////////////////////////////////////////// // Variables and temps -newtype_index! { +rustc_index::newtype_index! { pub struct Local { derive [HashStable] DEBUG_FORMAT = "_{}", @@ -599,13 +598,13 @@ impl Atom for Local { /// Classifies locals into categories. See `Body::local_kind`. #[derive(PartialEq, Eq, Debug, HashStable)] pub enum LocalKind { - /// User-declared variable binding + /// User-declared variable binding. Var, - /// Compiler-introduced temporary + /// Compiler-introduced temporary. Temp, - /// Function argument + /// Function argument. Arg, - /// Location of function's return value + /// Location of function's return value. ReturnPointer, } @@ -627,7 +626,7 @@ pub struct VarBindingForm<'tcx> { /// (b) it gives a way to separate this case from the remaining cases /// for diagnostics. pub opt_match_place: Option<(Option>, Span)>, - /// Span of the pattern in which this variable was bound. + /// The span of the pattern in which this variable was bound. pub pat_span: Span, } @@ -683,14 +682,10 @@ impl_stable_hash_for!(enum self::MirPhase { mod binding_form_impl { use crate::ich::StableHashingContext; - use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; + use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; impl<'a, 'tcx> HashStable> for super::BindingForm<'tcx> { - fn hash_stable( - &self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher, - ) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use super::BindingForm::*; ::std::mem::discriminant(self).hash_stable(hcx, hasher); @@ -729,12 +724,12 @@ impl_stable_hash_for!(struct BlockTailInfo { tail_result_is_ignored }); /// argument, or the return place. #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] pub struct LocalDecl<'tcx> { - /// `let mut x` vs `let x`. + /// Whether this is a mutable minding (i.e., `let x` or `let mut x`). /// /// Temporaries and the return place are always mutable. pub mutability: Mutability, - /// Some(binding_mode) if this corresponds to a user-declared local variable. + /// `Some(binding_mode)` if this corresponds to a user-declared local variable. /// /// This is solely used for local diagnostics when generating /// warnings/errors when compiling the current crate, and @@ -768,7 +763,7 @@ pub struct LocalDecl<'tcx> { /// intervening statement context). pub is_block_tail: Option, - /// Type of this local. + /// The type of this local. pub ty: Ty<'tcx>, /// If the user manually ascribed a type to this variable, @@ -777,7 +772,7 @@ pub struct LocalDecl<'tcx> { /// region inference. pub user_ty: UserTypeProjections, - /// Name of the local, used in debuginfo and pretty-printing. + /// The name of the local, used in debuginfo and pretty-printing. /// /// Note that function arguments can also have this set to `Some(_)` /// to generate better debuginfo. @@ -845,8 +840,8 @@ pub struct LocalDecl<'tcx> { /// ROOT SCOPE /// │{ argument x: &str } /// │ - /// │ │{ #[allow(unused_mut)] } // this is actually split into 2 scopes - /// │ │ // in practice because I'm lazy. + /// │ │{ #[allow(unused_mut)] } // This is actually split into 2 scopes + /// │ │ // in practice because I'm lazy. /// │ │ /// │ │← x.source_info.scope /// │ │← `x.parse().unwrap()` @@ -860,7 +855,7 @@ pub struct LocalDecl<'tcx> { /// │ /// │ │{ let x: u32 } /// │ │← x.visibility_scope - /// │ │← `drop(x)` // this accesses `x: u32` + /// │ │← `drop(x)` // This accesses `x: u32`. /// ``` pub source_info: SourceInfo, @@ -999,7 +994,7 @@ pub struct UpvarDebuginfo { /////////////////////////////////////////////////////////////////////////// // BasicBlock -newtype_index! { +rustc_index::newtype_index! { pub struct BasicBlock { derive [HashStable] DEBUG_FORMAT = "bb{}", @@ -1046,16 +1041,16 @@ pub struct Terminator<'tcx> { #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] pub enum TerminatorKind<'tcx> { - /// block should have one successor in the graph; we jump there + /// Block should have one successor in the graph; we jump there. Goto { target: BasicBlock }, - /// operand evaluates to an integer; jump depending on its value - /// to one of the targets, and otherwise fallback to `otherwise` + /// Operand evaluates to an integer; jump depending on its value + /// to one of the targets, and otherwise fallback to `otherwise`. SwitchInt { - /// discriminant value being tested + /// The discriminant value being tested. discr: Operand<'tcx>, - /// type of value being tested + /// The type of value being tested. switch_ty: Ty<'tcx>, /// Possible values. The locations to branch to in each case @@ -1065,6 +1060,7 @@ pub enum TerminatorKind<'tcx> { /// Possible branch sites. The last element of this vector is used /// for the otherwise branch, so targets.len() == values.len() + 1 /// should hold. + // // This invariant is quite non-obvious and also could be improved. // One way to make this invariant is to have something like this instead: // @@ -1077,7 +1073,7 @@ pub enum TerminatorKind<'tcx> { }, /// Indicates that the landing pad is finished and unwinding should - /// continue. Emitted by build::scope::diverge_cleanup. + /// continue. Emitted by `build::scope::diverge_cleanup`. Resume, /// Indicates that the landing pad is finished and that the process @@ -1091,10 +1087,10 @@ pub enum TerminatorKind<'tcx> { /// Indicates a terminator that can never be reached. Unreachable, - /// Drop the Place + /// Drop the `Place`. Drop { location: Place<'tcx>, target: BasicBlock, unwind: Option }, - /// Drop the Place and assign the new value over it. This ensures + /// Drop the `Place` and assign the new value over it. This ensures /// that the assignment to `P` occurs *even if* the destructor for /// place unwinds. Its semantics are best explained by the /// elaboration: @@ -1127,9 +1123,9 @@ pub enum TerminatorKind<'tcx> { unwind: Option, }, - /// Block ends with a call of a converging function + /// Block ends with a call of a converging function. Call { - /// The function that’s being called + /// The function that’s being called. func: Operand<'tcx>, /// Arguments the function is called with. /// These are owned by the callee, which is free to modify them. @@ -1140,7 +1136,7 @@ pub enum TerminatorKind<'tcx> { destination: Option<(Place<'tcx>, BasicBlock)>, /// Cleanups to be done if the call unwinds. cleanup: Option, - /// Whether this is from a call in HIR, rather than from an overloaded + /// `true` if this is from a call in HIR rather than from an overloaded /// operator. True for overloaded function call. from_hir_call: bool, }, @@ -1155,40 +1151,40 @@ pub enum TerminatorKind<'tcx> { cleanup: Option, }, - /// A suspend point + /// A suspend point. Yield { - /// The value to return + /// The value to return. value: Operand<'tcx>, - /// Where to resume to + /// Where to resume to. resume: BasicBlock, - /// Cleanup to be done if the generator is dropped at this suspend point + /// Cleanup to be done if the generator is dropped at this suspend point. drop: Option, }, - /// Indicates the end of the dropping of a generator + /// Indicates the end of the dropping of a generator. GeneratorDrop, /// A block where control flow only ever takes one real path, but borrowck /// needs to be more conservative. FalseEdges { - /// The target normal control flow will take + /// The target normal control flow will take. real_target: BasicBlock, /// A block control flow could conceptually jump to, but won't in - /// practice + /// practice. imaginary_target: BasicBlock, }, /// A terminator for blocks that only take one path in reality, but where we /// reserve the right to unwind in borrowck, even if it won't happen in practice. /// This can arise in infinite loops with no function calls for example. FalseUnwind { - /// The target normal control flow will take + /// The target normal control flow will take. real_target: BasicBlock, /// The imaginary cleanup block link. This particular path will never be taken /// in practice, but in order to avoid fragility we want to always /// consider it in borrowck. We don't want to accept programs which - /// pass borrowck only when panic=abort or some assertions are disabled - /// due to release vs. debug mode builds. This needs to be an Option because - /// of the remove_noop_landing_pads and no_landing_pads passes + /// pass borrowck only when `panic=abort` or some assertions are disabled + /// due to release vs. debug mode builds. This needs to be an `Option` because + /// of the `remove_noop_landing_pads` and `no_landing_pads` passes. unwind: Option, }, } @@ -1453,7 +1449,7 @@ impl<'tcx> Debug for TerminatorKind<'tcx> { } impl<'tcx> TerminatorKind<'tcx> { - /// Write the "head" part of the terminator; that is, its name and the data it uses to pick the + /// Writes the "head" part of the terminator; that is, its name and the data it uses to pick the /// successor basic block, if any. The only information not included is the list of possible /// successors, which may be rendered differently between the text and the graphviz format. pub fn fmt_head(&self, fmt: &mut W) -> fmt::Result { @@ -1504,7 +1500,7 @@ impl<'tcx> TerminatorKind<'tcx> { Goto { .. } => vec!["".into()], SwitchInt { ref values, switch_ty, .. } => ty::tls::with(|tcx| { let param_env = ty::ParamEnv::empty(); - let switch_ty = tcx.lift_to_global(&switch_ty).unwrap(); + let switch_ty = tcx.lift(&switch_ty).unwrap(); let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size; values .iter() @@ -1553,9 +1549,9 @@ pub struct Statement<'tcx> { // `Statement` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert_size!(Statement<'_>, 56); +static_assert_size!(Statement<'_>, 32); -impl<'tcx> Statement<'tcx> { +impl Statement<'_> { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids /// invalidating statement indices in `Location`s. pub fn make_nop(&mut self) { @@ -1574,7 +1570,7 @@ impl<'tcx> Statement<'tcx> { #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] pub enum StatementKind<'tcx> { /// Write the RHS Rvalue to the LHS Place. - Assign(Place<'tcx>, Box>), + Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>), /// This represents all the reading that a pattern match may do /// (e.g., inspecting constants and discriminant values), and the @@ -1583,10 +1579,10 @@ pub enum StatementKind<'tcx> { /// /// Note that this also is emitted for regular `let` bindings to ensure that locals that are /// never accessed still get some sanity checks for, e.g., `let x: ! = ..;` - FakeRead(FakeReadCause, Place<'tcx>), + FakeRead(FakeReadCause, Box>), /// Write the discriminant for a variant to the enum Place. - SetDiscriminant { place: Place<'tcx>, variant_index: VariantIdx }, + SetDiscriminant { place: Box>, variant_index: VariantIdx }, /// Start a live range for the storage of the local. StorageLive(Local), @@ -1603,7 +1599,7 @@ pub enum StatementKind<'tcx> { /// by miri and only generated when "-Z mir-emit-retag" is passed. /// See /// for more details. - Retag(RetagKind, Place<'tcx>), + Retag(RetagKind, Box>), /// Encodes a user's type ascription. These need to be preserved /// intact so that NLL can respect them. For example: @@ -1617,26 +1613,26 @@ pub enum StatementKind<'tcx> { /// - `Contravariant` -- requires that `T_y :> T` /// - `Invariant` -- requires that `T_y == T` /// - `Bivariant` -- no effect - AscribeUserType(Place<'tcx>, ty::Variance, Box), + AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance), /// No-op. Useful for deleting instructions without affecting statement indices. Nop, } -/// `RetagKind` describes what kind of retag is to be performed. +/// Describes what kind of retag is to be performed. #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq, HashStable)] pub enum RetagKind { - /// The initial retag when entering a function + /// The initial retag when entering a function. FnEntry, - /// Retag preparing for a two-phase borrow + /// Retag preparing for a two-phase borrow. TwoPhase, - /// Retagging raw pointers + /// Retagging raw pointers. Raw, - /// A "normal" retag + /// A "normal" retag. Default, } -/// The `FakeReadCause` describes the type of pattern why a `FakeRead` statement exists. +/// The `FakeReadCause` describes the type of pattern why a FakeRead statement exists. #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] pub enum FakeReadCause { /// Inject a fake read of the borrowed input at the end of each guards @@ -1677,11 +1673,11 @@ pub struct InlineAsm<'tcx> { pub inputs: Box<[(Span, Operand<'tcx>)]>, } -impl<'tcx> Debug for Statement<'tcx> { +impl Debug for Statement<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use self::StatementKind::*; match self.kind { - Assign(ref place, ref rv) => write!(fmt, "{:?} = {:?}", place, rv), + Assign(box(ref place, ref rv)) => write!(fmt, "{:?} = {:?}", place, rv), FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place), Retag(ref kind, ref place) => write!( fmt, @@ -1702,7 +1698,7 @@ impl<'tcx> Debug for Statement<'tcx> { InlineAsm(ref asm) => { write!(fmt, "asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs) } - AscribeUserType(ref place, ref variance, ref c_ty) => { + AscribeUserType(box(ref place, ref c_ty), ref variance) => { write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty) } Nop => write!(fmt, "nop"), @@ -1722,7 +1718,7 @@ pub struct Place<'tcx> { pub base: PlaceBase<'tcx>, /// projection out of a place (access a field, deref a pointer, etc) - pub projection: Option>>, + pub projection: Box<[PlaceElem<'tcx>]>, } #[derive( @@ -1737,34 +1733,34 @@ pub enum PlaceBase<'tcx> { } /// We store the normalized type to avoid requiring normalization when reading MIR -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct Static<'tcx> { pub ty: Ty<'tcx>, - pub kind: StaticKind, + pub kind: StaticKind<'tcx>, + /// The `DefId` of the item this static was declared in. For promoted values, usually, this is + /// the same as the `DefId` of the `mir::Body` containing the `Place` this promoted appears in. + /// However, after inlining, that might no longer be the case as inlined `Place`s are copied + /// into the calling frame. + pub def_id: DefId, } #[derive( - Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, RustcEncodable, RustcDecodable, + Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, RustcEncodable, RustcDecodable, )] -pub enum StaticKind { - Promoted(Promoted), - Static(DefId), +pub enum StaticKind<'tcx> { + /// Promoted references consist of an id (`Promoted`) and the substs necessary to monomorphize + /// it. Usually, these substs are just the identity substs for the item. However, the inliner + /// will adjust these substs when it inlines a function based on the substs at the callsite. + Promoted(Promoted, SubstsRef<'tcx>), + Static, } impl_stable_hash_for!(struct Static<'tcx> { ty, - kind + kind, + def_id }); -/// The `Projection` data structure defines things of the form `base.x`, `*b` or `b[index]`. -#[derive( - Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable, -)] -pub struct Projection<'tcx> { - pub base: Option>>, - pub elem: PlaceElem<'tcx>, -} - #[derive( Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable, )] @@ -1807,6 +1803,23 @@ pub enum ProjectionElem { Downcast(Option, VariantIdx), } +impl ProjectionElem { + /// Returns `true` if the target of this projection may refer to a different region of memory + /// than the base. + fn is_indirect(&self) -> bool { + match self { + Self::Deref => true, + + | Self::Field(_, _) + | Self::Index(_) + | Self::ConstantIndex { .. } + | Self::Subslice { .. } + | Self::Downcast(_, _) + => false + } + } +} + /// Alias for projections as they appear in places, where the base is a place /// and the index is a local. pub type PlaceElem<'tcx> = ProjectionElem>; @@ -1819,7 +1832,7 @@ static_assert_size!(PlaceElem<'_>, 16); /// need neither the `V` parameter for `Index` nor the `T` for `Field`. pub type ProjectionKind = ProjectionElem<(), ()>; -newtype_index! { +rustc_index::newtype_index! { pub struct Field { derive [HashStable] DEBUG_FORMAT = "field[{}]" @@ -1829,14 +1842,22 @@ newtype_index! { #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct PlaceRef<'a, 'tcx> { pub base: &'a PlaceBase<'tcx>, - pub projection: &'a Option>>, + pub projection: &'a [PlaceElem<'tcx>], } impl<'tcx> Place<'tcx> { - pub const RETURN_PLACE: Place<'tcx> = Place { - base: PlaceBase::Local(RETURN_PLACE), - projection: None, - }; + // FIXME change this back to a const when projection is a shared slice. + // + // pub const RETURN_PLACE: Place<'tcx> = Place { + // base: PlaceBase::Local(RETURN_PLACE), + // projection: &[], + // }; + pub fn return_place() -> Place<'tcx> { + Place { + base: PlaceBase::Local(RETURN_PLACE), + projection: Box::new([]), + } + } pub fn field(self, f: Field, ty: Ty<'tcx>) -> Place<'tcx> { self.elem(ProjectionElem::Field(f, ty)) @@ -1862,12 +1883,24 @@ impl<'tcx> Place<'tcx> { } pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> { + // FIXME(spastorino): revisit this again once projection is not a Box<[T]> anymore + let mut projection = self.projection.into_vec(); + projection.push(elem); + Place { base: self.base, - projection: Some(Box::new(Projection { base: self.projection, elem })), + projection: projection.into_boxed_slice(), } } + /// Returns `true` if this `Place` contains a `Deref` projection. + /// + /// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the + /// same region of memory as its base. + pub fn is_indirect(&self) -> bool { + self.projection.iter().any(|elem| elem.is_indirect()) + } + /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or /// a single deref of a local. // @@ -1876,59 +1909,23 @@ impl<'tcx> Place<'tcx> { match self { Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } | Place { base: PlaceBase::Local(local), - projection: Some(box Projection { - base: None, - elem: ProjectionElem::Deref, - }), + projection: box [ProjectionElem::Deref], } => Some(*local), _ => None, } } - /// Recursively "iterates" over place components, generating a `PlaceBase` and - /// `Projections` list and invoking `op` with a `ProjectionsIter`. - pub fn iterate( - &self, - op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R, - ) -> R { - Place::iterate_over(&self.base, &self.projection, op) - } - - pub fn iterate_over( - place_base: &PlaceBase<'tcx>, - place_projection: &Option>>, - op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R, - ) -> R { - fn iterate_over2<'tcx, R>( - place_base: &PlaceBase<'tcx>, - place_projection: &Option>>, - next: &Projections<'_, 'tcx>, - op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R, - ) -> R { - match place_projection { - None => { - op(place_base, next.iter()) - } - - Some(interior) => { - iterate_over2( - place_base, - &interior.base, - &Projections::List { - projection: interior, - next, - }, - op, - ) - } - } + /// If this place represents a local variable like `_X` with no + /// projections, return `Some(_X)`. + pub fn as_local(&self) -> Option { + match self { + Place { projection: box [], base: PlaceBase::Local(l) } => Some(*l), + _ => None, } - - iterate_over2(place_base, place_projection, &Projections::Empty, op) } pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> { @@ -1943,7 +1940,7 @@ impl From for Place<'_> { fn from(local: Local) -> Self { Place { base: local.into(), - projection: None, + projection: Box::new([]), } } } @@ -1955,13 +1952,6 @@ impl From for PlaceBase<'_> { } impl<'a, 'tcx> PlaceRef<'a, 'tcx> { - pub fn iterate( - &self, - op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R, - ) -> R { - Place::iterate_over(self.base, self.projection, op) - } - /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or /// a single deref of a local. // @@ -1970,143 +1960,71 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> { match self { PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } | PlaceRef { base: PlaceBase::Local(local), - projection: Some(box Projection { - base: None, - elem: ProjectionElem::Deref, - }), + projection: [ProjectionElem::Deref], } => Some(*local), _ => None, } } } -/// A linked list of projections running up the stack; begins with the -/// innermost projection and extends to the outermost (e.g., `a.b.c` -/// would have the place `b` with a "next" pointer to `b.c`). -/// Created by `Place::iterate`. -/// -/// N.B., this particular impl strategy is not the most obvious. It was -/// chosen because it makes a measurable difference to NLL -/// performance, as this code (`borrow_conflicts_with_place`) is somewhat hot. -pub enum Projections<'p, 'tcx> { - Empty, - - List { projection: &'p Projection<'tcx>, next: &'p Projections<'p, 'tcx> }, -} - -impl<'p, 'tcx> Projections<'p, 'tcx> { - fn iter(&self) -> ProjectionsIter<'_, 'tcx> { - ProjectionsIter { value: self } - } -} - -impl<'p, 'tcx> IntoIterator for &'p Projections<'p, 'tcx> { - type Item = &'p Projection<'tcx>; - type IntoIter = ProjectionsIter<'p, 'tcx>; - - /// Converts a list of `Projection` components into an iterator; - /// this iterator yields up a never-ending stream of `Option<&Place>`. - /// These begin with the "innermost" projection and then with each - /// projection therefrom. So given a place like `a.b.c` it would - /// yield up: - /// - /// ```notrust - /// Some(`a`), Some(`a.b`), Some(`a.b.c`), None, None, ... - /// ``` - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -/// Iterator over components; see `Projections::iter` for more -/// information. -/// -/// N.B., this is not a *true* Rust iterator -- the code above just -/// manually invokes `next`. This is because we (sometimes) want to -/// keep executing even after `None` has been returned. -pub struct ProjectionsIter<'p, 'tcx> { - pub value: &'p Projections<'p, 'tcx>, -} - -impl<'p, 'tcx> Iterator for ProjectionsIter<'p, 'tcx> { - type Item = &'p Projection<'tcx>; - - fn next(&mut self) -> Option { - if let &Projections::List { projection, next } = self.value { - self.value = next; - Some(projection) - } else { - None - } - } -} - -impl<'p, 'tcx> FusedIterator for ProjectionsIter<'p, 'tcx> {} - -impl<'tcx> Debug for Place<'tcx> { +impl Debug for Place<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - self.iterate(|_place_base, place_projections| { - // FIXME: remove this collect once we have migrated to slices - let projs_vec: Vec<_> = place_projections.collect(); - for projection in projs_vec.iter().rev() { - match projection.elem { - ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => { - write!(fmt, "(").unwrap(); - } - ProjectionElem::Deref => { - write!(fmt, "(*").unwrap(); - } - ProjectionElem::Index(_) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } => {} + for elem in self.projection.iter().rev() { + match elem { + ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => { + write!(fmt, "(").unwrap(); + } + ProjectionElem::Deref => { + write!(fmt, "(*").unwrap(); } + ProjectionElem::Index(_) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } => {} } - }); + } - self.iterate(|place_base, place_projections| { - write!(fmt, "{:?}", place_base)?; + write!(fmt, "{:?}", self.base)?; - for projection in place_projections { - match projection.elem { - ProjectionElem::Downcast(Some(name), _index) => { - write!(fmt, " as {})", name)?; - } - ProjectionElem::Downcast(None, index) => { - write!(fmt, " as variant#{:?})", index)?; - } - ProjectionElem::Deref => { - write!(fmt, ")")?; - } - ProjectionElem::Field(field, ty) => { - write!(fmt, ".{:?}: {:?})", field.index(), ty)?; - } - ProjectionElem::Index(ref index) => { - write!(fmt, "[{:?}]", index)?; - } - ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => { - write!(fmt, "[{:?} of {:?}]", offset, min_length)?; - } - ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => { - write!(fmt, "[-{:?} of {:?}]", offset, min_length)?; - } - ProjectionElem::Subslice { from, to } if to == 0 => { - write!(fmt, "[{:?}:]", from)?; - } - ProjectionElem::Subslice { from, to } if from == 0 => { - write!(fmt, "[:-{:?}]", to)?; - } - ProjectionElem::Subslice { from, to } => { - write!(fmt, "[{:?}:-{:?}]", from, to)?; - } + for elem in self.projection.iter() { + match elem { + ProjectionElem::Downcast(Some(name), _index) => { + write!(fmt, " as {})", name)?; + } + ProjectionElem::Downcast(None, index) => { + write!(fmt, " as variant#{:?})", index)?; + } + ProjectionElem::Deref => { + write!(fmt, ")")?; + } + ProjectionElem::Field(field, ty) => { + write!(fmt, ".{:?}: {:?})", field.index(), ty)?; + } + ProjectionElem::Index(ref index) => { + write!(fmt, "[{:?}]", index)?; + } + ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => { + write!(fmt, "[{:?} of {:?}]", offset, min_length)?; + } + ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => { + write!(fmt, "[-{:?} of {:?}]", offset, min_length)?; + } + ProjectionElem::Subslice { from, to } if *to == 0 => { + write!(fmt, "[{:?}:]", from)?; + } + ProjectionElem::Subslice { from, to } if *from == 0 => { + write!(fmt, "[:-{:?}]", to)?; + } + ProjectionElem::Subslice { from, to } => { + write!(fmt, "[{:?}:-{:?}]", from, to)?; } } + } - Ok(()) - }) + Ok(()) } } @@ -2114,10 +2032,12 @@ impl Debug for PlaceBase<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { match *self { PlaceBase::Local(id) => write!(fmt, "{:?}", id), - PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static(def_id) }) => { + PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static, def_id }) => { write!(fmt, "({}: {:?})", ty::tls::with(|tcx| tcx.def_path_str(def_id)), ty) } - PlaceBase::Static(box self::Static { ty, kind: StaticKind::Promoted(promoted) }) => { + PlaceBase::Static(box self::Static { + ty, kind: StaticKind::Promoted(promoted, _), def_id: _ + }) => { write!(fmt, "({:?}: {:?})", promoted, ty) } } @@ -2127,7 +2047,7 @@ impl Debug for PlaceBase<'_> { /////////////////////////////////////////////////////////////////////////// // Scopes -newtype_index! { +rustc_index::newtype_index! { pub struct SourceScope { derive [HashStable] DEBUG_FORMAT = "scope[{}]", @@ -2143,7 +2063,7 @@ pub struct SourceScopeData { #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] pub struct SourceScopeLocalData { - /// A HirId with lint levels equivalent to this scope's lint levels. + /// An `HirId` with lint levels equivalent to this scope's lint levels. pub lint_root: hir::HirId, /// The unsafe block that contains this node. pub safety: Safety, @@ -2197,7 +2117,6 @@ impl<'tcx> Operand<'tcx> { let ty = tcx.type_of(def_id).subst(tcx, substs); Operand::Constant(box Constant { span, - ty, user_ty: None, literal: ty::Const::zero_sized(tcx, ty), }) @@ -2269,8 +2188,8 @@ pub enum AggregateKind<'tcx> { /// active field index would identity the field `c` Adt(&'tcx AdtDef, VariantIdx, SubstsRef<'tcx>, Option, Option), - Closure(DefId, ClosureSubsts<'tcx>), - Generator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability), + Closure(DefId, SubstsRef<'tcx>), + Generator(DefId, SubstsRef<'tcx>, hir::GeneratorMovability), } #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] @@ -2476,7 +2395,6 @@ impl<'tcx> Debug for Rvalue<'tcx> { #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] pub struct Constant<'tcx> { pub span: Span, - pub ty: Ty<'tcx>, /// Optional user-given type: for something like /// `collect::>`, this would be present and would @@ -2668,7 +2586,7 @@ impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection { } } -newtype_index! { +rustc_index::newtype_index! { pub struct Promoted { derive [HashStable] DEBUG_FORMAT = "promoted[{}]" @@ -2684,7 +2602,14 @@ impl<'tcx> Debug for Constant<'tcx> { impl<'tcx> Display for Constant<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { write!(fmt, "const ")?; - write!(fmt, "{}", self.literal) + // FIXME make the default pretty printing of raw pointers more detailed. Here we output the + // debug representation of raw pointers, so that the raw pointers in the mir dump output are + // detailed and just not '{pointer}'. + if let ty::RawPtr(_) = self.literal.ty.kind { + write!(fmt, "{:?} : {}", self.literal.val, self.literal.ty) + } else { + write!(fmt, "{}", self.literal) + } } } @@ -2734,11 +2659,12 @@ impl<'a, 'b> graph::GraphSuccessors<'b> for Body<'a> { #[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, HashStable)] pub struct Location { - /// the location is within this block + /// The block that the location is within. pub block: BasicBlock, - /// the location is the start of the statement; or, if `statement_index` - /// == num-statements, then the start of the terminator. + /// The location is the position of the start of the statement; or, if + /// `statement_index` equals the number of statements, then the start of the + /// terminator. pub statement_index: usize, } @@ -2801,7 +2727,7 @@ impl Location { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] pub enum UnsafetyViolationKind { General, - /// Permitted in const fn and regular fns. + /// Permitted both in `const fn`s and regular `fn`s. GeneralAndConstFn, ExternStatic(hir::HirId), BorrowPacked(hir::HirId), @@ -2817,21 +2743,21 @@ pub struct UnsafetyViolation { #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] pub struct UnsafetyCheckResult { - /// Violations that are propagated *upwards* from this function + /// Violations that are propagated *upwards* from this function. pub violations: Lrc<[UnsafetyViolation]>, - /// unsafe blocks in this function, along with whether they are used. This is + /// `unsafe` blocks in this function, along with whether they are used. This is /// used for the "unused_unsafe" lint. pub unsafe_blocks: Lrc<[(hir::HirId, bool)]>, } -newtype_index! { +rustc_index::newtype_index! { pub struct GeneratorSavedLocal { derive [HashStable] DEBUG_FORMAT = "_{}", } } -/// The layout of generator state +/// The layout of generator state. #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] pub struct GeneratorLayout<'tcx> { /// The type of every local stored inside the generator. @@ -2846,11 +2772,14 @@ pub struct GeneratorLayout<'tcx> { /// layout. pub storage_conflicts: BitMatrix, - /// Names and scopes of all the stored generator locals. - /// NOTE(tmandry) This is *strictly* a temporary hack for codegen + /// The names and scopes of all the stored generator locals. + /// + /// N.B., this is *strictly* a temporary hack for codegen /// debuginfo generation, and will be removed at some point. /// Do **NOT** use it for anything else, local information should not be /// in the MIR, please rely on local crate HIR or other side-channels. + // + // FIXME(tmandry): see above. pub __local_debuginfo_codegen_only_do_not_use: IndexVec>, } @@ -2908,7 +2837,7 @@ pub struct BorrowCheckResult<'tcx> { /// instances assigned one of these same indices. Those regions will /// be substituted away by the creator. We use `ReClosureBound` in /// that case because the regions must be allocated in the global -/// TyCtxt, and hence we cannot use `ReVar` (which is what we use +/// `TyCtxt`, and hence we cannot use `ReVar` (which is what we use /// internally within the rest of the NLL code). #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] pub struct ClosureRegionRequirements<'tcx> { @@ -2924,8 +2853,8 @@ pub struct ClosureRegionRequirements<'tcx> { pub outlives_requirements: Vec>, } -/// Indicates an outlives constraint between a type or between two -/// free-regions declared on the closure. +/// Indicates an outlives-constraint between a type or between two +/// free regions declared on the closure. #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] pub struct ClosureOutlivesRequirement<'tcx> { // This region or type ... @@ -2941,11 +2870,11 @@ pub struct ClosureOutlivesRequirement<'tcx> { pub category: ConstraintCategory, } -/// Outlives constraints can be categorized to determine whether and why they +/// Outlives-constraints can be categorized to determine whether and why they /// are interesting (for error reporting). Order of variants indicates sort /// order of the category, thereby influencing diagnostic output. /// -/// See also [rustc_mir::borrow_check::nll::constraints] +/// See also [rustc_mir::borrow_check::nll::constraints]. #[derive( Copy, Clone, @@ -2993,7 +2922,7 @@ pub enum ConstraintCategory { Internal, } -/// The subject of a ClosureOutlivesRequirement -- that is, the thing +/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing /// that must outlive some region. #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] pub enum ClosureOutlivesSubject<'tcx> { @@ -3011,7 +2940,7 @@ pub enum ClosureOutlivesSubject<'tcx> { } /* - * TypeFoldable implementations for MIR types + * `TypeFoldable` implementations for MIR types */ CloneTypeFoldableAndLiftImpls! { @@ -3034,7 +2963,6 @@ BraceStructTypeFoldableImpl! { basic_blocks, source_scopes, source_scope_local_data, - promoted, yield_ty, generator_drop, generator_layout, @@ -3088,14 +3016,14 @@ BraceStructTypeFoldableImpl! { EnumTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> { - (StatementKind::Assign)(a, b), + (StatementKind::Assign)(a), (StatementKind::FakeRead)(cause, place), (StatementKind::SetDiscriminant) { place, variant_index }, (StatementKind::StorageLive)(a), (StatementKind::StorageDead)(a), (StatementKind::InlineAsm)(a), (StatementKind::Retag)(kind, place), - (StatementKind::AscribeUserType)(a, v, b), + (StatementKind::AscribeUserType)(a, v), (StatementKind::Nop), } } @@ -3228,13 +3156,63 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { Place { - base: self.base.clone(), + base: self.base.fold_with(folder), projection: self.projection.fold_with(folder), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.projection.visit_with(visitor) + self.base.visit_with(visitor) || self.projection.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for PlaceBase<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + match self { + PlaceBase::Local(local) => PlaceBase::Local(local.fold_with(folder)), + PlaceBase::Static(static_) => PlaceBase::Static(static_.fold_with(folder)), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match self { + PlaceBase::Local(local) => local.visit_with(visitor), + PlaceBase::Static(static_) => (**static_).visit_with(visitor), + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Static<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + Static { + ty: self.ty.fold_with(folder), + kind: self.kind.fold_with(folder), + def_id: self.def_id, + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + let Static { ty, kind, def_id: _ } = self; + + ty.visit_with(visitor) || kind.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for StaticKind<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + match self { + StaticKind::Promoted(promoted, substs) => + StaticKind::Promoted(promoted.fold_with(folder), substs.fold_with(folder)), + StaticKind::Static => StaticKind::Static + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match self { + StaticKind::Promoted(promoted, substs) => + promoted.visit_with(visitor) || substs.visit_with(visitor), + StaticKind::Static => { false } + } } } @@ -3327,30 +3305,26 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for Projection<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { use crate::mir::ProjectionElem::*; - let base = self.base.fold_with(folder); - let elem = match self.elem { + match self { Deref => Deref, - Field(f, ref ty) => Field(f, ty.fold_with(folder)), - Index(ref v) => Index(v.fold_with(folder)), - ref elem => elem.clone(), - }; - - Projection { base, elem } + Field(f, ty) => Field(*f, ty.fold_with(folder)), + Index(v) => Index(v.fold_with(folder)), + elem => elem.clone(), + } } fn super_visit_with>(&self, visitor: &mut Vs) -> bool { use crate::mir::ProjectionElem::*; - self.base.visit_with(visitor) - || match self.elem { - Field(_, ref ty) => ty.visit_with(visitor), - Index(ref v) => v.visit_with(visitor), - _ => false, - } + match self { + Field(_, ty) => ty.visit_with(visitor), + Index(v) => v.visit_with(visitor), + _ => false, + } } } @@ -3385,12 +3359,11 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { Constant { span: self.span.clone(), - ty: self.ty.fold_with(folder), user_ty: self.user_ty.fold_with(folder), literal: self.literal.fold_with(folder), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.ty.visit_with(visitor) || self.literal.visit_with(visitor) + self.literal.visit_with(visitor) } } diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index a061e6f48f4c0..265ac975ed7a2 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -8,8 +8,7 @@ use crate::util::nodemap::FxHashMap; use crate::ty::print::obsolete::DefPathBasedNames; use crate::dep_graph::{WorkProductId, DepNode, WorkProduct, DepConstructor}; use rustc_data_structures::base_n; -use rustc_data_structures::stable_hasher::{HashStable, StableHasherResult, - StableHasher}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use crate::ich::{Fingerprint, StableHashingContext, NodeIdHashingMode}; use crate::session::config::OptLevel; use std::fmt; @@ -223,9 +222,7 @@ impl<'tcx> MonoItem<'tcx> { } impl<'a, 'tcx> HashStable> for MonoItem<'tcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { ::std::mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -389,6 +386,7 @@ impl<'tcx> CodegenUnit<'tcx> { tcx.hir().as_local_hir_id(def_id) } InstanceDef::VtableShim(..) | + InstanceDef::ReifyShim(..) | InstanceDef::Intrinsic(..) | InstanceDef::FnPtrShim(..) | InstanceDef::Virtual(..) | @@ -419,9 +417,7 @@ impl<'tcx> CodegenUnit<'tcx> { } impl<'a, 'tcx> HashStable> for CodegenUnit<'tcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let CodegenUnit { ref items, name, diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index f8889380b2abf..e87aabf9a0566 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -34,7 +34,7 @@ impl<'tcx> PlaceTy<'tcx> { /// /// Note that the resulting type has not been normalized. pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: &Field) -> Ty<'tcx> { - let answer = match self.ty.sty { + let answer = match self.ty.kind { ty::Adt(adt_def, substs) => { let variant_def = match self.variant_index { None => adt_def.non_enum_variant(), @@ -89,7 +89,7 @@ impl<'tcx> PlaceTy<'tcx> { ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => PlaceTy::from_ty(self.ty.builtin_index().unwrap()), ProjectionElem::Subslice { from, to } => { - PlaceTy::from_ty(match self.ty.sty { + PlaceTy::from_ty(match self.ty.kind { ty::Array(inner, size) => { let size = size.eval_usize(tcx, param_env); let len = size - (from as u64) - (to as u64); @@ -121,21 +121,16 @@ BraceStructTypeFoldableImpl! { impl<'tcx> Place<'tcx> { pub fn ty_from( base: &PlaceBase<'tcx>, - projection: &Option>>, + projection: &[PlaceElem<'tcx>], local_decls: &D, tcx: TyCtxt<'tcx> ) -> PlaceTy<'tcx> where D: HasLocalDecls<'tcx> { - Place::iterate_over(base, projection, |place_base, place_projections| { - let mut place_ty = place_base.ty(local_decls); - - for proj in place_projections { - place_ty = place_ty.projection_ty(tcx, &proj.elem); - } - - place_ty - }) + projection.iter().fold( + base.ty(local_decls), + |place_ty, elem| place_ty.projection_ty(tcx, elem) + ) } pub fn ty(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> @@ -200,9 +195,9 @@ impl<'tcx> Rvalue<'tcx> { } Rvalue::Discriminant(ref place) => { let ty = place.ty(local_decls, tcx).ty; - match ty.sty { + match ty.kind { ty::Adt(adt_def, _) => adt_def.repr.discr_type().to_ty(tcx), - ty::Generator(_, substs, _) => substs.discr_ty(tcx), + ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx), _ => { // This can only be `0`, for now, so `u8` will suffice. tcx.types.u8 @@ -252,7 +247,7 @@ impl<'tcx> Operand<'tcx> { match self { &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty, - &Operand::Constant(ref c) => c.ty, + &Operand::Constant(ref c) => c.literal.ty, } } } diff --git a/src/librustc/mir/traversal.rs b/src/librustc/mir/traversal.rs index 1416a5f0a6e9f..f129dd3abeff7 100644 --- a/src/librustc/mir/traversal.rs +++ b/src/librustc/mir/traversal.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::bit_set::BitSet; +use rustc_index::bit_set::BitSet; use super::*; diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index ee4ecb6762c96..edc7922f46eec 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -1,5 +1,5 @@ use crate::ty::subst::SubstsRef; -use crate::ty::{CanonicalUserTypeAnnotation, ClosureSubsts, GeneratorSubsts, Ty}; +use crate::ty::{CanonicalUserTypeAnnotation, Ty}; use crate::mir::*; use syntax_pos::Span; @@ -152,18 +152,27 @@ macro_rules! make_mir_visitor { } fn visit_place_base(&mut self, - place_base: & $($mutability)? PlaceBase<'tcx>, + base: & $($mutability)? PlaceBase<'tcx>, context: PlaceContext, location: Location) { - self.super_place_base(place_base, context, location); + self.super_place_base(base, context, location); } fn visit_projection(&mut self, - place_base: & $($mutability)? PlaceBase<'tcx>, - place: & $($mutability)? Projection<'tcx>, + base: & $($mutability)? PlaceBase<'tcx>, + projection: & $($mutability)? [PlaceElem<'tcx>], context: PlaceContext, location: Location) { - self.super_projection(place_base, place, context, location); + self.super_projection(base, projection, context, location); + } + + fn visit_projection_elem(&mut self, + base: & $($mutability)? PlaceBase<'tcx>, + proj_base: & $($mutability)? [PlaceElem<'tcx>], + elem: & $($mutability)? PlaceElem<'tcx>, + context: PlaceContext, + location: Location) { + self.super_projection_elem(base, proj_base, elem, context, location); } fn visit_constant(&mut self, @@ -221,18 +230,6 @@ macro_rules! make_mir_visitor { self.super_substs(substs); } - fn visit_closure_substs(&mut self, - substs: & $($mutability)? ClosureSubsts<'tcx>, - _: Location) { - self.super_closure_substs(substs); - } - - fn visit_generator_substs(&mut self, - substs: & $($mutability)? GeneratorSubsts<'tcx>, - _: Location) { - self.super_generator_substs(substs); - } - fn visit_local_decl(&mut self, local: Local, local_decl: & $($mutability)? LocalDecl<'tcx>) { @@ -344,7 +341,9 @@ macro_rules! make_mir_visitor { self.visit_source_info(source_info); match kind { - StatementKind::Assign(place, rvalue) => { + StatementKind::Assign( + box(ref $($mutability)? place, ref $($mutability)? rvalue) + ) => { self.visit_assign(place, rvalue, location); } StatementKind::FakeRead(_, place) => { @@ -391,7 +390,10 @@ macro_rules! make_mir_visitor { StatementKind::Retag(kind, place) => { self.visit_retag(kind, place, location); } - StatementKind::AscribeUserType(place, variance, user_ty) => { + StatementKind::AscribeUserType( + box(ref $($mutability)? place, ref $($mutability)? user_ty), + variance + ) => { self.visit_ascribe_user_ty(place, variance, user_ty, location); } StatementKind::Nop => {} @@ -613,14 +615,14 @@ macro_rules! make_mir_visitor { _, closure_substs ) => { - self.visit_closure_substs(closure_substs, location); + self.visit_substs(closure_substs, location); } AggregateKind::Generator( _, generator_substs, _movability, ) => { - self.visit_generator_substs(generator_substs, location); + self.visit_substs(generator_substs, location); } } @@ -685,7 +687,7 @@ macro_rules! make_mir_visitor { location: Location) { let mut context = context; - if place.projection.is_some() { + if !place.projection.is_empty() { context = if context.is_mutating_use() { PlaceContext::MutatingUse(MutatingUseContext::Projection) } else { @@ -695,9 +697,10 @@ macro_rules! make_mir_visitor { self.visit_place_base(& $($mutability)? place.base, context, location); - if let Some(box proj) = & $($mutability)? place.projection { - self.visit_projection(& $($mutability)? place.base, proj, context, location); - } + self.visit_projection(& $($mutability)? place.base, + & $($mutability)? place.projection, + context, + location); } fn super_place_base(&mut self, @@ -708,26 +711,31 @@ macro_rules! make_mir_visitor { PlaceBase::Local(local) => { self.visit_local(local, context, location); } - PlaceBase::Static(box Static { kind: _, ty }) => { + PlaceBase::Static(box Static { kind: _, ty, def_id: _ }) => { self.visit_ty(& $($mutability)? *ty, TyContext::Location(location)); } } } fn super_projection(&mut self, - place_base: & $($mutability)? PlaceBase<'tcx>, - proj: & $($mutability)? Projection<'tcx>, + base: & $($mutability)? PlaceBase<'tcx>, + projection: & $($mutability)? [PlaceElem<'tcx>], context: PlaceContext, location: Location) { - if let Some(box proj_base) = & $($mutability)? proj.base { - self.visit_projection(place_base, proj_base, context, location); + let mut cursor = projection; + while let [proj_base @ .., elem] = cursor { + cursor = proj_base; + self.visit_projection_elem(base, cursor, elem, context, location); } + } - match & $($mutability)? proj.elem { - ProjectionElem::Deref => { - } - ProjectionElem::Subslice { from: _, to: _ } => { - } + fn super_projection_elem(&mut self, + _base: & $($mutability)? PlaceBase<'tcx>, + _proj_base: & $($mutability)? [PlaceElem<'tcx>], + elem: & $($mutability)? PlaceElem<'tcx>, + _context: PlaceContext, + location: Location) { + match elem { ProjectionElem::Field(_field, ty) => { self.visit_ty(ty, TyContext::Location(location)); } @@ -738,11 +746,12 @@ macro_rules! make_mir_visitor { location ); } + ProjectionElem::Deref | + ProjectionElem::Subslice { from: _, to: _ } | ProjectionElem::ConstantIndex { offset: _, min_length: _, - from_end: _ } => { - } - ProjectionElem::Downcast(_name, _variant_index) => { + from_end: _ } | + ProjectionElem::Downcast(_, _) => { } } } @@ -782,13 +791,11 @@ macro_rules! make_mir_visitor { location: Location) { let Constant { span, - ty, user_ty, literal, } = constant; self.visit_span(span); - self.visit_ty(ty, TyContext::Location(location)); drop(user_ty); // no visit method for this self.visit_const(literal, location); } @@ -833,14 +840,6 @@ macro_rules! make_mir_visitor { fn super_substs(&mut self, _substs: & $($mutability)? SubstsRef<'tcx>) { } - fn super_generator_substs(&mut self, - _substs: & $($mutability)? GeneratorSubsts<'tcx>) { - } - - fn super_closure_substs(&mut self, - _substs: & $($mutability)? ClosureSubsts<'tcx>) { - } - // Convenience methods fn visit_location(&mut self, body: & $($mutability)? Body<'tcx>, location: Location) { diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 5ab1b90642a6a..c95652f274e36 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -17,7 +17,6 @@ use crate::traits::query::{ use std::borrow::Cow; use syntax_pos::symbol::InternedString; - // Each of these queries corresponds to a function pointer field in the // `Providers` struct for requesting a value of that type, and a method // on `tcx: TyCtxt` (and `tcx.at(span)`) for doing that request in a way @@ -95,6 +94,7 @@ rustc_queries! { /// of the MIR qualify_consts pass. The actual meaning of /// the value isn't known except to the pass itself. query mir_const_qualif(key: DefId) -> (u8, &'tcx BitSet) { + desc { |tcx| "const checking `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } } @@ -110,7 +110,11 @@ rustc_queries! { no_hash } - query mir_validated(_: DefId) -> &'tcx Steal> { + query mir_validated(_: DefId) -> + ( + &'tcx Steal>, + &'tcx Steal>> + ) { no_hash } @@ -125,7 +129,17 @@ rustc_queries! { } } - query promoted_mir(key: DefId) -> &'tcx IndexVec> { } + query promoted_mir(key: DefId) -> &'tcx IndexVec> { + cache_on_disk_if { key.is_local() } + load_cached(tcx, id) { + let promoted: Option< + rustc_index::vec::IndexVec< + crate::mir::Promoted, + crate::mir::Body<'tcx> + >> = tcx.queries.on_disk_cache.try_load_query_result(tcx, id); + promoted.map(|p| &*tcx.arena.alloc(p)) + } + } } TypeChecking { @@ -231,6 +245,10 @@ rustc_queries! { desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) } } + query asyncness(key: DefId) -> hir::IsAsync { + desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) } + } + /// Returns `true` if calls to the function may be promoted. /// /// This is either because the function is e.g., a tuple-struct or tuple-variant @@ -273,7 +291,7 @@ rustc_queries! { query associated_item(_: DefId) -> ty::AssocItem {} query impl_trait_ref(_: DefId) -> Option> {} - query impl_polarity(_: DefId) -> hir::ImplPolarity {} + query impl_polarity(_: DefId) -> ty::ImplPolarity {} query issue33140_self_ty(_: DefId) -> Option> {} } @@ -380,10 +398,6 @@ rustc_queries! { } BorrowChecking { - query borrowck(key: DefId) -> &'tcx BorrowCheckResult { - cache_on_disk_if { key.is_local() } - } - /// Borrow-checks the function body. If this is a closure, returns /// additional requirements that the closure's creator must verify. query mir_borrowck(key: DefId) -> mir::BorrowCheckResult<'tcx> { @@ -449,19 +463,10 @@ rustc_queries! { no_force desc { "extract field of const" } } - - /// Produces an absolute path representation of the given type. See also the documentation - /// on `std::any::type_name`. - query type_name(key: Ty<'tcx>) -> &'tcx ty::Const<'tcx> { - eval_always - no_force - desc { "get absolute path of type" } - } - } TypeChecking { - query check_match(key: DefId) -> SignalledError { + query check_match(key: DefId) { cache_on_disk_if { key.is_local() } } @@ -526,19 +531,6 @@ rustc_queries! { TypeChecking { query trait_of_item(_: DefId) -> Option {} - query const_is_rvalue_promotable_to_static(key: DefId) -> bool { - desc { |tcx| - "const checking if rvalue is promotable to static `{}`", - tcx.def_path_str(key) - } - cache_on_disk_if { true } - } - query rvalue_promotable_map(key: DefId) -> &'tcx ItemLocalSet { - desc { |tcx| - "checking which parts of `{}` are promotable to static", - tcx.def_path_str(key) - } - } } Codegen { @@ -626,6 +618,12 @@ rustc_queries! { -> &'tcx [(CrateNum, LinkagePreference)] { desc { "dylib dependency formats of crate" } } + + query dependency_formats(_: CrateNum) + -> Lrc + { + desc { "get the linkage format of all dependencies" } + } } Codegen { @@ -790,7 +788,7 @@ rustc_queries! { } BorrowChecking { - // Lifetime resolution. See `middle::resolve_lifetimes`. + /// Lifetime resolution. See `middle::resolve_lifetimes`. query resolve_lifetimes(_: CrateNum) -> &'tcx ResolveLifetimes { desc { "resolving lifetimes" } } @@ -832,13 +830,30 @@ rustc_queries! { -> &'tcx [(Symbol, Option)] { desc { "calculating the lib features defined in a crate" } } + /// Returns the lang items defined in another crate by loading it from metadata. + // FIXME: It is illegal to pass a `CrateNum` other than `LOCAL_CRATE` here, just get rid + // of that argument? query get_lang_items(_: CrateNum) -> &'tcx LanguageItems { eval_always desc { "calculating the lang items map" } } + + /// Returns all diagnostic items defined in all crates. + query all_diagnostic_items(_: CrateNum) -> &'tcx FxHashMap { + eval_always + desc { "calculating the diagnostic items map" } + } + + /// Returns the lang items defined in another crate by loading it from metadata. query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, usize)] { desc { "calculating the lang items defined in a crate" } } + + /// Returns the diagnostic items defined in a crate. + query diagnostic_items(_: CrateNum) -> &'tcx FxHashMap { + desc { "calculating the diagnostic items map in a crate" } + } + query missing_lang_items(_: CrateNum) -> &'tcx [LangItem] { desc { "calculating the missing lang items in a crate" } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 3536b2aa8fffe..25e68e6408de2 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1,36 +1,38 @@ //! Contains infrastructure for configuring the compiler, including parsing -//! command line options. - -use std::str::FromStr; +//! command-line options. +use crate::lint; +use crate::middle::cstore; use crate::session::{early_error, early_warn, Session}; use crate::session::search_paths::SearchPath; +use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::sync::Lrc; + use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel}; use rustc_target::spec::{Target, TargetTriple}; -use crate::lint; -use crate::middle::cstore; use syntax; use syntax::ast::{self, IntTy, UintTy, MetaItemKind}; use syntax::source_map::{FileName, FilePathMapping}; use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION}; +use syntax::parse::{ParseSess, new_parser_from_source_str}; use syntax::parse::token; -use syntax::parse; use syntax::symbol::{sym, Symbol}; use syntax::feature_gate::UnstableFeatures; -use errors::emitter::HumanReadableErrorType; +use syntax::source_map::SourceMap; +use errors::emitter::HumanReadableErrorType; use errors::{ColorConfig, FatalError, Handler}; use getopts; -use std::collections::{BTreeMap, BTreeSet}; -use std::collections::btree_map::Iter as BTreeMapIter; -use std::collections::btree_map::Keys as BTreeMapKeysIter; -use std::collections::btree_map::Values as BTreeMapValuesIter; -use rustc_data_structures::fx::FxHashSet; -use std::{fmt, str}; +use std::collections::{BTreeMap, BTreeSet}; +use std::collections::btree_map::{ + Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter, +}; +use std::fmt; +use std::str::{self, FromStr}; use std::hash::Hasher; use std::collections::hash_map::DefaultHasher; use std::iter::FromIterator; @@ -241,14 +243,14 @@ pub enum ErrorOutputType { } impl Default for ErrorOutputType { - fn default() -> ErrorOutputType { - ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto)) + fn default() -> Self { + Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto)) } } -// Use tree-based collections to cheaply get a deterministic Hash implementation. -// DO NOT switch BTreeMap out for an unsorted container type! That would break -// dependency tracking for command-line arguments. +/// Use tree-based collections to cheaply get a deterministic `Hash` implementation. +/// *Do not* switch `BTreeMap` out for an unsorted container type! That would break +/// dependency tracking for command-line arguments. #[derive(Clone, Hash)] pub struct OutputTypes(BTreeMap>); @@ -281,7 +283,7 @@ impl OutputTypes { self.0.len() } - // True if any of the output types require codegen or linking. + // Returns `true` if any of the output types require codegen or linking. pub fn should_codegen(&self) -> bool { self.0.keys().any(|k| match *k { OutputType::Bitcode @@ -295,9 +297,9 @@ impl OutputTypes { } } -// Use tree-based collections to cheaply get a deterministic Hash implementation. -// DO NOT switch BTreeMap or BTreeSet out for an unsorted container type! That -// would break dependency tracking for command-line arguments. +/// Use tree-based collections to cheaply get a deterministic `Hash` implementation. +/// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That +/// would break dependency tracking for command-line arguments. #[derive(Clone, Hash)] pub struct Externs(BTreeMap); @@ -327,7 +329,7 @@ macro_rules! hash_option { ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({ if $sub_hashes.insert(stringify!($opt_name), $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() { - bug!("Duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name)) + bug!("duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name)) } }); } @@ -362,7 +364,7 @@ macro_rules! top_level_options { ); } -// The top-level command-line options struct +// The top-level command-line options struct. // // For each option, one has to specify how it behaves with regard to the // dependency tracking system of incremental compilation. This is done via the @@ -376,16 +378,16 @@ macro_rules! top_level_options { // Incremental compilation is not influenced by this option. // // If you add a new option to this struct or one of the sub-structs like -// CodegenOptions, think about how it influences incremental compilation. If in +// `CodegenOptions`, think about how it influences incremental compilation. If in // doubt, specify [TRACKED], which is always "correct" but might lead to // unnecessary re-compilation. top_level_options!( pub struct Options { // The crate config requested for the session, which may be combined - // with additional crate configurations during the compile process + // with additional crate configurations during the compile process. crate_types: Vec [TRACKED], optimize: OptLevel [TRACKED], - // Include the debug_assertions flag into dependency tracking, since it + // Include the `debug_assertions` flag in dependency tracking, since it // can influence whether overflow checks are done or not. debug_assertions: bool [TRACKED], debuginfo: DebugInfo [TRACKED], @@ -395,15 +397,15 @@ top_level_options!( output_types: OutputTypes [TRACKED], search_paths: Vec [UNTRACKED], libs: Vec<(String, Option, Option)> [TRACKED], - maybe_sysroot: Option [TRACKED], + maybe_sysroot: Option [UNTRACKED], target_triple: TargetTriple [TRACKED], test: bool [TRACKED], error_format: ErrorOutputType [UNTRACKED], - // if Some, enable incremental compilation, using the given - // directory to store intermediate results + // If `Some`, enable incremental compilation, using the given + // directory to store intermediate results. incremental: Option [UNTRACKED], debugging_opts: DebuggingOptions [TRACKED], @@ -418,7 +420,7 @@ top_level_options!( // written `extern crate name as std`. Defaults to `std`. Used by // out-of-tree drivers. alt_std_name: Option [TRACKED], - // Indicates how the compiler should treat unstable features + // Indicates how the compiler should treat unstable features. unstable_features: UnstableFeatures [TRACKED], // Indicates whether this run of the compiler is actually rustdoc. This @@ -434,12 +436,12 @@ top_level_options!( cli_forced_codegen_units: Option [UNTRACKED], cli_forced_thinlto_off: bool [UNTRACKED], - // Remap source path prefixes in all output (messages, object files, debug, etc) + // Remap source path prefixes in all output (messages, object files, debug, etc.). remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED], edition: Edition [TRACKED], - // Whether or not we're emitting JSON blobs about each artifact produced + // `true` if we're emitting JSON blobs about each artifact produced // by the compiler. json_artifact_notifications: bool [TRACKED], } @@ -468,7 +470,7 @@ pub enum BorrowckMode { } impl BorrowckMode { - /// Should we run the MIR-based borrow check, but also fall back + /// Returns whether we should run the MIR-based borrow check, but also fall back /// on the AST borrow check if the MIR-based one errors. pub fn migrate(self) -> bool { match self { @@ -476,23 +478,16 @@ impl BorrowckMode { BorrowckMode::Migrate => true, } } - - /// Should we emit the AST-based borrow checker errors? - pub fn use_ast(self) -> bool { - match self { - BorrowckMode::Mir => false, - BorrowckMode::Migrate => false, - } - } } pub enum Input { - /// Loads source from file + /// Load source code from a file. File(PathBuf), + /// Load source code from a string. Str { - /// String that is shown in place of a filename + /// A string that is shown in place of a filename. name: FileName, - /// Anonymous source string + /// An anonymous string containing the source code. input: String, }, } @@ -651,7 +646,7 @@ impl Options { FilePathMapping::new(self.remap_path_prefix.clone()) } - /// Returns `true` if there will be an output file generated + /// Returns `true` if there will be an output file generated. pub fn will_create_output_file(&self) -> bool { !self.debugging_opts.parse_only && // The file is just being parsed !self.debugging_opts.ls // The file is just being queried @@ -684,7 +679,7 @@ pub enum EntryFnType { impl_stable_hash_via_hash!(EntryFnType); -#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)] +#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, HashStable)] pub enum CrateType { Executable, Dylib, @@ -709,16 +704,14 @@ impl Passes { } } -/// Declare a macro that will define all CodegenOptions/DebuggingOptions fields and parsers all -/// at once. The goal of this macro is to define an interface that can be -/// programmatically used by the option parser in order to initialize the struct -/// without hardcoding field names all over the place. +/// Defines all `CodegenOptions`/`DebuggingOptions` fields and parsers all at once. The goal of this +/// macro is to define an interface that can be programmatically used by the option parser +/// to initialize the struct without hardcoding field names all over the place. /// -/// The goal is to invoke this macro once with the correct fields, and then this -/// macro generates all necessary code. The main gotcha of this macro is the -/// cgsetters module which is a bunch of generated code to parse an option into -/// its respective field in the struct. There are a few hand-written parsers for -/// parsing specific types of values in this module. +/// The goal is to invoke this macro once with the correct fields, and then this macro generates all +/// necessary code. The main gotcha of this macro is the `cgsetters` module which is a bunch of +/// generated code to parse an option into its respective field in the struct. There are a few +/// hand-written parsers for parsing specific types of values in this module. macro_rules! options { ($struct_name:ident, $setter_name:ident, $defaultfn:ident, $buildfn:ident, $prefix:expr, $outputname:expr, @@ -812,6 +805,7 @@ macro_rules! options { pub const parse_list: Option<&str> = Some("a space-separated list of strings"); pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings"); pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings"); + pub const parse_threads: Option<&str> = Some("a number"); pub const parse_uint: Option<&str> = Some("a number"); pub const parse_passes: Option<&str> = Some("a space-separated list of passes, or `all`"); @@ -955,6 +949,14 @@ macro_rules! options { } } + fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool { + match v.and_then(|s| s.parse().ok()) { + Some(0) => { *slot = ::num_cpus::get(); true }, + Some(i) => { *slot = i; true }, + None => false + } + } + fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool { match v.and_then(|s| s.parse().ok()) { Some(i) => { *slot = i; true }, @@ -1258,7 +1260,11 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "prints the LLVM optimization passes being run"), ast_json: bool = (false, parse_bool, [UNTRACKED], "print the AST as JSON and halt"), - threads: Option = (None, parse_opt_uint, [UNTRACKED], + // We default to 1 here since we want to behave like + // a sequential compiler for now. This'll likely be adjusted + // in the future. Note that -Zthreads=0 is the way to get + // the num_cpus behavior. + threads: usize = (1, parse_threads, [UNTRACKED], "use a thread pool with N threads"), ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED], "print the pre-expansion AST as JSON and halt"), @@ -1267,14 +1273,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, save_analysis: bool = (false, parse_bool, [UNTRACKED], "write syntax and type analysis (in JSON format) information, in \ addition to normal output"), - flowgraph_print_loans: bool = (false, parse_bool, [UNTRACKED], - "include loan analysis data in -Z unpretty flowgraph output"), - flowgraph_print_moves: bool = (false, parse_bool, [UNTRACKED], - "include move analysis data in -Z unpretty flowgraph output"), - flowgraph_print_assigns: bool = (false, parse_bool, [UNTRACKED], - "include assignment analysis data in -Z unpretty flowgraph output"), - flowgraph_print_all: bool = (false, parse_bool, [UNTRACKED], - "include all dataflow analysis data in -Z unpretty flowgraph output"), print_region_graph: bool = (false, parse_bool, [UNTRACKED], "prints region inference graph. \ Use with RUST_REGION_GRAPH=help for more info"), @@ -1292,6 +1290,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "show macro backtraces even for non-local macros"), teach: bool = (false, parse_bool, [TRACKED], "show extended diagnostic help"), + terminal_width: Option = (None, parse_opt_uint, [UNTRACKED], + "set the current terminal width"), + panic_abort_tests: bool = (false, parse_bool, [TRACKED], + "support compiling tests with panic=abort"), continue_parse_after_error: bool = (false, parse_bool, [TRACKED], "attempt to recover from parse errors (experimental)"), dep_tasks: bool = (false, parse_bool, [UNTRACKED], @@ -1314,10 +1316,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"), query_dep_graph: bool = (false, parse_bool, [UNTRACKED], "enable queries of the dependency graph for regression testing"), - profile_queries: bool = (false, parse_bool, [UNTRACKED], - "trace and profile the queries of the incremental compilation framework"), - profile_queries_and_keys: bool = (false, parse_bool, [UNTRACKED], - "trace and profile the queries and keys of the incremental compilation framework"), no_analysis: bool = (false, parse_bool, [UNTRACKED], "parse and expand the source, but run no analysis"), extra_plugins: Vec = (Vec::new(), parse_list, [TRACKED], @@ -1343,7 +1341,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, mir_opt_level: usize = (1, parse_uint, [TRACKED], "set the MIR optimization level (0-3, default: 1)"), mutable_noalias: Option = (None, parse_opt_bool, [TRACKED], - "emit noalias metadata for mutable references (default: yes on LLVM >= 6)"), + "emit noalias metadata for mutable references (default: no)"), dump_mir: Option = (None, parse_opt_string, [UNTRACKED], "dump MIR state to file. `val` is used to select which passes and functions to dump. For example: @@ -1372,6 +1370,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "describes how to render the `rendered` field of json diagnostics"), unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED], "take the breaks off const evaluation. NOTE: this is unsound"), + suppress_const_validation_back_compat_ice: bool = (false, parse_bool, [TRACKED], + "silence ICE triggered when the new const validator disagrees with the old"), osx_rpath_install_name: bool = (false, parse_bool, [TRACKED], "pass `-install_name @rpath/...` to the macOS linker"), sanitizer: Option = (None, parse_sanitizer, [TRACKED], @@ -1421,8 +1421,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, valid types are any of the types for `--pretty`, as well as: `expanded`, `expanded,identified`, `expanded,hygiene` (with internal representations), - `flowgraph=` (graphviz formatted flowgraph for node), - `flowgraph,unlabelled=` (unlabelled graphviz formatted flowgraph for node), `everybody_loops` (all function bodies replaced with `loop {}`), `hir` (the HIR), `hir,identified`, `hir,typed` (HIR with types for each node), @@ -1469,6 +1467,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "which mangling version to use for symbol names"), binary_dep_depinfo: bool = (false, parse_bool, [TRACKED], "include artifacts (sysroot, crate dependencies) used during compilation in dep-info"), + insert_sideeffect: bool = (false, parse_bool, [TRACKED], + "fix undefined behavior when a thread doesn't eventually make progress \ + (such as entering an empty infinite loop) by inserting llvm.sideeffect"), } pub fn default_lib_output() -> CrateType { @@ -1537,7 +1538,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { ret } -/// Converts the crate cfg! configuration from String to Symbol. +/// Converts the crate `cfg!` configuration from `String` to `Symbol`. /// `rustc_interface::interface::Config` accepts this in the compiler configuration, /// but the symbol interner is not yet set up then, so we must convert it later. pub fn to_crate_config(cfg: FxHashSet<(String, Option)>) -> ast::CrateConfig { @@ -1548,9 +1549,9 @@ pub fn to_crate_config(cfg: FxHashSet<(String, Option)>) -> ast::CrateCo pub fn build_configuration(sess: &Session, mut user_cfg: ast::CrateConfig) -> ast::CrateConfig { // Combine the configuration requested by the session (command line) with - // some default and generated configuration items + // some default and generated configuration items. let default_cfg = default_configuration(sess); - // If the user wants a test runner, then add the test cfg + // If the user wants a test runner, then add the test cfg. if sess.opts.test { user_cfg.insert((sym::test, None)); } @@ -1719,13 +1720,7 @@ pub fn rustc_short_optgroups() -> Vec { static, framework, or dylib (the default).", "[KIND=]NAME", ), - opt::multi_s( - "", - "crate-type", - "Comma separated list of types of crates - for the compiler to emit", - "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]", - ), + make_crate_type_option(), opt::opt_s( "", "crate-name", @@ -1855,13 +1850,22 @@ pub fn rustc_optgroups() -> Vec { opts } -// Convert strings provided as --cfg [cfgspec] into a crate_cfg +struct NullEmitter; + +impl errors::emitter::Emitter for NullEmitter { + fn emit_diagnostic(&mut self, _: &errors::Diagnostic) {} +} + +// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`. pub fn parse_cfgspecs(cfgspecs: Vec) -> FxHashSet<(String, Option)> { syntax::with_default_globals(move || { let cfg = cfgspecs.into_iter().map(|s| { - let sess = parse::ParseSess::new(FilePathMapping::empty()); + + let cm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let handler = Handler::with_emitter(false, None, Box::new(NullEmitter)); + let sess = ParseSess::with_span_handler(handler, cm); let filename = FileName::cfg_spec_source_code(&s); - let mut parser = parse::new_parser_from_source_str(&sess, filename, s.to_string()); + let mut parser = new_parser_from_source_str(&sess, filename, s.to_string()); macro_rules! error {($reason: expr) => { early_error(ErrorOutputType::default(), @@ -1873,11 +1877,11 @@ pub fn parse_cfgspecs(cfgspecs: Vec) -> FxHashSet<(String, Option { error!(r#"expected `key` or `key="value"`"#); } - MetaItemKind::NameValue(lit) if !lit.node.is_str() => { + MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { error!("argument value must be a string"); } MetaItemKind::NameValue(..) | MetaItemKind::Word => { @@ -1921,7 +1925,7 @@ pub fn get_cmd_lint_options(matches: &getopts::Matches, (lint_opts, describe_lints, lint_cap) } -/// Parse the `--color` flag +/// Parses the `--color` flag. pub fn parse_color(matches: &getopts::Matches) -> ColorConfig { match matches.opt_str("color").as_ref().map(|s| &s[..]) { Some("auto") => ColorConfig::Auto, @@ -1933,7 +1937,7 @@ pub fn parse_color(matches: &getopts::Matches) -> ColorConfig { Some(arg) => early_error( ErrorOutputType::default(), &format!( - "argument for --color must be auto, \ + "argument for `--color` must be auto, \ always or never (instead was `{}`)", arg ), @@ -1978,16 +1982,16 @@ pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) (json_rendered(json_color), json_artifact_notifications) } -/// Parse the `--error-format` flag +/// Parses the `--error-format` flag. pub fn parse_error_format( matches: &getopts::Matches, color: ColorConfig, json_rendered: HumanReadableErrorType, ) -> ErrorOutputType { - // We need the opts_present check because the driver will send us Matches + // We need the `opts_present` check because the driver will send us Matches // with only stable options if no unstable options are used. Since error-format - // is unstable, it will not be present. We have to use opts_present not - // opt_present because the latter will panic. + // is unstable, it will not be present. We have to use `opts_present` not + // `opt_present` because the latter will panic. let error_format = if matches.opts_present(&["error-format".to_owned()]) { match matches.opt_str("error-format").as_ref().map(|s| &s[..]) { None | @@ -2002,7 +2006,7 @@ pub fn parse_error_format( Some(arg) => early_error( ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)), &format!( - "argument for --error-format must be `human`, `json` or \ + "argument for `--error-format` must be `human`, `json` or \ `short` (instead was `{}`)", arg ), @@ -2041,7 +2045,7 @@ pub fn build_session_options_and_crate_config( early_error( ErrorOutputType::default(), &format!( - "argument for --edition must be one of: \ + "argument for `--edition` must be one of: \ {}. (instead was `{}`)", EDITION_NAME_LIST, arg @@ -2055,7 +2059,7 @@ pub fn build_session_options_and_crate_config( early_error( ErrorOutputType::default(), &format!( - "Edition {} is unstable and only \ + "edition {} is unstable and only \ available for nightly builds of rustc.", edition, ) @@ -2079,14 +2083,14 @@ pub fn build_session_options_and_crate_config( if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format { early_error( ErrorOutputType::Json { pretty: false, json_rendered }, - "--error-format=pretty-json is unstable", + "`--error-format=pretty-json` is unstable", ); } if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) = error_format { early_error( ErrorOutputType::Json { pretty: false, json_rendered }, - "--error-format=human-annotate-rs is unstable", + "`--error-format=human-annotate-rs` is unstable", ); } } @@ -2120,7 +2124,7 @@ pub fn build_session_options_and_crate_config( let mut codegen_units = cg.codegen_units; let mut disable_thinlto = false; - // Issue #30063: if user requests llvm-related output to one + // Issue #30063: if user requests LLVM-related output to one // particular path, disable codegen-units. let incompatible: Vec<_> = output_types .iter() @@ -2136,8 +2140,8 @@ pub fn build_session_options_and_crate_config( early_warn( error_format, &format!( - "--emit={} with -o incompatible with \ - -C codegen-units=N for N > 1", + "`--emit={}` with `-o` incompatible with \ + `-C codegen-units=N` for N > 1", ot ), ); @@ -2154,24 +2158,24 @@ pub fn build_session_options_and_crate_config( } } - if debugging_opts.threads == Some(0) { + if debugging_opts.threads == 0 { early_error( error_format, - "Value for threads must be a positive nonzero integer", + "value for threads must be a positive non-zero integer", ); } - if debugging_opts.threads.unwrap_or(1) > 1 && debugging_opts.fuel.is_some() { + if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() { early_error( error_format, - "Optimization fuel is incompatible with multiple threads", + "optimization fuel is incompatible with multiple threads", ); } if codegen_units == Some(0) { early_error( error_format, - "Value for codegen units must be a positive nonzero integer", + "value for codegen units must be a positive non-zero integer", ); } @@ -2418,10 +2422,10 @@ pub fn build_session_options_and_crate_config( ) } - // We start out with a Vec<(Option, bool)>>, - // and later convert it into a BTreeSet<(Option, bool)> + // We start out with a `Vec<(Option, bool)>>`, + // and later convert it into a `BTreeSet<(Option, bool)>` // This allows to modify entries in-place to set their correct - // 'public' value + // 'public' value. let mut externs: BTreeMap = BTreeMap::new(); for (arg, private) in matches.opt_strs("extern").into_iter().map(|v| (v, false)) .chain(matches.opt_strs("extern-private").into_iter().map(|v| (v, true))) { @@ -2506,6 +2510,16 @@ pub fn build_session_options_and_crate_config( ) } +pub fn make_crate_type_option() -> RustcOptGroup { + opt::multi_s( + "", + "crate-type", + "Comma separated list of types of crates + for the compiler to emit", + "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]", + ) +} + pub fn parse_crate_types_from_list(list_list: Vec) -> Result, String> { let mut crate_types: Vec = Vec::new(); for unparsed_crate_type in &list_list { @@ -2610,15 +2624,15 @@ impl fmt::Display for CrateType { /// The values of all command-line arguments that are relevant for dependency /// tracking are hashed into a single value that determines whether the /// incremental compilation cache can be re-used or not. This hashing is done -/// via the DepTrackingHash trait defined below, since the standard Hash -/// implementation might not be suitable (e.g., arguments are stored in a Vec, +/// via the `DepTrackingHash` trait defined below, since the standard `Hash` +/// implementation might not be suitable (e.g., arguments are stored in a `Vec`, /// the hash of which is order dependent, but we might not want the order of /// arguments to make a difference for the hash). /// -/// However, since the value provided by Hash::hash often *is* suitable, +/// However, since the value provided by `Hash::hash` often *is* suitable, /// especially for primitive types, there is the -/// impl_dep_tracking_hash_via_hash!() macro that allows to simply reuse the -/// Hash implementation for DepTrackingHash. It's important though that +/// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the +/// `Hash` implementation for `DepTrackingHash`. It's important though that /// we have an opt-in scheme here, so one is hopefully forced to think about /// how the hash should be calculated when adding a new command-line argument. mod dep_tracking { @@ -2631,9 +2645,9 @@ mod dep_tracking { use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath, SymbolManglingVersion}; - use syntax::feature_gate::UnstableFeatures; use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple}; use syntax::edition::Edition; + use syntax::feature_gate::UnstableFeatures; pub trait DepTrackingHash { fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType); diff --git a/src/librustc/session/config/tests.rs b/src/librustc/session/config/tests.rs index 3d6312548a47b..c117418f63699 100644 --- a/src/librustc/session/config/tests.rs +++ b/src/librustc/session/config/tests.rs @@ -87,7 +87,7 @@ fn test_can_print_warnings() { let registry = errors::registry::Registry::new(&[]); let (sessopts, _) = build_session_options_and_crate_config(&matches); let sess = build_session(sessopts, None, registry); - assert!(!sess.diagnostic().flags.can_emit_warnings); + assert!(!sess.diagnostic().can_emit_warnings()); }); syntax::with_default_globals(|| { @@ -97,7 +97,7 @@ fn test_can_print_warnings() { let registry = errors::registry::Registry::new(&[]); let (sessopts, _) = build_session_options_and_crate_config(&matches); let sess = build_session(sessopts, None, registry); - assert!(sess.diagnostic().flags.can_emit_warnings); + assert!(sess.diagnostic().can_emit_warnings()); }); syntax::with_default_globals(|| { @@ -105,7 +105,7 @@ fn test_can_print_warnings() { let registry = errors::registry::Registry::new(&[]); let (sessopts, _) = build_session_options_and_crate_config(&matches); let sess = build_session(sessopts, None, registry); - assert!(sess.diagnostic().flags.can_emit_warnings); + assert!(sess.diagnostic().can_emit_warnings()); }); } @@ -589,14 +589,6 @@ fn test_debugging_options_tracking_hash() { assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.save_analysis = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); - opts.debugging_opts.flowgraph_print_loans = true; - assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); - opts.debugging_opts.flowgraph_print_moves = true; - assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); - opts.debugging_opts.flowgraph_print_assigns = true; - assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); - opts.debugging_opts.flowgraph_print_all = true; - assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.print_region_graph = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.parse_only = true; diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 61dac678912df..9d60221fa3d75 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -7,12 +7,10 @@ use rustc_data_structures::fingerprint::Fingerprint; use crate::lint; use crate::lint::builtin::BuiltinLintDiagnostics; -use crate::middle::dependency_format; use crate::session::config::{OutputType, PrintRequest, SwitchWithOptPath}; use crate::session::search_paths::{PathKind, SearchPath}; use crate::util::nodemap::{FxHashMap, FxHashSet}; use crate::util::common::{duration_to_secs_str, ErrorReported}; -use crate::util::common::ProfileQueriesMsg; use rustc_data_structures::base_n; use rustc_data_structures::sync::{ @@ -33,7 +31,7 @@ use syntax::source_map; use syntax::parse::{self, ParseSess}; use syntax::symbol::Symbol; use syntax_pos::{MultiSpan, Span}; -use crate::util::profiling::SelfProfiler; +use crate::util::profiling::{SelfProfiler, SelfProfilerRef}; use rustc_target::spec::{PanicStrategy, RelroLevel, Target, TargetTriple}; use rustc_data_structures::flock; @@ -47,7 +45,7 @@ use std::fmt; use std::io::Write; use std::path::PathBuf; use std::time::Duration; -use std::sync::{Arc, mpsc}; +use std::sync::Arc; mod code_stats; pub mod config; @@ -79,24 +77,23 @@ pub struct Session { /// if the value stored here has been affected by path remapping. pub working_dir: (PathBuf, bool), - // FIXME: lint_store and buffered_lints are not thread-safe, - // but are only used in a single thread + // FIXME: `lint_store` and `buffered_lints` are not thread-safe, + // but are only used in a single thread. pub lint_store: RwLock, pub buffered_lints: Lock>, - /// Set of (DiagnosticId, Option, message) tuples tracking + /// Set of `(DiagnosticId, Option, message)` tuples tracking /// (sub)diagnostics that have been set once, but should not be set again, /// in order to avoid redundantly verbose output (Issue #24690, #44953). pub one_time_diagnostics: Lock, String)>>, pub plugin_llvm_passes: OneThread>>, pub plugin_attributes: Lock>, pub crate_types: Once>, - pub dependency_formats: Once, - /// The crate_disambiguator is constructed out of all the `-C metadata` + /// The `crate_disambiguator` is constructed out of all the `-C metadata` /// arguments passed to the compiler. Its value together with the crate-name /// forms a unique global identifier for the crate. It is used to allow /// multiple crates with the same name to coexist. See the - /// rustc_codegen_llvm::back::symbol_names module for more information. + /// `rustc_codegen_llvm::back::symbol_names` module for more information. pub crate_disambiguator: Once, features: Once, @@ -111,7 +108,7 @@ pub struct Session { /// The maximum number of stackframes allowed in const eval. pub const_eval_stack_frame_limit: usize, - /// The metadata::creader module may inject an allocator/panic_runtime + /// The `metadata::creader` module may inject an allocator/`panic_runtime` /// dependency if it didn't already find one, and this tracks what was /// injected. pub allocator_kind: Once>, @@ -127,11 +124,8 @@ pub struct Session { /// `-Zquery-dep-graph` is specified. pub cgu_reuse_tracker: CguReuseTracker, - /// Used by `-Z profile-queries` in `util::common`. - pub profile_channel: Lock>>, - - /// Used by -Z self-profile - pub self_profiling: Option>, + /// Used by `-Z self-profile`. + pub prof: SelfProfilerRef, /// Some measurements that are being gathered during compilation. pub perf_stats: PerfStats, @@ -187,16 +181,16 @@ pub struct PerfStats { pub normalize_projection_ty: AtomicUsize, } -/// Enum to support dispatch of one-time diagnostics (in Session.diag_once) +/// Enum to support dispatch of one-time diagnostics (in `Session.diag_once`). enum DiagnosticBuilderMethod { Note, SpanNote, SpanSuggestion(String), // suggestion - // add more variants as needed to support one-time diagnostics + // Add more variants as needed to support one-time diagnostics. } -/// Diagnostic message ID—used by `Session.one_time_diagnostics` to avoid -/// emitting the same message more than once +/// Diagnostic message ID, used by `Session.one_time_diagnostics` to avoid +/// emitting the same message more than once. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum DiagnosticMessageId { ErrorId(u16), // EXXXX error code as integer @@ -321,6 +315,7 @@ impl Session { } pub fn compile_status(&self) -> Result<(), ErrorReported> { if self.has_errors() { + self.diagnostic().emit_stashed_diagnostics(); Err(ErrorReported) } else { Ok(()) @@ -365,12 +360,6 @@ impl Session { pub fn span_note_without_error>(&self, sp: S, msg: &str) { self.diagnostic().span_note_without_error(sp, msg) } - pub fn span_unimpl>(&self, sp: S, msg: &str) -> ! { - self.diagnostic().span_unimpl(sp, msg) - } - pub fn unimpl(&self, msg: &str) -> ! { - self.diagnostic().unimpl(msg) - } pub fn buffer_lint>( &self, @@ -408,7 +397,7 @@ impl Session { Some(next) => { self.next_node_id.set(ast::NodeId::from_usize(next)); } - None => bug!("Input too large, ran out of node ids!"), + None => bug!("input too large; ran out of node-IDs!"), } id @@ -440,11 +429,11 @@ impl Session { diag_builder.note(message); } DiagnosticBuilderMethod::SpanNote => { - let span = span_maybe.expect("span_note needs a span"); + let span = span_maybe.expect("`span_note` needs a span"); diag_builder.span_note(span, message); } DiagnosticBuilderMethod::SpanSuggestion(suggestion) => { - let span = span_maybe.expect("span_suggestion_* needs a span"); + let span = span_maybe.expect("`span_suggestion_*` needs a span"); diag_builder.span_suggestion( span, message, @@ -516,13 +505,6 @@ impl Session { pub fn time_extended(&self) -> bool { self.opts.debugging_opts.time_passes } - pub fn profile_queries(&self) -> bool { - self.opts.debugging_opts.profile_queries - || self.opts.debugging_opts.profile_queries_and_keys - } - pub fn profile_queries_and_keys(&self) -> bool { - self.opts.debugging_opts.profile_queries_and_keys - } pub fn instrument_mcount(&self) -> bool { self.opts.debugging_opts.instrument_mcount } @@ -688,7 +670,7 @@ impl Session { pub fn must_not_eliminate_frame_pointers(&self) -> bool { // "mcount" function relies on stack pointer. - // See https://sourceware.org/binutils/docs/gprof/Implementation.html + // See . if self.instrument_mcount() { true } else if let Some(x) = self.opts.cg.force_frame_pointers { @@ -699,7 +681,7 @@ impl Session { } /// Returns the symbol name for the registrar function, - /// given the crate Svh and the function DefIndex. + /// given the crate `Svh` and the function `DefIndex`. pub fn generate_plugin_registrar_symbol(&self, disambiguator: CrateDisambiguator) -> String { format!( "__rustc_plugin_registrar_{}__", @@ -719,7 +701,7 @@ impl Session { &self.sysroot, self.opts.target_triple.triple(), &self.opts.search_paths, - // target_tlib_path==None means it's the same as host_tlib_path. + // `target_tlib_path == None` means it's the same as `host_tlib_path`. self.target_tlib_path.as_ref().unwrap_or(&self.host_tlib_path), kind, ) @@ -779,12 +761,12 @@ impl Session { if let IncrCompSession::Active { .. } = *incr_comp_session { } else { bug!( - "Trying to finalize IncrCompSession `{:?}`", + "trying to finalize `IncrCompSession` `{:?}`", *incr_comp_session - ) + ); } - // Note: This will also drop the lock file, thus unlocking the directory + // Note: this will also drop the lock file, thus unlocking the directory. *incr_comp_session = IncrCompSession::Finalized { session_directory: new_directory_path, }; @@ -800,13 +782,15 @@ impl Session { } => session_directory.clone(), IncrCompSession::InvalidBecauseOfErrors { .. } => return, _ => bug!( - "Trying to invalidate IncrCompSession `{:?}`", + "trying to invalidate `IncrCompSession` `{:?}`", *incr_comp_session ), }; - // Note: This will also drop the lock file, thus unlocking the directory - *incr_comp_session = IncrCompSession::InvalidBecauseOfErrors { session_directory }; + // Note: this will also drop the lock file, thus unlocking the directory. + *incr_comp_session = IncrCompSession::InvalidBecauseOfErrors { + session_directory, + }; } pub fn incr_comp_session_dir(&self) -> cell::Ref<'_, PathBuf> { @@ -815,8 +799,8 @@ impl Session { incr_comp_session, |incr_comp_session| match *incr_comp_session { IncrCompSession::NotInitialized => bug!( - "Trying to get session directory from IncrCompSession `{:?}`", - *incr_comp_session + "trying to get session directory from `IncrCompSession`: {:?}", + *incr_comp_session, ), IncrCompSession::Active { ref session_directory, @@ -840,24 +824,6 @@ impl Session { } } - #[inline(never)] - #[cold] - fn profiler_active ()>(&self, f: F) { - match &self.self_profiling { - None => bug!("profiler_active() called but there was no profiler active"), - Some(profiler) => { - f(&profiler); - } - } - } - - #[inline(always)] - pub fn profiler ()>(&self, f: F) { - if unlikely!(self.self_profiling.is_some()) { - self.profiler_active(f) - } - } - pub fn print_perf_stats(&self) { println!( "Total time spent computing symbol hashes: {}", @@ -901,16 +867,10 @@ impl Session { ret } - /// Returns the number of query threads that should be used for this - /// compilation - pub fn threads_from_count(query_threads: Option) -> usize { - query_threads.unwrap_or(::num_cpus::get()) - } - /// Returns the number of query threads that should be used for this /// compilation pub fn threads(&self) -> usize { - Self::threads_from_count(self.opts.debugging_opts.threads) + self.opts.debugging_opts.threads } /// Returns the number of codegen units that should be used for this @@ -1038,6 +998,7 @@ fn default_emitter( source_map: &Lrc, emitter_dest: Option>, ) -> Box { + let external_macro_backtrace = sopts.debugging_opts.external_macro_backtrace; match (sopts.error_format, emitter_dest) { (config::ErrorOutputType::HumanReadable(kind), dst) => { let (short, color_config) = kind.unzip(); @@ -1046,6 +1007,7 @@ fn default_emitter( let emitter = AnnotateSnippetEmitterWriter::new( Some(source_map.clone()), short, + external_macro_backtrace, ); Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing)) } else { @@ -1055,6 +1017,8 @@ fn default_emitter( Some(source_map.clone()), short, sopts.debugging_opts.teach, + sopts.debugging_opts.terminal_width, + external_macro_backtrace, ), Some(dst) => EmitterWriter::new( dst, @@ -1062,6 +1026,8 @@ fn default_emitter( short, false, // no teach messages when writing to a buffer false, // no colors when writing to a buffer + None, // no terminal width + external_macro_backtrace, ), }; Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing)) @@ -1073,6 +1039,7 @@ fn default_emitter( source_map.clone(), pretty, json_rendered, + external_macro_backtrace, ).ui_testing(sopts.debugging_opts.ui_testing), ), (config::ErrorOutputType::Json { pretty, json_rendered }, Some(dst)) => Box::new( @@ -1082,6 +1049,7 @@ fn default_emitter( source_map.clone(), pretty, json_rendered, + external_macro_backtrace, ).ui_testing(sopts.debugging_opts.ui_testing), ), } @@ -1183,7 +1151,10 @@ fn build_session_( ); let target_cfg = config::build_target_config(&sopts, &span_diagnostic); - let p_s = parse::ParseSess::with_span_handler(span_diagnostic, source_map); + let parse_sess = parse::ParseSess::with_span_handler( + span_diagnostic, + source_map, + ); let sysroot = match &sopts.maybe_sysroot { Some(sysroot) => sysroot.clone(), None => filesearch::get_or_default_sysroot(), @@ -1212,7 +1183,7 @@ fn build_session_( let print_fuel = AtomicU64::new(0); let working_dir = env::current_dir().unwrap_or_else(|e| - p_s.span_diagnostic + parse_sess.span_diagnostic .fatal(&format!("Current directory is invalid: {}", e)) .raise() ); @@ -1230,7 +1201,7 @@ fn build_session_( opts: sopts, host_tlib_path, target_tlib_path, - parse_sess: p_s, + parse_sess, sysroot, local_crate_source_file, working_dir, @@ -1240,7 +1211,6 @@ fn build_session_( plugin_llvm_passes: OneThread::new(RefCell::new(Vec::new())), plugin_attributes: Lock::new(Vec::new()), crate_types: Once::new(), - dependency_formats: Once::new(), crate_disambiguator: Once::new(), features: Once::new(), recursion_limit: Once::new(), @@ -1252,8 +1222,7 @@ fn build_session_( imported_macro_spans: OneThread::new(RefCell::new(FxHashMap::default())), incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)), cgu_reuse_tracker, - self_profiling: self_profiler, - profile_channel: Lock::new(None), + prof: SelfProfilerRef::new(self_profiler), perf_stats: PerfStats { symbol_hash_time: Lock::new(Duration::from_secs(0)), decode_def_path_tables_time: Lock::new(Duration::from_secs(0)), @@ -1375,13 +1344,13 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { let emitter: Box = match output { config::ErrorOutputType::HumanReadable(kind) => { let (short, color_config) = kind.unzip(); - Box::new(EmitterWriter::stderr(color_config, None, short, false)) + Box::new(EmitterWriter::stderr(color_config, None, short, false, None, false)) } config::ErrorOutputType::Json { pretty, json_rendered } => - Box::new(JsonEmitter::basic(pretty, json_rendered)), + Box::new(JsonEmitter::basic(pretty, json_rendered, false)), }; let handler = errors::Handler::with_emitter(true, None, emitter); - handler.emit(&MultiSpan::new(), msg, errors::Level::Fatal); + handler.struct_fatal(msg).emit(); errors::FatalError.raise(); } @@ -1389,13 +1358,13 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) { let emitter: Box = match output { config::ErrorOutputType::HumanReadable(kind) => { let (short, color_config) = kind.unzip(); - Box::new(EmitterWriter::stderr(color_config, None, short, false)) + Box::new(EmitterWriter::stderr(color_config, None, short, false, None, false)) } config::ErrorOutputType::Json { pretty, json_rendered } => - Box::new(JsonEmitter::basic(pretty, json_rendered)), + Box::new(JsonEmitter::basic(pretty, json_rendered, false)), }; let handler = errors::Handler::with_emitter(true, None, emitter); - handler.emit(&MultiSpan::new(), msg, errors::Level::Warning); + handler.struct_warn(msg).emit(); } pub type CompileResult = Result<(), ErrorReported>; diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index d89cf8eb3e843..9faf58aee6f92 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -321,7 +321,7 @@ impl AutoTraitFinder<'tcx> { match vtable { Vtable::VtableImpl(VtableImplData { impl_def_id, .. }) => { // Blame tidy for the weird bracket placement - if infcx.tcx.impl_polarity(*impl_def_id) == hir::ImplPolarity::Negative + if infcx.tcx.impl_polarity(*impl_def_id) == ty::ImplPolarity::Negative { debug!("evaluate_nested_obligations: Found explicit negative impl\ {:?}, bailing out", impl_def_id); @@ -601,7 +601,7 @@ impl AutoTraitFinder<'tcx> { } pub fn is_of_param(&self, ty: Ty<'_>) -> bool { - return match ty.sty { + return match ty.kind { ty::Param(_) => true, ty::Projection(p) => self.is_of_param(p.self_ty()), _ => false, @@ -609,7 +609,7 @@ impl AutoTraitFinder<'tcx> { } fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool { - match p.ty().skip_binder().sty { + match p.ty().skip_binder().kind { ty::Projection(proj) if proj == p.skip_binder().projection_ty => { true }, diff --git a/src/librustc/traits/chalk_fulfill.rs b/src/librustc/traits/chalk_fulfill.rs index 0c7c94b684a9f..d9e83df7ddda6 100644 --- a/src/librustc/traits/chalk_fulfill.rs +++ b/src/librustc/traits/chalk_fulfill.rs @@ -81,6 +81,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { .map(|obligation| FulfillmentError { obligation: obligation.goal.clone(), code: FulfillmentErrorCode::CodeAmbiguity, + points_at_arg_span: false, }) .collect(); Err(errors) @@ -107,7 +108,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { goal: obligation.goal.predicate, }, &mut orig_values); - match infcx.tcx.global_tcx().evaluate_goal(canonical_goal) { + match infcx.tcx.evaluate_goal(canonical_goal) { Ok(response) => { if response.is_proven() { making_progress = true; @@ -129,6 +130,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { code: FulfillmentErrorCode::CodeSelectionError( SelectionError::Unimplemented ), + points_at_arg_span: false, }), } } else { @@ -142,6 +144,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { code: FulfillmentErrorCode::CodeSelectionError( SelectionError::Unimplemented ), + points_at_arg_span: false, }) } } diff --git a/src/librustc/traits/codegen/mod.rs b/src/librustc/traits/codegen/mod.rs index 97fb430a3e051..9dff699deb8af 100644 --- a/src/librustc/traits/codegen/mod.rs +++ b/src/librustc/traits/codegen/mod.rs @@ -3,12 +3,10 @@ // seems likely that they should eventually be merged into more // general routines. -use crate::dep_graph::{DepKind, DepTrackingMapConfig}; -use std::marker::PhantomData; use crate::infer::InferCtxt; use crate::traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, TraitEngine, Vtable}; -use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::{self, TyCtxt}; use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::fold::TypeFoldable; @@ -100,33 +98,8 @@ impl<'tcx> TyCtxt<'tcx> { } } -// Implement DepTrackingMapConfig for `trait_cache` -pub struct TraitSelectionCache<'tcx> { - data: PhantomData<&'tcx ()> -} - -impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> { - type Key = (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>); - type Value = Vtable<'tcx, ()>; - fn to_dep_kind() -> DepKind { - DepKind::TraitSelect - } -} - // # Global Cache -pub struct ProjectionCache<'tcx> { - data: PhantomData<&'tcx ()>, -} - -impl<'tcx> DepTrackingMapConfig for ProjectionCache<'tcx> { - type Key = Ty<'tcx>; - type Value = Ty<'tcx>; - fn to_dep_kind() -> DepKind { - DepKind::TraitSelect - } -} - impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Finishes processes any obligations that remain in the /// fulfillment context, and then returns the result with all type diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index b6f0addd77107..4696d4da58ec0 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -378,12 +378,20 @@ fn orphan_check_trait_ref<'tcx>( // Let Ti be the first such type. // - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti) // - for input_ty in trait_ref.input_types() { + fn uncover_fundamental_ty(ty: Ty<'_>) -> Vec> { + if fundamental_ty(ty) { + ty.walk_shallow().flat_map(|ty| uncover_fundamental_ty(ty)).collect() + } else { + vec![ty] + } + } + + for input_ty in trait_ref.input_types().flat_map(uncover_fundamental_ty) { debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty); if ty_is_local(tcx, input_ty, in_crate) { debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty); return Ok(()); - } else if let ty::Param(_) = input_ty.sty { + } else if let ty::Param(_) = input_ty.kind { debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty); return Err(OrphanCheckErr::UncoveredTy(input_ty)) } @@ -432,7 +440,7 @@ fn orphan_check_trait_ref<'tcx>( } fn uncovered_tys<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, in_crate: InCrate) -> Vec> { - if ty_is_local_constructor(ty, in_crate) { + if ty_is_local_constructor(tcx, ty, in_crate) { vec![] } else if fundamental_ty(ty) { ty.walk_shallow() @@ -444,19 +452,19 @@ fn uncovered_tys<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, in_crate: InCrate) -> Vec< } fn is_possibly_remote_type(ty: Ty<'_>, _in_crate: InCrate) -> bool { - match ty.sty { + match ty.kind { ty::Projection(..) | ty::Param(..) => true, _ => false, } } fn ty_is_local(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool { - ty_is_local_constructor(ty, in_crate) || + ty_is_local_constructor(tcx, ty, in_crate) || fundamental_ty(ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, in_crate)) } fn fundamental_ty(ty: Ty<'_>) -> bool { - match ty.sty { + match ty.kind { ty::Ref(..) => true, ty::Adt(def, _) => def.is_fundamental(), _ => false @@ -472,10 +480,10 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool { } } -fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool { +fn ty_is_local_constructor(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool { debug!("ty_is_local_constructor({:?})", ty); - match ty.sty { + match ty.kind { ty::Bool | ty::Char | ty::Int(..) | @@ -504,6 +512,15 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool { ty::Adt(def, _) => def_id_is_local(def.did, in_crate), ty::Foreign(did) => def_id_is_local(did, in_crate), + ty::Opaque(did, _) => { + // Check the underlying type that this opaque + // type resolves to. + // This recursion will eventually terminate, + // since we've already managed to successfully + // resolve all opaque types by this point + let real_ty = tcx.type_of(did); + ty_is_local_constructor(tcx, real_ty, in_crate) + } ty::Dynamic(ref tt, ..) => { if let Some(principal) = tt.principal() { @@ -518,8 +535,7 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool { ty::UnnormalizedProjection(..) | ty::Closure(..) | ty::Generator(..) | - ty::GeneratorWitness(..) | - ty::Opaque(..) => { + ty::GeneratorWitness(..) => { bug!("ty_is_local invoked on unexpected type: {:?}", ty) } } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 83bd5c56040e1..9eb91569ed5c4 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1,20 +1,21 @@ use super::{ + ConstEvalFailure, + EvaluationResult, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, + ObjectSafetyViolation, Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, OutputTypeParameterMismatch, - TraitNotObjectSafe, - ConstEvalFailure, + Overflow, PredicateObligation, SelectionContext, SelectionError, - ObjectSafetyViolation, - Overflow, + TraitNotObjectSafe, }; use crate::hir; @@ -23,7 +24,7 @@ use crate::hir::def_id::DefId; use crate::infer::{self, InferCtxt}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::session::DiagnosticMessageId; -use crate::ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use crate::ty::GenericParamDefKind; use crate::ty::error::ExpectedFound; use crate::ty::fast_reject; @@ -32,17 +33,19 @@ use crate::ty::subst::Subst; use crate::ty::SubtypePredicate; use crate::util::nodemap::{FxHashMap, FxHashSet}; -use errors::{Applicability, DiagnosticBuilder}; +use errors::{Applicability, DiagnosticBuilder, pluralise}; use std::fmt; use syntax::ast; -use syntax::symbol::sym; -use syntax_pos::{DUMMY_SP, Span, ExpnInfo, ExpnKind}; +use syntax::symbol::{sym, kw}; +use syntax_pos::{DUMMY_SP, Span, ExpnKind, MultiSpan}; impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn report_fulfillment_errors(&self, - errors: &[FulfillmentError<'tcx>], - body_id: Option, - fallback_has_occurred: bool) { + pub fn report_fulfillment_errors( + &self, + errors: &[FulfillmentError<'tcx>], + body_id: Option, + fallback_has_occurred: bool, + ) { #[derive(Debug)] struct ErrorDescriptor<'tcx> { predicate: ty::Predicate<'tcx>, @@ -61,9 +64,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // We want to ignore desugarings here: spans are equivalent even // if one is the result of a desugaring and the other is not. let mut span = error.obligation.cause.span; - if let Some(ExpnInfo { kind: ExpnKind::Desugaring(_), def_site, .. }) - = span.ctxt().outer_expn_info() { - span = def_site; + let expn_data = span.ctxt().outer_expn_data(); + if let ExpnKind::Desugaring(_) = expn_data.kind { + span = expn_data.call_site; } error_map.entry(span).or_default().push( @@ -118,11 +121,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // returns if `cond` not occurring implies that `error` does not occur - i.e., that // `error` occurring implies that `cond` occurs. - fn error_implies(&self, - cond: &ty::Predicate<'tcx>, - error: &ty::Predicate<'tcx>) - -> bool - { + fn error_implies( + &self, + cond: &ty::Predicate<'tcx>, + error: &ty::Predicate<'tcx>, + ) -> bool { if cond == error { return true } @@ -154,13 +157,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { false } - fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>, - body_id: Option, - fallback_has_occurred: bool) { + fn report_fulfillment_error( + &self, + error: &FulfillmentError<'tcx>, + body_id: Option, + fallback_has_occurred: bool, + ) { debug!("report_fulfillment_errors({:?})", error); match error.code { - FulfillmentErrorCode::CodeSelectionError(ref e) => { - self.report_selection_error(&error.obligation, e, fallback_has_occurred); + FulfillmentErrorCode::CodeSelectionError(ref selection_error) => { + self.report_selection_error( + &error.obligation, + selection_error, + fallback_has_occurred, + error.points_at_arg_span, + ); } FulfillmentErrorCode::CodeProjectionError(ref e) => { self.report_projection_error(&error.obligation, e); @@ -169,19 +180,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.maybe_report_ambiguity(&error.obligation, body_id); } FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => { - self.report_mismatched_types(&error.obligation.cause, - expected_found.expected, - expected_found.found, - err.clone()) - .emit(); + self.report_mismatched_types( + &error.obligation.cause, + expected_found.expected, + expected_found.found, + err.clone(), + ).emit(); } } } - fn report_projection_error(&self, - obligation: &PredicateObligation<'tcx>, - error: &MismatchedProjectionTypes<'tcx>) - { + fn report_projection_error( + &self, + obligation: &PredicateObligation<'tcx>, + error: &MismatchedProjectionTypes<'tcx>, + ) { let predicate = self.resolve_vars_if_possible(&obligation.predicate); @@ -245,7 +258,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// returns the fuzzy category of a given type, or None /// if the type can be equated to any type. fn type_category(t: Ty<'_>) -> Option { - match t.sty { + match t.kind { ty::Bool => Some(0), ty::Char => Some(1), ty::Str => Some(2), @@ -275,7 +288,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } match (type_category(a), type_category(b)) { - (Some(cat_a), Some(cat_b)) => match (&a.sty, &b.sty) { + (Some(cat_a), Some(cat_b)) => match (&a.kind, &b.kind) { (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => def_a == def_b, _ => cat_a == cat_b }, @@ -406,7 +419,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { flags.push((sym::_Self, Some("{integral}".to_owned()))); } - if let ty::Array(aty, len) = self_ty.sty { + if let ty::Array(aty, len) = self_ty.kind { flags.push((sym::_Self, Some("[]".to_owned()))); flags.push((sym::_Self, Some(format!("[{}]", aty)))); if let Some(def) = aty.ty_adt_def() { @@ -440,21 +453,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - fn find_similar_impl_candidates(&self, - trait_ref: ty::PolyTraitRef<'tcx>) - -> Vec> - { - let simp = fast_reject::simplify_type(self.tcx, - trait_ref.skip_binder().self_ty(), - true); + fn find_similar_impl_candidates( + &self, + trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Vec> { + let simp = fast_reject::simplify_type(self.tcx, trait_ref.skip_binder().self_ty(), true); let all_impls = self.tcx.all_impls(trait_ref.def_id()); match simp { Some(simp) => all_impls.iter().filter_map(|&def_id| { let imp = self.tcx.impl_trait_ref(def_id).unwrap(); - let imp_simp = fast_reject::simplify_type(self.tcx, - imp.self_ty(), - true); + let imp_simp = fast_reject::simplify_type(self.tcx, imp.self_ty(), true); if let Some(imp_simp) = imp_simp { if simp != imp_simp { return None @@ -469,10 +478,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - fn report_similar_impl_candidates(&self, - impl_candidates: Vec>, - err: &mut DiagnosticBuilder<'_>) - { + fn report_similar_impl_candidates( + &self, + impl_candidates: Vec>, + err: &mut DiagnosticBuilder<'_>, + ) { if impl_candidates.is_empty() { return; } @@ -484,7 +494,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 4 }; - let normalize = |candidate| self.tcx.global_tcx().infer_ctxt().enter(|ref infcx| { + let normalize = |candidate| self.tcx.infer_ctxt().enter(|ref infcx| { let normalized = infcx .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) .normalize(candidate) @@ -537,7 +547,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.suggest_new_overflow_limit(&mut err); } - self.note_obligation_cause(&mut err, obligation); + self.note_obligation_cause_code(&mut err, &obligation.predicate, &obligation.cause.code, + &mut vec![]); err.emit(); self.tcx.sess.abort_if_errors(); @@ -602,6 +613,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { obligation: &PredicateObligation<'tcx>, error: &SelectionError<'tcx>, fallback_has_occurred: bool, + points_at_arg: bool, ) { let span = obligation.cause.span; @@ -657,19 +669,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span, E0277, "{}", - message.unwrap_or_else(|| - format!("the trait bound `{}` is not satisfied{}", - trait_ref.to_predicate(), post_message) - )); + message.unwrap_or_else(|| format!( + "the trait bound `{}` is not satisfied{}", + trait_ref.to_predicate(), + post_message, + ))); let explanation = if obligation.cause.code == ObligationCauseCode::MainFunctionType { "consider using `()`, or a `Result`".to_owned() } else { - format!("{}the trait `{}` is not implemented for `{}`", - pre_message, - trait_ref, - trait_ref.self_ty()) + format!( + "{}the trait `{}` is not implemented for `{}`", + pre_message, + trait_ref, + trait_ref.self_ty(), + ) }; if let Some(ref s) = label { @@ -686,6 +701,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err); + self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg); self.suggest_remove_reference(&obligation, &mut err, &trait_ref); self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref); @@ -701,10 +717,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // which is somewhat confusing. err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate())); - } else if !have_alt_message { - // Can't show anything else useful, try to find similar impls. - let impl_candidates = self.find_similar_impl_candidates(trait_ref); - self.report_similar_impl_candidates(impl_candidates, &mut err); + } else { + if !have_alt_message { + // Can't show anything else useful, try to find similar impls. + let impl_candidates = self.find_similar_impl_candidates(trait_ref); + self.report_similar_impl_candidates(impl_candidates, &mut err); + } + self.suggest_change_mut( + &obligation, + &mut err, + &trait_ref, + points_at_arg, + ); } // If this error is due to `!: Trait` not implemented but `(): Trait` is @@ -765,8 +789,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } ty::Predicate::ObjectSafe(trait_def_id) => { - let violations = self.tcx.global_tcx() - .object_safety_violations(trait_def_id); + let violations = self.tcx.object_safety_violations(trait_def_id); if let Some(err) = self.tcx.report_object_safety_error( span, trait_def_id, @@ -858,7 +881,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let found_trait_ty = found_trait_ref.self_ty(); - let found_did = match found_trait_ty.sty { + let found_did = match found_trait_ty.kind { ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) => Some(did), ty::Adt(def, _) => Some(def.did), _ => None, @@ -868,13 +891,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tcx.hir().span_if_local(did) ).map(|sp| self.tcx.sess.source_map().def_span(sp)); // the sp could be an fn def - let found = match found_trait_ref.skip_binder().substs.type_at(1).sty { + if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) { + // We check closures twice, with obligations flowing in different directions, + // but we want to complain about them only once. + return; + } + + self.reported_closure_mismatch.borrow_mut().insert((span, found_span)); + + let found = match found_trait_ref.skip_binder().substs.type_at(1).kind { ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()], _ => vec![ArgKind::empty()], }; let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1); - let expected = match expected_ty.sty { + let expected = match expected_ty.kind { ty::Tuple(ref tys) => tys.iter() .map(|t| ArgKind::from_expected_ty(t.expect_ty(), Some(span))).collect(), _ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())], @@ -902,7 +933,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } TraitNotObjectSafe(did) => { - let violations = self.tcx.global_tcx().object_safety_violations(did); + let violations = self.tcx.object_safety_violations(did); if let Some(err) = self.tcx.report_object_safety_error(span, did, violations) { err } else { @@ -923,7 +954,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { bug!("overflow should be handled before the `report_selection_error` path"); } }; + self.note_obligation_cause(&mut err, obligation); + err.emit(); } @@ -938,7 +971,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let parent_node = self.tcx.hir().get_parent_node(hir_id); if let Some(Node::Local(ref local)) = self.tcx.hir().find(parent_node) { if let Some(ref expr) = local.init { - if let hir::ExprKind::Index(_, _) = expr.node { + if let hir::ExprKind::Index(_, _) = expr.kind { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(expr.span) { err.span_suggestion( expr.span, @@ -953,6 +986,74 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + fn suggest_fn_call( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + trait_ref: &ty::Binder>, + points_at_arg: bool, + ) { + let self_ty = trait_ref.self_ty(); + match self_ty.kind { + ty::FnDef(def_id, _) => { + // We tried to apply the bound to an `fn`. Check whether calling it would evaluate + // to a type that *would* satisfy the trait binding. If it would, suggest calling + // it: `bar(foo)` -> `bar(foo)`. This case is *very* likely to be hit if `foo` is + // `async`. + let output_ty = self_ty.fn_sig(self.tcx).output(); + let new_trait_ref = ty::TraitRef { + def_id: trait_ref.def_id(), + substs: self.tcx.mk_substs_trait(output_ty.skip_binder(), &[]), + }; + let obligation = Obligation::new( + obligation.cause.clone(), + obligation.param_env, + new_trait_ref.to_predicate(), + ); + match self.evaluate_obligation(&obligation) { + Ok(EvaluationResult::EvaluatedToOk) | + Ok(EvaluationResult::EvaluatedToOkModuloRegions) | + Ok(EvaluationResult::EvaluatedToAmbig) => { + if let Some(hir::Node::Item(hir::Item { + ident, + kind: hir::ItemKind::Fn(.., body_id), + .. + })) = self.tcx.hir().get_if_local(def_id) { + let body = self.tcx.hir().body(*body_id); + let msg = "use parentheses to call the function"; + let snippet = format!( + "{}({})", + ident, + body.params.iter() + .map(|arg| match &arg.pat.kind { + hir::PatKind::Binding(_, _, ident, None) + if ident.name != kw::SelfLower => ident.to_string(), + _ => "_".to_string(), + }).collect::>().join(", "), + ); + // When the obligation error has been ensured to have been caused by + // an argument, the `obligation.cause.span` points at the expression + // of the argument, so we can provide a suggestion. This is signaled + // by `points_at_arg`. Otherwise, we give a more general note. + if points_at_arg { + err.span_suggestion( + obligation.cause.span, + msg, + snippet, + Applicability::HasPlaceholders, + ); + } else { + err.help(&format!("{}: `{}`", msg, snippet)); + } + } + } + _ => {} + } + } + _ => {} + } + } + /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`, /// suggest removing these references until we reach a type that implements the trait. fn suggest_remove_reference( @@ -969,18 +1070,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .filter(|c| !c.is_whitespace()) .take_while(|c| *c == '&') .count(); + if let Some('\'') = snippet.chars() + .filter(|c| !c.is_whitespace()) + .skip(refs_number) + .next() + { // Do not suggest removal of borrow from type arguments. + return; + } let mut trait_type = trait_ref.self_ty(); for refs_remaining in 0..refs_number { - if let ty::Ref(_, t_type, _) = trait_type.sty { + if let ty::Ref(_, t_type, _) = trait_type.kind { trait_type = t_type; let substs = self.tcx.mk_substs_trait(trait_type, &[]); let new_trait_ref = ty::TraitRef::new(trait_ref.def_id, substs); - let new_obligation = Obligation::new(ObligationCause::dummy(), - obligation.param_env, - new_trait_ref.to_predicate()); + let new_obligation = Obligation::new( + ObligationCause::dummy(), + obligation.param_env, + new_trait_ref.to_predicate(), + ); if self.predicate_may_hold(&new_obligation) { let sp = self.tcx.sess.source_map() @@ -1002,6 +1112,77 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + /// Check if the trait bound is implemented for a different mutability and note it in the + /// final error. + fn suggest_change_mut( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + trait_ref: &ty::Binder>, + points_at_arg: bool, + ) { + let span = obligation.cause.span; + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + let refs_number = snippet.chars() + .filter(|c| !c.is_whitespace()) + .take_while(|c| *c == '&') + .count(); + if let Some('\'') = snippet.chars() + .filter(|c| !c.is_whitespace()) + .skip(refs_number) + .next() + { // Do not suggest removal of borrow from type arguments. + return; + } + let trait_ref = self.resolve_vars_if_possible(trait_ref); + if trait_ref.has_infer_types() { + // Do not ICE while trying to find if a reborrow would succeed on a trait with + // unresolved bindings. + return; + } + + if let ty::Ref(region, t_type, mutability) = trait_ref.skip_binder().self_ty().kind { + let trait_type = match mutability { + hir::Mutability::MutMutable => self.tcx.mk_imm_ref(region, t_type), + hir::Mutability::MutImmutable => self.tcx.mk_mut_ref(region, t_type), + }; + + let substs = self.tcx.mk_substs_trait(&trait_type, &[]); + let new_trait_ref = ty::TraitRef::new(trait_ref.skip_binder().def_id, substs); + let new_obligation = Obligation::new( + ObligationCause::dummy(), + obligation.param_env, + new_trait_ref.to_predicate(), + ); + + if self.evaluate_obligation_no_overflow( + &new_obligation, + ).must_apply_modulo_regions() { + let sp = self.tcx.sess.source_map() + .span_take_while(span, |c| c.is_whitespace() || *c == '&'); + if points_at_arg && + mutability == hir::Mutability::MutImmutable && + refs_number > 0 + { + err.span_suggestion( + sp, + "consider changing this borrow's mutability", + "&mut ".to_string(), + Applicability::MachineApplicable, + ); + } else { + err.note(&format!( + "`{}` is implemented for `{:?}`, but not for `{:?}`", + trait_ref, + trait_type, + trait_ref.skip_binder().self_ty(), + )); + } + } + } + } + } + fn suggest_semicolon_removal( &self, obligation: &PredicateObligation<'tcx>, @@ -1013,11 +1194,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let parent_node = hir.get_parent_node(obligation.cause.body_id); let node = hir.find(parent_node); if let Some(hir::Node::Item(hir::Item { - node: hir::ItemKind::Fn(decl, _, _, body_id), + kind: hir::ItemKind::Fn(decl, _, _, body_id), .. })) = node { let body = hir.body(*body_id); - if let hir::ExprKind::Block(blk, _) = &body.value.node { + if let hir::ExprKind::Block(blk, _) = &body.value.kind { if decl.output.span().overlaps(span) && blk.expr.is_none() && "()" == &trait_ref.self_ty().to_string() { @@ -1041,13 +1222,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn get_fn_like_arguments(&self, node: Node<'_>) -> (Span, Vec) { match node { Node::Expr(&hir::Expr { - node: hir::ExprKind::Closure(_, ref _decl, id, span, _), + kind: hir::ExprKind::Closure(_, ref _decl, id, span, _), .. }) => { - (self.tcx.sess.source_map().def_span(span), self.tcx.hir().body(id).arguments.iter() + (self.tcx.sess.source_map().def_span(span), + self.tcx.hir().body(id).params.iter() .map(|arg| { if let hir::Pat { - node: hir::PatKind::Tuple(ref args, _), + kind: hir::PatKind::Tuple(ref args, _), span, .. } = *arg.pat { @@ -1069,21 +1251,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } Node::Item(&hir::Item { span, - node: hir::ItemKind::Fn(ref decl, ..), + kind: hir::ItemKind::Fn(ref decl, ..), .. }) | Node::ImplItem(&hir::ImplItem { span, - node: hir::ImplItemKind::Method(hir::MethodSig { ref decl, .. }, _), + kind: hir::ImplItemKind::Method(hir::MethodSig { ref decl, .. }, _), .. }) | Node::TraitItem(&hir::TraitItem { span, - node: hir::TraitItemKind::Method(hir::MethodSig { ref decl, .. }, _), + kind: hir::TraitItemKind::Method(hir::MethodSig { ref decl, .. }, _), .. }) => { (self.tcx.sess.source_map().def_span(span), decl.inputs.iter() - .map(|arg| match arg.clone().node { + .map(|arg| match arg.clone().kind { hir::TyKind::Tup(ref tys) => ArgKind::Tuple( Some(arg.span), vec![("_".to_owned(), "_".to_owned()); tys.len()] @@ -1129,7 +1311,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => format!("{} {}argument{}", arg_length, if distinct && arg_length > 1 { "distinct " } else { "" }, - if arg_length == 1 { "" } else { "s" }), + pluralise!(arg_length)) } }; @@ -1246,7 +1428,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) -> DiagnosticBuilder<'tcx> { fn build_fn_sig_string<'tcx>(tcx: TyCtxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> String { let inputs = trait_ref.substs.type_at(1); - let sig = if let ty::Tuple(inputs) = inputs.sty { + let sig = if let ty::Tuple(inputs) = inputs.kind { tcx.mk_fn_sig( inputs.iter().map(|k| k.expect_ty()), tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), @@ -1327,7 +1509,10 @@ impl<'tcx> TyCtxt<'tcx> { let mut reported_violations = FxHashSet::default(); for violation in violations { if reported_violations.insert(violation.clone()) { - err.note(&violation.error_msg()); + match violation.span() { + Some(span) => err.span_label(span, violation.error_msg()), + None => err.note(&violation.error_msg()), + }; } } Some(err) @@ -1335,8 +1520,11 @@ impl<'tcx> TyCtxt<'tcx> { } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>, - body_id: Option) { + fn maybe_report_ambiguity( + &self, + obligation: &PredicateObligation<'tcx>, + body_id: Option, + ) { // Unable to successfully determine, probably means // insufficient type information, but could mean // ambiguous impls. The latter *ought* to be a @@ -1345,9 +1533,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let predicate = self.resolve_vars_if_possible(&obligation.predicate); let span = obligation.cause.span; - debug!("maybe_report_ambiguity(predicate={:?}, obligation={:?})", - predicate, - obligation); + debug!( + "maybe_report_ambiguity(predicate={:?}, obligation={:?} body_id={:?}, code={:?})", + predicate, + obligation, + body_id, + obligation.cause.code, + ); // Ambiguity errors are often caused as fallout from earlier // errors. So just ignore them if this infcx is tainted. @@ -1359,6 +1551,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty::Predicate::Trait(ref data) => { let trait_ref = data.to_poly_trait_ref(); let self_ty = trait_ref.self_ty(); + debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref); + if predicate.references_error() { return; } @@ -1383,24 +1577,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // be ignoring the fact that we don't KNOW the type works // out. Though even that would probably be harmless, given that // we're only talking about builtin traits, which are known to be - // inhabited. But in any case I just threw in this check for - // has_errors() to be sure that compilation isn't happening - // anyway. In that case, why inundate the user. - if !self.tcx.sess.has_errors() { - if - self.tcx.lang_items().sized_trait() - .map_or(false, |sized_id| sized_id == trait_ref.def_id()) - { - self.need_type_info_err(body_id, span, self_ty).emit(); - } else { - let mut err = struct_span_err!(self.tcx.sess, - span, E0283, - "type annotations required: \ - cannot resolve `{}`", - predicate); - self.note_obligation_cause(&mut err, obligation); - err.emit(); - } + // inhabited. We used to check for `self.tcx.sess.has_errors()` to + // avoid inundating the user with unnecessary errors, but we now + // check upstream for type errors and dont add the obligations to + // begin with in those cases. + if + self.tcx.lang_items().sized_trait() + .map_or(false, |sized_id| sized_id == trait_ref.def_id()) + { + self.need_type_info_err(body_id, span, self_ty).emit(); + } else { + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0283, + "type annotations needed: cannot resolve `{}`", + predicate, + ); + self.note_obligation_cause(&mut err, obligation); + err.emit(); } } @@ -1427,11 +1622,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => { if !self.tcx.sess.has_errors() { - let mut err = struct_span_err!(self.tcx.sess, - obligation.cause.span, E0284, - "type annotations required: \ - cannot resolve `{}`", - predicate); + let mut err = struct_span_err!( + self.tcx.sess, + obligation.cause.span, + E0284, + "type annotations needed: cannot resolve `{}`", + predicate, + ); self.note_obligation_cause(&mut err, obligation); err.emit(); } @@ -1455,7 +1652,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { self.infcx.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Param(ty::ParamTy {name, .. }) = ty.sty { + if let ty::Param(ty::ParamTy {name, .. }) = ty.kind { let infcx = self.infcx; self.var_map.entry(ty).or_insert_with(|| infcx.next_ty_var( @@ -1496,15 +1693,165 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) } - fn note_obligation_cause(&self, - err: &mut DiagnosticBuilder<'_>, - obligation: &Obligation<'tcx, T>) - where T: fmt::Display - { - self.note_obligation_cause_code(err, - &obligation.predicate, - &obligation.cause.code, - &mut vec![]); + fn note_obligation_cause( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + ) { + // First, attempt to add note to this error with an async-await-specific + // message, and fall back to regular note otherwise. + if !self.note_obligation_cause_for_async_await(err, obligation) { + self.note_obligation_cause_code(err, &obligation.predicate, &obligation.cause.code, + &mut vec![]); + } + } + + /// Adds an async-await specific note to the diagnostic: + /// + /// ```ignore (diagnostic) + /// note: future does not implement `std::marker::Send` because this value is used across an + /// await + /// --> $DIR/issue-64130-non-send-future-diags.rs:15:5 + /// | + /// LL | let g = x.lock().unwrap(); + /// | - has type `std::sync::MutexGuard<'_, u32>` + /// LL | baz().await; + /// | ^^^^^^^^^^^ await occurs here, with `g` maybe used later + /// LL | } + /// | - `g` is later dropped here + /// ``` + /// + /// Returns `true` if an async-await specific note was added to the diagnostic. + fn note_obligation_cause_for_async_await( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + ) -> bool { + debug!("note_obligation_cause_for_async_await: obligation.predicate={:?} \ + obligation.cause.span={:?}", obligation.predicate, obligation.cause.span); + let source_map = self.tcx.sess.source_map(); + + // Look into the obligation predicate to determine the type in the generator which meant + // that the predicate was not satisifed. + let (trait_ref, target_ty) = match obligation.predicate { + ty::Predicate::Trait(trait_predicate) => + (trait_predicate.skip_binder().trait_ref, trait_predicate.skip_binder().self_ty()), + _ => return false, + }; + debug!("note_obligation_cause_for_async_await: target_ty={:?}", target_ty); + + // Attempt to detect an async-await error by looking at the obligation causes, looking + // for only generators, generator witnesses, opaque types or `std::future::GenFuture` to + // be present. + // + // When a future does not implement a trait because of a captured type in one of the + // generators somewhere in the call stack, then the result is a chain of obligations. + // Given a `async fn` A that calls a `async fn` B which captures a non-send type and that + // future is passed as an argument to a function C which requires a `Send` type, then the + // chain looks something like this: + // + // - `BuiltinDerivedObligation` with a generator witness (B) + // - `BuiltinDerivedObligation` with a generator (B) + // - `BuiltinDerivedObligation` with `std::future::GenFuture` (B) + // - `BuiltinDerivedObligation` with `impl std::future::Future` (B) + // - `BuiltinDerivedObligation` with `impl std::future::Future` (B) + // - `BuiltinDerivedObligation` with a generator witness (A) + // - `BuiltinDerivedObligation` with a generator (A) + // - `BuiltinDerivedObligation` with `std::future::GenFuture` (A) + // - `BuiltinDerivedObligation` with `impl std::future::Future` (A) + // - `BuiltinDerivedObligation` with `impl std::future::Future` (A) + // - `BindingObligation` with `impl_send (Send requirement) + // + // The first obligations in the chain can be used to get the details of the type that is + // captured but the entire chain must be inspected to detect this case. + let mut generator = None; + let mut next_code = Some(&obligation.cause.code); + while let Some(code) = next_code { + debug!("note_obligation_cause_for_async_await: code={:?}", code); + match code { + ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) | + ObligationCauseCode::ImplDerivedObligation(derived_obligation) => { + debug!("note_obligation_cause_for_async_await: self_ty.kind={:?}", + derived_obligation.parent_trait_ref.self_ty().kind); + match derived_obligation.parent_trait_ref.self_ty().kind { + ty::Adt(ty::AdtDef { did, .. }, ..) if + self.tcx.is_diagnostic_item(sym::gen_future, *did) => {}, + ty::Generator(did, ..) => generator = generator.or(Some(did)), + ty::GeneratorWitness(_) | ty::Opaque(..) => {}, + _ => return false, + } + + next_code = Some(derived_obligation.parent_code.as_ref()); + }, + ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::BindingObligation(..) + if generator.is_some() => break, + _ => return false, + } + } + + let generator_did = generator.expect("can only reach this if there was a generator"); + + // Only continue to add a note if the generator is from an `async` function. + let parent_node = self.tcx.parent(generator_did) + .and_then(|parent_did| self.tcx.hir().get_if_local(parent_did)); + debug!("note_obligation_cause_for_async_await: parent_node={:?}", parent_node); + if let Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(_, header, _, _), + .. + })) = parent_node { + debug!("note_obligation_cause_for_async_await: header={:?}", header); + if header.asyncness != hir::IsAsync::Async { + return false; + } + } + + let span = self.tcx.def_span(generator_did); + let tables = self.tcx.typeck_tables_of(generator_did); + debug!("note_obligation_cause_for_async_await: generator_did={:?} span={:?} ", + generator_did, span); + + // Look for a type inside the generator interior that matches the target type to get + // a span. + let target_span = tables.generator_interior_types.iter() + .find(|ty::GeneratorInteriorTypeCause { ty, .. }| ty::TyS::same_type(*ty, target_ty)) + .map(|ty::GeneratorInteriorTypeCause { span, scope_span, .. }| + (span, source_map.span_to_snippet(*span), scope_span)); + if let Some((target_span, Ok(snippet), scope_span)) = target_span { + // Look at the last interior type to get a span for the `.await`. + let await_span = tables.generator_interior_types.iter().map(|i| i.span).last().unwrap(); + let mut span = MultiSpan::from_span(await_span); + span.push_span_label( + await_span, format!("await occurs here, with `{}` maybe used later", snippet)); + + span.push_span_label(*target_span, format!("has type `{}`", target_ty)); + + // If available, use the scope span to annotate the drop location. + if let Some(scope_span) = scope_span { + span.push_span_label( + source_map.end_point(*scope_span), + format!("`{}` is later dropped here", snippet), + ); + } + + err.span_note(span, &format!( + "future does not implement `{}` as this value is used across an await", + trait_ref, + )); + + // Add a note for the item obligation that remains - normally a note pointing to the + // bound that introduced the obligation (e.g. `T: Send`). + debug!("note_obligation_cause_for_async_await: next_code={:?}", next_code); + self.note_obligation_cause_code( + err, + &obligation.predicate, + next_code.unwrap(), + &mut Vec::new(), + ); + + true + } else { + false + } } fn note_obligation_cause_code(&self, @@ -1534,17 +1881,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.note("only the last element of a tuple may have a dynamically sized type"); } ObligationCauseCode::ProjectionWf(data) => { - err.note(&format!("required so that the projection `{}` is well-formed", - data)); + err.note(&format!( + "required so that the projection `{}` is well-formed", + data, + )); } ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { - err.note(&format!("required so that reference `{}` does not outlive its referent", - ref_ty)); + err.note(&format!( + "required so that reference `{}` does not outlive its referent", + ref_ty, + )); } ObligationCauseCode::ObjectTypeBound(object_ty, region) => { - err.note(&format!("required so that the lifetime bound of `{}` for `{}` \ - is satisfied", - region, object_ty)); + err.note(&format!( + "required so that the lifetime bound of `{}` for `{}` is satisfied", + region, + object_ty, + )); } ObligationCauseCode::ItemObligation(item_def_id) => { let item_name = tcx.def_path_str(item_def_id); @@ -1552,7 +1905,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let Some(sp) = tcx.hir().span_if_local(item_def_id) { let sp = tcx.sess.source_map().def_span(sp); - err.span_note(sp, &msg); + err.span_label(sp, &msg); + } else { + err.note(&msg); + } + } + ObligationCauseCode::BindingObligation(item_def_id, span) => { + let item_name = tcx.def_path_str(item_def_id); + let msg = format!("required by this bound in `{}`", item_name); + if let Some(ident) = tcx.opt_item_name(item_def_id) { + err.span_label(ident.span, ""); + } + if span != DUMMY_SP { + err.span_label(span, &msg); } else { err.note(&msg); } @@ -1651,7 +2016,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { but not on the corresponding trait method", predicate)); } - ObligationCauseCode::ReturnType(_) | + ObligationCauseCode::ReturnType | + ObligationCauseCode::ReturnValue(_) | ObligationCauseCode::BlockTailExpression(_) => (), ObligationCauseCode::TrivialBound => { err.help("see issue #48214"); @@ -1706,7 +2072,7 @@ impl ArgKind { /// Creates an `ArgKind` from the expected type of an /// argument. It has no name (`_`) and an optional source span. pub fn from_expected_ty(t: Ty<'_>, span: Option) -> ArgKind { - match t.sty { + match t.kind { ty::Tuple(ref tys) => ArgKind::Tuple( span, tys.iter() diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 99b5ef3894b9c..a981162fdc326 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -68,6 +68,10 @@ pub struct PendingPredicateObligation<'tcx> { pub stalled_on: Vec>, } +// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert_size!(PendingPredicateObligation<'_>, 136); + impl<'a, 'tcx> FulfillmentContext<'tcx> { /// Creates a new fulfillment context. pub fn new() -> FulfillmentContext<'tcx> { @@ -248,28 +252,50 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { /// This is always inlined, despite its size, because it has a single /// callsite and it is called *very* frequently. #[inline(always)] - fn process_obligation(&mut self, - pending_obligation: &mut Self::Obligation) - -> ProcessResult - { - // if we were stalled on some unresolved variables, first check - // whether any of them have been resolved; if not, don't bother - // doing more work yet - if !pending_obligation.stalled_on.is_empty() { - if pending_obligation.stalled_on.iter().all(|&ty| { - // Use the force-inlined variant of shallow_resolve() because this code is hot. - let resolved = ShallowResolver::new(self.selcx.infcx()).inlined_shallow_resolve(ty); - resolved == ty // nothing changed here - }) { - debug!("process_predicate: pending obligation {:?} still stalled on {:?}", - self.selcx.infcx() - .resolve_vars_if_possible(&pending_obligation.obligation), - pending_obligation.stalled_on); - return ProcessResult::Unchanged; + fn process_obligation( + &mut self, + pending_obligation: &mut Self::Obligation, + ) -> ProcessResult { + // If we were stalled on some unresolved variables, first check whether + // any of them have been resolved; if not, don't bother doing more work + // yet. + let change = match pending_obligation.stalled_on.len() { + // Match arms are in order of frequency, which matters because this + // code is so hot. 1 and 0 dominate; 2+ is fairly rare. + 1 => { + let ty = pending_obligation.stalled_on[0]; + ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty) } - pending_obligation.stalled_on = vec![]; + 0 => { + // In this case we haven't changed, but wish to make a change. + true + } + _ => { + // This `for` loop was once a call to `all()`, but this lower-level + // form was a perf win. See #64545 for details. + (|| { + for &ty in &pending_obligation.stalled_on { + if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty) { + return true; + } + } + false + })() + } + }; + + if !change { + debug!("process_predicate: pending obligation {:?} still stalled on {:?}", + self.selcx.infcx() + .resolve_vars_if_possible(&pending_obligation.obligation), + pending_obligation.stalled_on); + return ProcessResult::Unchanged; } + // This part of the code is much colder. + + pending_obligation.stalled_on.truncate(0); + let obligation = &mut pending_obligation.obligation; if obligation.predicate.has_infer_types() { @@ -277,7 +303,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { self.selcx.infcx().resolve_vars_if_possible(&obligation.predicate); } - debug!("process_obligation: obligation = {:?}", obligation); + debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause); match obligation.predicate { ty::Predicate::Trait(ref data) => { @@ -425,10 +451,13 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } ty::Predicate::WellFormed(ty) => { - match ty::wf::obligations(self.selcx.infcx(), - obligation.param_env, - obligation.cause.body_id, - ty, obligation.cause.span) { + match ty::wf::obligations( + self.selcx.infcx(), + obligation.param_env, + obligation.cause.body_id, + ty, + obligation.cause.span, + ) { None => { pending_obligation.stalled_on = vec![ty]; ProcessResult::Unchanged @@ -466,7 +495,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } else { if !substs.has_local_value() { let instance = ty::Instance::resolve( - self.selcx.tcx().global_tcx(), + self.selcx.tcx(), obligation.param_env, def_id, substs, @@ -519,7 +548,7 @@ fn trait_ref_type_vars<'a, 'tcx>( .map(|t| selcx.infcx().resolve_vars_if_possible(&t)) .filter(|t| t.has_infer_types()) .flat_map(|t| t.walk()) - .filter(|t| match t.sty { ty::Infer(_) => true, _ => false }) + .filter(|t| match t.kind { ty::Infer(_) => true, _ => false }) .collect() } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 1ca92d79fa5f6..d96330bf0a9b4 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -123,6 +123,10 @@ pub struct Obligation<'tcx, T> { pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; +// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert_size!(PredicateObligation<'_>, 112); + /// The reason why we incurred this obligation; used for error reporting. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct ObligationCause<'tcx> { @@ -147,7 +151,8 @@ impl<'tcx> ObligationCause<'tcx> { ObligationCauseCode::StartFunctionType => { tcx.sess.source_map().def_span(self.span) } - ObligationCauseCode::MatchExpressionArm { arm_span, .. } => arm_span, + ObligationCauseCode::MatchExpressionArm( + box MatchExpressionArmCause { arm_span, .. }) => arm_span, _ => self.span, } } @@ -171,6 +176,9 @@ pub enum ObligationCauseCode<'tcx> { /// also implement all supertraits of `X`. ItemObligation(DefId), + /// Like `ItemObligation`, but with extra detail on the source of the obligation. + BindingObligation(DefId, Span), + /// A type like `&'a T` is WF only if `T: 'a`. ReferenceOutlivesReferent(Ty<'tcx>), @@ -204,14 +212,14 @@ pub enum ObligationCauseCode<'tcx> { /// Constant expressions must be sized. ConstSized, - /// static items must have `Sync` type + /// Static items must have `Sync` type SharedStatic, BuiltinDerivedObligation(DerivedObligationCause<'tcx>), ImplDerivedObligation(DerivedObligationCause<'tcx>), - /// error derived when matching traits/impls; see ObligationCause for more details + /// Error derived when matching traits/impls; see ObligationCause for more details CompareImplMethodObligation { item_name: ast::Name, impl_item_def_id: DefId, @@ -223,23 +231,13 @@ pub enum ObligationCauseCode<'tcx> { ExprAssignable, /// Computing common supertype in the arms of a match expression - MatchExpressionArm { - arm_span: Span, - source: hir::MatchSource, - prior_arms: Vec, - last_ty: Ty<'tcx>, - discrim_hir_id: hir::HirId, - }, + MatchExpressionArm(Box>), /// Computing common supertype in the pattern guard for the arms of a match expression MatchExpressionArmPattern { span: Span, ty: Ty<'tcx> }, /// Computing common supertype in an if expression - IfExpression { - then: Span, - outer: Option, - semicolon: Option, - }, + IfExpression(Box), /// Computing common supertype of an if expression with no else counter-part IfExpressionWithNoElse, @@ -250,17 +248,20 @@ pub enum ObligationCauseCode<'tcx> { /// `start` has wrong type StartFunctionType, - /// intrinsic has wrong type + /// Intrinsic has wrong type IntrinsicType, - /// method receiver + /// Method receiver MethodReceiver, /// `return` with no expression ReturnNoExpression, /// `return` with an expression - ReturnType(hir::HirId), + ReturnValue(hir::HirId), + + /// Return type of this function + ReturnType, /// Block implicit return BlockTailExpression(hir::HirId), @@ -269,6 +270,26 @@ pub enum ObligationCauseCode<'tcx> { TrivialBound, } +// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert_size!(ObligationCauseCode<'_>, 32); + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct MatchExpressionArmCause<'tcx> { + pub arm_span: Span, + pub source: hir::MatchSource, + pub prior_arms: Vec, + pub last_ty: Ty<'tcx>, + pub discrim_hir_id: hir::HirId, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct IfExpressionCause { + pub then: Span, + pub outer: Option, + pub semicolon: Option, +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct DerivedObligationCause<'tcx> { /// The trait reference of the parent obligation that led to the @@ -469,7 +490,11 @@ EnumTypeFoldableImpl! { pub struct FulfillmentError<'tcx> { pub obligation: PredicateObligation<'tcx>, - pub code: FulfillmentErrorCode<'tcx> + pub code: FulfillmentErrorCode<'tcx>, + /// Diagnostics only: we opportunistically change the `code.span` when we encounter an + /// obligation error caused by a call argument. When this is the case, we also signal that in + /// this field to ensure accuracy of suggestions. + pub points_at_arg_span: bool, } #[derive(Clone)] @@ -585,7 +610,7 @@ pub struct VtableImplData<'tcx, N> { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] pub struct VtableGeneratorData<'tcx, N> { pub generator_def_id: DefId, - pub substs: ty::GeneratorSubsts<'tcx>, + pub substs: SubstsRef<'tcx>, /// Nested obligations. This can be non-empty if the generator /// signature contains associated types. pub nested: Vec @@ -594,7 +619,7 @@ pub struct VtableGeneratorData<'tcx, N> { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] pub struct VtableClosureData<'tcx, N> { pub closure_def_id: DefId, - pub substs: ty::ClosureSubsts<'tcx>, + pub substs: SubstsRef<'tcx>, /// Nested obligations. This can be non-empty if the closure /// signature contains associated types. pub nested: Vec @@ -640,11 +665,11 @@ pub struct VtableTraitAliasData<'tcx, N> { } /// Creates predicate obligations from the generic bounds. -pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - generic_bounds: &ty::InstantiatedPredicates<'tcx>) - -> PredicateObligations<'tcx> -{ +pub fn predicates_for_generics<'tcx>( + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + generic_bounds: &ty::InstantiatedPredicates<'tcx>, +) -> PredicateObligations<'tcx> { util::predicates_for_generics(cause, 0, param_env, generic_bounds) } @@ -1168,7 +1193,7 @@ impl<'tcx> FulfillmentError<'tcx> { code: FulfillmentErrorCode<'tcx>) -> FulfillmentError<'tcx> { - FulfillmentError { obligation: obligation, code: code } + FulfillmentError { obligation: obligation, code: code, points_at_arg_span: false } } } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 37eff852abd01..e0ef179911b6c 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -20,7 +20,7 @@ use std::borrow::Cow; use std::iter::{self}; use syntax::ast::{self}; use syntax::symbol::InternedString; -use syntax_pos::Span; +use syntax_pos::{Span, DUMMY_SP}; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum ObjectSafetyViolation { @@ -32,10 +32,10 @@ pub enum ObjectSafetyViolation { SupertraitSelf, /// Method has something illegal. - Method(ast::Name, MethodViolationCode), + Method(ast::Name, MethodViolationCode, Span), /// Associated const. - AssocConst(ast::Name), + AssocConst(ast::Name, Span), } impl ObjectSafetyViolation { @@ -46,22 +46,35 @@ impl ObjectSafetyViolation { ObjectSafetyViolation::SupertraitSelf => "the trait cannot use `Self` as a type parameter \ in the supertraits or where-clauses".into(), - ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod) => - format!("method `{}` has no receiver", name).into(), - ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelf) => - format!("method `{}` references the `Self` type \ - in its arguments or return type", name).into(), - ObjectSafetyViolation::Method(name, - MethodViolationCode::WhereClauseReferencesSelf(_)) => - format!("method `{}` references the `Self` type in where clauses", name).into(), - ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) => + ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod, _) => + format!("associated function `{}` has no `self` parameter", name).into(), + ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelf, _) => format!( + "method `{}` references the `Self` type in its parameters or return type", + name, + ).into(), + ObjectSafetyViolation::Method( + name, + MethodViolationCode::WhereClauseReferencesSelf, + _, + ) => format!("method `{}` references the `Self` type in where clauses", name).into(), + ObjectSafetyViolation::Method(name, MethodViolationCode::Generic, _) => format!("method `{}` has generic type parameters", name).into(), - ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver) => - format!("method `{}`'s receiver cannot be dispatched on", name).into(), - ObjectSafetyViolation::AssocConst(name) => + ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver, _) => + format!("method `{}`'s `self` parameter cannot be dispatched on", name).into(), + ObjectSafetyViolation::AssocConst(name, _) => format!("the trait cannot contain associated consts like `{}`", name).into(), } } + + pub fn span(&self) -> Option { + // When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so + // diagnostics use a `note` instead of a `span_label`. + match *self { + ObjectSafetyViolation::AssocConst(_, span) | + ObjectSafetyViolation::Method(_, _, span) if span != DUMMY_SP => Some(span), + _ => None, + } + } } /// Reasons a method might not be object-safe. @@ -74,7 +87,7 @@ pub enum MethodViolationCode { ReferencesSelf, /// e.g., `fn foo(&self) where Self: Clone` - WhereClauseReferencesSelf(Span), + WhereClauseReferencesSelf, /// e.g., `fn foo()` Generic, @@ -88,9 +101,11 @@ impl<'tcx> TyCtxt<'tcx> { /// astconv -- currently, `Self` in supertraits. This is needed /// because `object_safety_violations` can't be used during /// type collection. - pub fn astconv_object_safety_violations(self, trait_def_id: DefId) - -> Vec - { + pub fn astconv_object_safety_violations( + self, + trait_def_id: DefId, + ) -> Vec { + debug_assert!(self.generics_of(trait_def_id).has_self); let violations = traits::supertrait_def_ids(self, trait_def_id) .filter(|&def_id| self.predicates_reference_self(def_id, true)) .map(|_| ObjectSafetyViolation::SupertraitSelf) @@ -106,6 +121,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn object_safety_violations(self, trait_def_id: DefId) -> Vec { + debug_assert!(self.generics_of(trait_def_id).has_self); debug!("object_safety_violations: {:?}", trait_def_id); traits::supertrait_def_ids(self, trait_def_id) @@ -113,19 +129,38 @@ impl<'tcx> TyCtxt<'tcx> { .collect() } - fn object_safety_violations_for_trait(self, trait_def_id: DefId) - -> Vec - { + /// We say a method is *vtable safe* if it can be invoked on a trait + /// object. Note that object-safe traits can have some + /// non-vtable-safe methods, so long as they require `Self: Sized` or + /// otherwise ensure that they cannot be used when `Self = Trait`. + pub fn is_vtable_safe_method(self, trait_def_id: DefId, method: &ty::AssocItem) -> bool { + debug_assert!(self.generics_of(trait_def_id).has_self); + debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method); + // Any method that has a `Self: Sized` bound cannot be called. + if self.generics_require_sized_self(method.def_id) { + return false; + } + + match self.virtual_call_violation_for_method(trait_def_id, method) { + None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true, + Some(_) => false, + } + } + + fn object_safety_violations_for_trait(self, trait_def_id: DefId) -> Vec { // Check methods for violations. let mut violations: Vec<_> = self.associated_items(trait_def_id) .filter(|item| item.kind == ty::AssocKind::Method) .filter_map(|item| - self.object_safety_violation_for_method(trait_def_id, &item) - .map(|code| ObjectSafetyViolation::Method(item.ident.name, code)) + self.object_safety_violation_for_method(trait_def_id, &item).map(|code| { + ObjectSafetyViolation::Method(item.ident.name, code, item.ident.span) + }) ).filter(|violation| { - if let ObjectSafetyViolation::Method(_, - MethodViolationCode::WhereClauseReferencesSelf(span)) = violation - { + if let ObjectSafetyViolation::Method( + _, + MethodViolationCode::WhereClauseReferencesSelf, + span, + ) = violation { // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id. // It's also hard to get a use site span, so we use the method definition span. self.lint_node_note( @@ -151,7 +186,7 @@ impl<'tcx> TyCtxt<'tcx> { violations.extend(self.associated_items(trait_def_id) .filter(|item| item.kind == ty::AssocKind::Const) - .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name))); + .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span))); debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", trait_def_id, @@ -163,14 +198,16 @@ impl<'tcx> TyCtxt<'tcx> { fn predicates_reference_self( self, trait_def_id: DefId, - supertraits_only: bool) -> bool - { + supertraits_only: bool, + ) -> bool { let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(self, trait_def_id)); let predicates = if supertraits_only { self.super_predicates_of(trait_def_id) } else { self.predicates_of(trait_def_id) }; + let self_ty = self.types.self_param; + let has_self_ty = |t: Ty<'tcx>| t.walk().any(|t| t == self_ty); predicates .predicates .iter() @@ -179,7 +216,7 @@ impl<'tcx> TyCtxt<'tcx> { match predicate { ty::Predicate::Trait(ref data) => { // In the case of a trait predicate, we can skip the "self" type. - data.skip_binder().input_types().skip(1).any(|t| t.has_self_ty()) + data.skip_binder().input_types().skip(1).any(has_self_ty) } ty::Predicate::Projection(ref data) => { // And similarly for projections. This should be redundant with @@ -199,7 +236,7 @@ impl<'tcx> TyCtxt<'tcx> { .trait_ref(self) .input_types() .skip(1) - .any(|t| t.has_self_ty()) + .any(has_self_ty) } ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | @@ -229,11 +266,11 @@ impl<'tcx> TyCtxt<'tcx> { let predicates = predicates.instantiate_identity(self).predicates; elaborate_predicates(self, predicates) .any(|predicate| match predicate { - ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => { - trait_pred.skip_binder().self_ty().is_self() + ty::Predicate::Trait(ref trait_pred) => { + trait_pred.def_id() == sized_def_id + && trait_pred.skip_binder().self_ty().is_param(0) } ty::Predicate::Projection(..) | - ty::Predicate::Trait(..) | ty::Predicate::Subtype(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | @@ -248,11 +285,11 @@ impl<'tcx> TyCtxt<'tcx> { } /// Returns `Some(_)` if this method makes the containing trait not object safe. - fn object_safety_violation_for_method(self, - trait_def_id: DefId, - method: &ty::AssocItem) - -> Option - { + fn object_safety_violation_for_method( + self, + trait_def_id: DefId, + method: &ty::AssocItem, + ) -> Option { debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method); // Any method that has a `Self : Sized` requisite is otherwise // exempt from the regulations. @@ -263,36 +300,15 @@ impl<'tcx> TyCtxt<'tcx> { self.virtual_call_violation_for_method(trait_def_id, method) } - /// We say a method is *vtable safe* if it can be invoked on a trait - /// object. Note that object-safe traits can have some - /// non-vtable-safe methods, so long as they require `Self:Sized` or - /// otherwise ensure that they cannot be used when `Self=Trait`. - pub fn is_vtable_safe_method(self, - trait_def_id: DefId, - method: &ty::AssocItem) - -> bool - { - debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method); - // Any method that has a `Self : Sized` requisite can't be called. - if self.generics_require_sized_self(method.def_id) { - return false; - } - - match self.virtual_call_violation_for_method(trait_def_id, method) { - None | Some(MethodViolationCode::WhereClauseReferencesSelf(_)) => true, - Some(_) => false, - } - } - /// Returns `Some(_)` if this method cannot be called on a trait /// object; this does not necessarily imply that the enclosing trait /// is not object safe, because the method might have a where clause /// `Self:Sized`. - fn virtual_call_violation_for_method(self, - trait_def_id: DefId, - method: &ty::AssocItem) - -> Option - { + fn virtual_call_violation_for_method( + self, + trait_def_id: DefId, + method: &ty::AssocItem, + ) -> Option { // The method's first parameter must be named `self` if !method.method_has_self_argument { return Some(MethodViolationCode::StaticMethod); @@ -323,9 +339,10 @@ impl<'tcx> TyCtxt<'tcx> { .collect::>() // Do a shallow visit so that `contains_illegal_self_type_reference` // may apply it's custom visiting. - .visit_tys_shallow(|t| self.contains_illegal_self_type_reference(trait_def_id, t)) { - let span = self.def_span(method.def_id); - return Some(MethodViolationCode::WhereClauseReferencesSelf(span)); + .visit_tys_shallow(|t| { + self.contains_illegal_self_type_reference(trait_def_id, t) + }) { + return Some(MethodViolationCode::WhereClauseReferencesSelf); } let receiver_ty = self.liberate_late_bound_regions( @@ -333,15 +350,15 @@ impl<'tcx> TyCtxt<'tcx> { &sig.map_bound(|sig| sig.inputs()[0]), ); - // until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on. + // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on. // However, this is already considered object-safe. We allow it as a special case here. // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows - // `Receiver: Unsize dyn Trait]>` - if receiver_ty != self.mk_self_type() { + // `Receiver: Unsize dyn Trait]>`. + if receiver_ty != self.types.self_param { if !self.receiver_is_dispatchable(method, receiver_ty) { return Some(MethodViolationCode::UndispatchableReceiver); } else { - // sanity check to make sure the receiver actually has the layout of a pointer + // Do sanity check to make sure the receiver actually has the layout of a pointer. use crate::ty::layout::Abi; @@ -351,12 +368,12 @@ impl<'tcx> TyCtxt<'tcx> { match self.layout_of(param_env.and(ty)) { Ok(layout) => &layout.abi, Err(err) => bug!( - "Error: {}\n while computing layout for type {:?}", err, ty + "error: {}\n while computing layout for type {:?}", err, ty ) } }; - // e.g., Rc<()> + // e.g., `Rc<()>` let unit_receiver_ty = self.receiver_for_self_ty( receiver_ty, self.mk_unit(), method.def_id ); @@ -367,7 +384,7 @@ impl<'tcx> TyCtxt<'tcx> { self.sess.delay_span_bug( self.def_span(method.def_id), &format!( - "Receiver when Self = () should have a Scalar ABI, found {:?}", + "receiver when `Self = ()` should have a Scalar ABI; found {:?}", abi ), ); @@ -378,7 +395,7 @@ impl<'tcx> TyCtxt<'tcx> { trait_def_id, self.mk_region(ty::ReStatic) ); - // e.g., Rc + // e.g., `Rc` let trait_object_receiver = self.receiver_for_self_ty( receiver_ty, trait_object_ty, method.def_id ); @@ -389,7 +406,8 @@ impl<'tcx> TyCtxt<'tcx> { self.sess.delay_span_bug( self.def_span(method.def_id), &format!( - "Receiver when Self = {} should have a ScalarPair ABI, found {:?}", + "receiver when `Self = {}` should have a ScalarPair ABI; \ + found {:?}", trait_object_ty, abi ), ); @@ -401,10 +419,13 @@ impl<'tcx> TyCtxt<'tcx> { None } - /// Performs a type substitution to produce the version of receiver_ty when `Self = self_ty` - /// e.g., for receiver_ty = `Rc` and self_ty = `Foo`, returns `Rc`. + /// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`. + /// For example, for `receiver_ty = Rc` and `self_ty = Foo`, returns `Rc`. fn receiver_for_self_ty( - self, receiver_ty: Ty<'tcx>, self_ty: Ty<'tcx>, method_def_id: DefId + self, + receiver_ty: Ty<'tcx>, + self_ty: Ty<'tcx>, + method_def_id: DefId, ) -> Ty<'tcx> { debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id); let substs = InternalSubsts::for_item(self, method_def_id, |param, _| { @@ -555,7 +576,7 @@ impl<'tcx> TyCtxt<'tcx> { // Self: Unsize let unsize_predicate = ty::TraitRef { def_id: unsize_did, - substs: self.mk_substs_trait(self.mk_self_type(), &[unsized_self_ty.into()]), + substs: self.mk_substs_trait(self.types.self_param, &[unsized_self_ty.into()]), }.to_predicate(); // U: Trait @@ -608,11 +629,11 @@ impl<'tcx> TyCtxt<'tcx> { }) } - fn contains_illegal_self_type_reference(self, - trait_def_id: DefId, - ty: Ty<'tcx>) - -> bool - { + fn contains_illegal_self_type_reference( + self, + trait_def_id: DefId, + ty: Ty<'tcx>, + ) -> bool { // This is somewhat subtle. In general, we want to forbid // references to `Self` in the argument and return types, // since the value of `Self` is erased. However, there is one @@ -654,10 +675,11 @@ impl<'tcx> TyCtxt<'tcx> { let mut supertraits: Option>> = None; let mut error = false; + let self_ty = self.types.self_param; ty.maybe_walk(|ty| { - match ty.sty { - ty::Param(ref param_ty) => { - if param_ty.is_self() { + match ty.kind { + ty::Param(_) => { + if ty == self_ty { error = true; } diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index 0a42b6b46f2c9..5a988d9509e80 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc/traits/on_unimplemented.rs @@ -9,10 +9,9 @@ use syntax::ast::{MetaItem, NestedMetaItem}; use syntax::attr; use syntax::symbol::{Symbol, kw, sym}; use syntax_pos::Span; -use syntax_pos::symbol::LocalInternedString; #[derive(Clone, Debug)] -pub struct OnUnimplementedFormatString(LocalInternedString); +pub struct OnUnimplementedFormatString(Symbol); #[derive(Debug)] pub struct OnUnimplementedDirective { @@ -89,19 +88,19 @@ impl<'tcx> OnUnimplementedDirective { if item.check_name(sym::message) && message.is_none() { if let Some(message_) = item.value_str() { message = Some(OnUnimplementedFormatString::try_parse( - tcx, trait_def_id, message_.as_str(), span)?); + tcx, trait_def_id, message_, span)?); continue; } } else if item.check_name(sym::label) && label.is_none() { if let Some(label_) = item.value_str() { label = Some(OnUnimplementedFormatString::try_parse( - tcx, trait_def_id, label_.as_str(), span)?); + tcx, trait_def_id, label_, span)?); continue; } } else if item.check_name(sym::note) && note.is_none() { if let Some(note_) = item.value_str() { note = Some(OnUnimplementedFormatString::try_parse( - tcx, trait_def_id, note_.as_str(), span)?); + tcx, trait_def_id, note_, span)?); continue; } } else if item.check_name(sym::on) && is_root && @@ -154,7 +153,7 @@ impl<'tcx> OnUnimplementedDirective { message: None, subcommands: vec![], label: Some(OnUnimplementedFormatString::try_parse( - tcx, trait_def_id, value.as_str(), attr.span)?), + tcx, trait_def_id, value, attr.span)?), note: None, })) } else { @@ -218,7 +217,7 @@ impl<'tcx> OnUnimplementedFormatString { fn try_parse( tcx: TyCtxt<'tcx>, trait_def_id: DefId, - from: LocalInternedString, + from: Symbol, err_sp: Span, ) -> Result { let result = OnUnimplementedFormatString(from); @@ -234,7 +233,8 @@ impl<'tcx> OnUnimplementedFormatString { ) -> Result<(), ErrorReported> { let name = tcx.item_name(trait_def_id); let generics = tcx.generics_of(trait_def_id); - let parser = Parser::new(&self.0, None, vec![], false); + let s = self.0.as_str(); + let parser = Parser::new(&s, None, vec![], false); let mut result = Ok(()); for token in parser { match token { @@ -294,7 +294,8 @@ impl<'tcx> OnUnimplementedFormatString { }).collect::>(); let empty_string = String::new(); - let parser = Parser::new(&self.0, None, vec![], false); + let s = self.0.as_str(); + let parser = Parser::new(&s, None, vec![], false); parser.map(|p| match p { Piece::String(s) => s, diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 38263f26a59a0..d88bbe145d1fd 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -15,7 +15,6 @@ use super::util; use crate::hir::def_id::DefId; use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use crate::mir::interpret::{GlobalId, ConstValue}; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use rustc_macros::HashStable; use syntax::ast::Ident; @@ -338,7 +337,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { // should occur eventually). let ty = ty.super_fold_with(self); - match ty.sty { + match ty.kind { ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // (*) // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal { @@ -397,40 +396,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ConstValue::Unevaluated(def_id, substs) = constant.val { - let tcx = self.selcx.tcx().global_tcx(); - let param_env = self.param_env; - if !param_env.has_local_value() { - if substs.needs_infer() || substs.has_placeholders() { - let identity_substs = InternalSubsts::identity_for_item(tcx, def_id); - let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs); - if let Some(instance) = instance { - let cid = GlobalId { - instance, - promoted: None - }; - if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { - let evaluated = evaluated.subst(tcx, substs); - return evaluated; - } - } - } else { - if !substs.has_local_value() { - let instance = ty::Instance::resolve(tcx, param_env, def_id, substs); - if let Some(instance) = instance { - let cid = GlobalId { - instance, - promoted: None - }; - if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { - return evaluated; - } - } - } - } - } - } - constant + constant.eval(self.selcx.tcx(), self.param_env) } } @@ -955,7 +921,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( let tcx = selcx.tcx(); // Check whether the self-type is itself a projection. - let (def_id, substs) = match obligation_trait_ref.self_ty().sty { + let (def_id, substs) = match obligation_trait_ref.self_ty().kind { ty::Projection(ref data) => { (data.trait_ref(tcx).def_id, data.substs) } @@ -1233,7 +1199,7 @@ fn confirm_object_candidate<'cx, 'tcx>( let object_ty = selcx.infcx().shallow_resolve(self_ty); debug!("confirm_object_candidate(object_ty={:?})", object_ty); - let data = match object_ty.sty { + let data = match object_ty.kind { ty::Dynamic(ref data, ..) => data, _ => { span_bug!( @@ -1293,7 +1259,7 @@ fn confirm_generator_candidate<'cx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, vtable: VtableGeneratorData<'tcx, PredicateObligation<'tcx>>, ) -> Progress<'tcx> { - let gen_sig = vtable.substs.poly_sig(vtable.generator_def_id, selcx.tcx()); + let gen_sig = vtable.substs.as_generator().poly_sig(vtable.generator_def_id, selcx.tcx()); let Normalized { value: gen_sig, obligations @@ -1368,7 +1334,8 @@ fn confirm_closure_candidate<'cx, 'tcx>( ) -> Progress<'tcx> { let tcx = selcx.tcx(); let infcx = selcx.infcx(); - let closure_sig_ty = vtable.substs.closure_sig_ty(vtable.closure_def_id, tcx); + let closure_sig_ty = vtable.substs + .as_closure().sig_ty(vtable.closure_def_id, tcx); let closure_sig = infcx.shallow_resolve(closure_sig_ty).fn_sig(tcx); let Normalized { value: closure_sig, @@ -1417,7 +1384,7 @@ fn confirm_callable_candidate<'cx, 'tcx>( projection_ty: ty::ProjectionTy::from_ref_and_name( tcx, trait_ref, - Ident::with_empty_ctxt(FN_OUTPUT_NAME), + Ident::with_dummy_span(FN_OUTPUT_NAME), ), ty: ret_type } @@ -1538,8 +1505,8 @@ fn assoc_ty_def( if let Some(assoc_item) = trait_def .ancestors(tcx, impl_def_id) - .defs(tcx, assoc_ty_name, ty::AssocKind::Type, trait_def_id) - .next() { + .leaf_def(tcx, assoc_ty_name, ty::AssocKind::Type) { + assoc_item } else { // This is saying that neither the trait nor diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs index 46403a38c99bd..eaf5971e4592f 100644 --- a/src/librustc/traits/query/dropck_outlives.rs +++ b/src/librustc/traits/query/dropck_outlives.rs @@ -3,7 +3,7 @@ use crate::infer::InferOk; use crate::infer::canonical::OriginalQueryValues; use std::iter::FromIterator; use syntax::source_map::Span; -use crate::ty::subst::Kind; +use crate::ty::subst::GenericArg; use crate::ty::{self, Ty, TyCtxt}; impl<'cx, 'tcx> At<'cx, 'tcx> { @@ -24,7 +24,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> { /// /// [#1238]: https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md /// [#1327]: https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md - pub fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec>> { + pub fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec>> { debug!( "dropck_outlives(ty={:?}, param_env={:?})", ty, self.param_env, @@ -40,12 +40,11 @@ impl<'cx, 'tcx> At<'cx, 'tcx> { }; } - let gcx = tcx.global_tcx(); let mut orig_values = OriginalQueryValues::default(); let c_ty = self.infcx.canonicalize_query(&self.param_env.and(ty), &mut orig_values); let span = self.cause.span; debug!("c_ty = {:?}", c_ty); - if let Ok(result) = &gcx.dropck_outlives(c_ty) { + if let Ok(result) = &tcx.dropck_outlives(c_ty) { if result.is_proven() { if let Ok(InferOk { value, obligations }) = self.infcx.instantiate_query_response_and_region_obligations( @@ -80,7 +79,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> { #[derive(Clone, Debug, Default)] pub struct DropckOutlivesResult<'tcx> { - pub kinds: Vec>, + pub kinds: Vec>, pub overflows: Vec>, } @@ -104,7 +103,7 @@ impl<'tcx> DropckOutlivesResult<'tcx> { tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>, - ) -> Vec> { + ) -> Vec> { self.report_overflows(tcx, span, ty); let DropckOutlivesResult { kinds, overflows: _ } = self; kinds @@ -117,7 +116,7 @@ impl<'tcx> DropckOutlivesResult<'tcx> { pub struct DtorckConstraint<'tcx> { /// Types that are required to be alive in order for this /// type to be valid for destruction. - pub outlives: Vec>, + pub outlives: Vec>, /// Types that could not be resolved: projections and params. pub dtorck_types: Vec>, @@ -186,7 +185,7 @@ impl_stable_hash_for!(struct DtorckConstraint<'tcx> { /// Note also that `needs_drop` requires a "global" type (i.e., one /// with erased regions), but this function does not. pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.sty { + match ty.kind { // None of these types have a destructor and hence they do not // require anything in particular to outlive the dtor's // execution. @@ -214,6 +213,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { // check if *any* of those are trivial. ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())), ty::Closure(def_id, ref substs) => substs + .as_closure() .upvar_tys(def_id, tcx) .all(|t| trivial_dropck_outlives(tcx, t)), diff --git a/src/librustc/traits/query/evaluate_obligation.rs b/src/librustc/traits/query/evaluate_obligation.rs index 2ee63647aaded..0d426cab9b751 100644 --- a/src/librustc/traits/query/evaluate_obligation.rs +++ b/src/librustc/traits/query/evaluate_obligation.rs @@ -1,7 +1,8 @@ use crate::infer::InferCtxt; use crate::infer::canonical::OriginalQueryValues; -use crate::traits::{EvaluationResult, PredicateObligation, SelectionContext, - TraitQueryMode, OverflowError}; +use crate::traits::{ + EvaluationResult, PredicateObligation, SelectionContext, TraitQueryMode, OverflowError, +}; impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// Evaluates whether the predicate can be satisfied (by any means) @@ -49,13 +50,13 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // Run canonical query. If overflow occurs, rerun from scratch but this time // in standard trait query mode so that overflow is handled appropriately // within `SelectionContext`. - self.tcx.global_tcx().evaluate_obligation(c_pred) + self.tcx.evaluate_obligation(c_pred) } // Helper function that canonicalizes and runs the query. If an // overflow results, we re-run it in the local context so we can // report a nice error. - fn evaluate_obligation_no_overflow( + crate fn evaluate_obligation_no_overflow( &self, obligation: &PredicateObligation<'tcx>, ) -> EvaluationResult { diff --git a/src/librustc/traits/query/method_autoderef.rs b/src/librustc/traits/query/method_autoderef.rs index 6b9bdfd63f4d0..039dea1ffcd16 100644 --- a/src/librustc/traits/query/method_autoderef.rs +++ b/src/librustc/traits/query/method_autoderef.rs @@ -6,11 +6,11 @@ use crate::ty::Ty; pub struct CandidateStep<'tcx> { pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, pub autoderefs: usize, - // true if the type results from a dereference of a raw pointer. - // when assembling candidates, we include these steps, but not when - // picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods - // `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then - // `foo.by_raw_ptr()` will work and `foo.by_ref()` won't. + /// `true` if the type results from a dereference of a raw pointer. + /// when assembling candidates, we include these steps, but not when + /// picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods + /// `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then + /// `foo.by_raw_ptr()` will work and `foo.by_ref()` won't. pub from_unsafe_deref: bool, pub unsize: bool, } diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index 2ffcd0fd4d941..ab42eab28440f 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -5,11 +5,10 @@ use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; -use crate::mir::interpret::{GlobalId, ConstValue}; use crate::traits::project::Normalized; use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use crate::ty::fold::{TypeFoldable, TypeFolder}; -use crate::ty::subst::{Subst, InternalSubsts}; +use crate::ty::subst::Subst; use crate::ty::{self, Ty, TyCtxt}; use super::NoSolution; @@ -89,7 +88,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { let ty = ty.super_fold_with(self); - match ty.sty { + match ty.kind { ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // (*) // Only normalize `impl Trait` after type-checking, usually in codegen. @@ -142,7 +141,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { // binder). It would be better to normalize in a // binding-aware fashion. - let gcx = self.infcx.tcx.global_tcx(); + let tcx = self.infcx.tcx; let mut orig_values = OriginalQueryValues::default(); // HACK(matthewjasper) `'static` is special-cased in selection, @@ -151,7 +150,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { &self.param_env.and(*data), &mut orig_values); debug!("QueryNormalizer: c_data = {:#?}", c_data); debug!("QueryNormalizer: orig_values = {:#?}", orig_values); - match gcx.normalize_projection_ty(c_data) { + match tcx.normalize_projection_ty(c_data) { Ok(result) => { // We don't expect ambiguity. if result.is_ambiguous() { @@ -191,40 +190,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { } fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ConstValue::Unevaluated(def_id, substs) = constant.val { - let tcx = self.infcx.tcx.global_tcx(); - let param_env = self.param_env; - if !param_env.has_local_value() { - if substs.needs_infer() || substs.has_placeholders() { - let identity_substs = InternalSubsts::identity_for_item(tcx, def_id); - let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs); - if let Some(instance) = instance { - let cid = GlobalId { - instance, - promoted: None, - }; - if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { - let evaluated = evaluated.subst(tcx, substs); - return evaluated; - } - } - } else { - if !substs.has_local_value() { - let instance = ty::Instance::resolve(tcx, param_env, def_id, substs); - if let Some(instance) = instance { - let cid = GlobalId { - instance, - promoted: None, - }; - if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { - return evaluated; - } - } - } - } - } - } - constant + constant.eval(self.infcx.tcx, self.param_env) } } diff --git a/src/librustc/traits/query/outlives_bounds.rs b/src/librustc/traits/query/outlives_bounds.rs index 40bd18738b528..eee084b78963c 100644 --- a/src/librustc/traits/query/outlives_bounds.rs +++ b/src/librustc/traits/query/outlives_bounds.rs @@ -7,8 +7,7 @@ use crate::traits::query::NoSolution; use crate::ty::{self, Ty, TyCtxt}; use crate::ich::StableHashingContext; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, - StableHasherResult}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use std::mem; /// Outlives bounds are relationships between generic parameters, @@ -43,9 +42,7 @@ EnumTypeFoldableImpl! { } impl<'a, 'tcx> HashStable> for OutlivesBound<'tcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { OutlivesBound::RegionSubRegion(ref a, ref b) => { @@ -97,7 +94,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { let mut orig_values = OriginalQueryValues::default(); let key = self.canonicalize_query(¶m_env.and(ty), &mut orig_values); - let result = match self.tcx.global_tcx().implied_outlives_bounds(key) { + let result = match self.tcx.implied_outlives_bounds(key) { Ok(r) => r, Err(NoSolution) => { self.tcx.sess.delay_span_bug( diff --git a/src/librustc/traits/query/type_op/ascribe_user_type.rs b/src/librustc/traits/query/type_op/ascribe_user_type.rs index 05a4d4336a7c2..34aa4ee78da30 100644 --- a/src/librustc/traits/query/type_op/ascribe_user_type.rs +++ b/src/librustc/traits/query/type_op/ascribe_user_type.rs @@ -1,4 +1,4 @@ -use crate::infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; +use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::Fallible; use crate::hir::def_id::DefId; use crate::ty::{ParamEnvAnd, Ty, TyCtxt}; @@ -37,12 +37,6 @@ impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> { ) -> Fallible> { tcx.type_op_ascribe_user_type(canonicalized) } - - fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResponse<'tcx, ()>, - ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> { - v - } } BraceStructTypeFoldableImpl! { diff --git a/src/librustc/traits/query/type_op/eq.rs b/src/librustc/traits/query/type_op/eq.rs index e8ec304f918a3..3653f9268dcde 100644 --- a/src/librustc/traits/query/type_op/eq.rs +++ b/src/librustc/traits/query/type_op/eq.rs @@ -1,4 +1,4 @@ -use crate::infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; +use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::Fallible; use crate::ty::{ParamEnvAnd, Ty, TyCtxt}; @@ -34,12 +34,6 @@ impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> { ) -> Fallible> { tcx.type_op_eq(canonicalized) } - - fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResponse<'tcx, ()>, - ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> { - v - } } BraceStructTypeFoldableImpl! { diff --git a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs index 3beb4d64656c5..12a834fbda6bd 100644 --- a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs +++ b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs @@ -1,4 +1,4 @@ -use crate::infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; +use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::outlives_bounds::OutlivesBound; use crate::traits::query::Fallible; use crate::ty::{ParamEnvAnd, Ty, TyCtxt}; @@ -38,12 +38,6 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> { tcx.implied_outlives_bounds(canonicalized) } - - fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResponse<'tcx, Self::QueryResponse>, - ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self::QueryResponse>> { - v - } } BraceStructTypeFoldableImpl! { diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs index e2a5cd9670e0c..98e535234b630 100644 --- a/src/librustc/traits/query/type_op/mod.rs +++ b/src/librustc/traits/query/type_op/mod.rs @@ -1,6 +1,6 @@ use crate::infer::canonical::{ - Canonical, Canonicalized, CanonicalizedQueryResponse, OriginalQueryValues, - QueryRegionConstraints, QueryResponse, + Canonicalized, CanonicalizedQueryResponse, OriginalQueryValues, + QueryRegionConstraints, }; use crate::infer::{InferCtxt, InferOk}; use std::fmt; @@ -66,22 +66,6 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx { canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, ) -> Fallible>; - /// Casts a lifted query result (which is in the gcx lifetime) - /// into the tcx lifetime. This is always just an identity cast, - /// but the generic code doesn't realize it -- put another way, in - /// the generic code, we have a `Lifted<'tcx, Self::QueryResponse>` - /// and we want to convert that to a `Self::QueryResponse`. This is - /// not a priori valid, so we can't do it -- but in practice, it - /// is always a no-op (e.g., the lifted form of a type, - /// `Ty<'tcx>`, is a subtype of `Ty<'tcx>`). So we have to push - /// the operation into the impls that know more specifically what - /// `QueryResponse` is. This operation would (maybe) be nicer with - /// something like HKTs or GATs, since then we could make - /// `QueryResponse` parametric and `'tcx` and `'tcx` etc. - fn shrink_to_tcx_lifetime( - lifted_query_result: &'a CanonicalizedQueryResponse<'tcx, Self::QueryResponse>, - ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self::QueryResponse>>; - fn fully_perform_into( query_key: ParamEnvAnd<'tcx, Self>, infcx: &InferCtxt<'_, 'tcx>, @@ -99,7 +83,6 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx { let canonical_self = infcx.canonicalize_hr_query_hack(&query_key, &mut canonical_var_values); let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?; - let canonical_result = Self::shrink_to_tcx_lifetime(&canonical_result); let param_env = query_key.param_env; diff --git a/src/librustc/traits/query/type_op/normalize.rs b/src/librustc/traits/query/type_op/normalize.rs index 3fe85d8d83eb9..2138f792d45bb 100644 --- a/src/librustc/traits/query/type_op/normalize.rs +++ b/src/librustc/traits/query/type_op/normalize.rs @@ -1,4 +1,4 @@ -use crate::infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; +use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use std::fmt; use crate::traits::query::Fallible; use crate::ty::fold::TypeFoldable; @@ -38,12 +38,6 @@ where ) -> Fallible> { T::type_op_method(tcx, canonicalized) } - - fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResponse<'tcx, T>, - ) -> &'a Canonical<'tcx, QueryResponse<'tcx, T>> { - T::shrink_to_tcx_lifetime(v) - } } pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable<'tcx> + Lift<'tcx> + Copy { @@ -51,12 +45,6 @@ pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable<'tcx> + Lift<'tcx> + Cop tcx: TyCtxt<'tcx>, canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize>>, ) -> Fallible>; - - /// Converts from the `'tcx` (lifted) form of `Self` into the `tcx` - /// form of `Self`. - fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResponse<'tcx, Self>, - ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>>; } impl Normalizable<'tcx> for Ty<'tcx> { @@ -66,12 +54,6 @@ impl Normalizable<'tcx> for Ty<'tcx> { ) -> Fallible> { tcx.type_op_normalize_ty(canonicalized) } - - fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResponse<'tcx, Self>, - ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>> { - v - } } impl Normalizable<'tcx> for ty::Predicate<'tcx> { @@ -81,12 +63,6 @@ impl Normalizable<'tcx> for ty::Predicate<'tcx> { ) -> Fallible> { tcx.type_op_normalize_predicate(canonicalized) } - - fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResponse<'tcx, Self>, - ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>> { - v - } } impl Normalizable<'tcx> for ty::PolyFnSig<'tcx> { @@ -96,12 +72,6 @@ impl Normalizable<'tcx> for ty::PolyFnSig<'tcx> { ) -> Fallible> { tcx.type_op_normalize_poly_fn_sig(canonicalized) } - - fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResponse<'tcx, Self>, - ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>> { - v - } } impl Normalizable<'tcx> for ty::FnSig<'tcx> { @@ -111,12 +81,6 @@ impl Normalizable<'tcx> for ty::FnSig<'tcx> { ) -> Fallible> { tcx.type_op_normalize_fn_sig(canonicalized) } - - fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResponse<'tcx, Self>, - ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>> { - v - } } BraceStructTypeFoldableImpl! { diff --git a/src/librustc/traits/query/type_op/outlives.rs b/src/librustc/traits/query/type_op/outlives.rs index d4b36356ffb06..9b956f3e55408 100644 --- a/src/librustc/traits/query/type_op/outlives.rs +++ b/src/librustc/traits/query/type_op/outlives.rs @@ -1,4 +1,4 @@ -use crate::infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; +use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::dropck_outlives::trivial_dropck_outlives; use crate::traits::query::dropck_outlives::DropckOutlivesResult; use crate::traits::query::Fallible; @@ -53,12 +53,6 @@ impl super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> { tcx.dropck_outlives(canonicalized) } - - fn shrink_to_tcx_lifetime( - lifted_query_result: &'a CanonicalizedQueryResponse<'tcx, Self::QueryResponse>, - ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self::QueryResponse>> { - lifted_query_result - } } BraceStructTypeFoldableImpl! { diff --git a/src/librustc/traits/query/type_op/prove_predicate.rs b/src/librustc/traits/query/type_op/prove_predicate.rs index 1efe66326d724..2a908d0f66e5b 100644 --- a/src/librustc/traits/query/type_op/prove_predicate.rs +++ b/src/librustc/traits/query/type_op/prove_predicate.rs @@ -1,4 +1,4 @@ -use crate::infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; +use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::Fallible; use crate::ty::{ParamEnvAnd, Predicate, TyCtxt}; @@ -43,12 +43,6 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { ) -> Fallible> { tcx.type_op_prove_predicate(canonicalized) } - - fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResponse<'tcx, ()>, - ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> { - v - } } BraceStructTypeFoldableImpl! { diff --git a/src/librustc/traits/query/type_op/subtype.rs b/src/librustc/traits/query/type_op/subtype.rs index 71c74999c2762..c89a55daa095e 100644 --- a/src/librustc/traits/query/type_op/subtype.rs +++ b/src/librustc/traits/query/type_op/subtype.rs @@ -1,4 +1,4 @@ -use crate::infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; +use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::Fallible; use crate::ty::{ParamEnvAnd, Ty, TyCtxt}; @@ -34,12 +34,6 @@ impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> { ) -> Fallible> { tcx.type_op_subtype(canonicalized) } - - fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResponse<'tcx, ()>, - ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> { - v - } } BraceStructTypeFoldableImpl! { diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index da582c015e4ea..44d611ace77d0 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -40,9 +40,11 @@ use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable}; use crate::hir; -use rustc_data_structures::bit_set::GrowableBitSet; +use rustc_index::bit_set::GrowableBitSet; use rustc_data_structures::sync::Lock; use rustc_target::spec::abi::Abi; +use syntax::attr; +use syntax::symbol::sym; use std::cell::{Cell, RefCell}; use std::cmp; use std::fmt::{self, Display}; @@ -99,6 +101,9 @@ pub enum IntercrateAmbiguityCause { trait_desc: String, self_desc: Option, }, + ReservationImpl { + message: String + }, } impl IntercrateAmbiguityCause { @@ -134,11 +139,16 @@ impl IntercrateAmbiguityCause { String::new() }; format!( - "upstream crates may add new impl of trait `{}`{} \ + "upstream crates may add a new impl of trait `{}`{} \ in future versions", trait_desc, self_desc ) } + &IntercrateAmbiguityCause::ReservationImpl { + ref message + } => { + message.clone() + } } } } @@ -214,7 +224,7 @@ pub struct SelectionCache<'tcx> { /// of type variables - it just means the obligation isn't sufficiently /// elaborated. In that case we report an ambiguity, and the caller can /// try again after more type information has been gathered or report a -/// "type annotations required" error. +/// "type annotations needed" error. /// /// However, with type parameters, this can be a real problem - type /// parameters don't unify with regular types, but they *can* unify @@ -1326,17 +1336,38 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (result, dep_node) } - // Treat negative impls as unimplemented - fn filter_negative_impls( - &self, + // Treat negative impls as unimplemented, and reservation impls as ambiguity. + fn filter_negative_and_reservation_impls( + &mut self, candidate: SelectionCandidate<'tcx>, ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { if let ImplCandidate(def_id) = candidate { - if !self.allow_negative_impls - && self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative - { - return Err(Unimplemented); - } + let tcx = self.tcx(); + match tcx.impl_polarity(def_id) { + ty::ImplPolarity::Negative if !self.allow_negative_impls => { + return Err(Unimplemented); + } + ty::ImplPolarity::Reservation => { + if let Some(intercrate_ambiguity_clauses) + = &mut self.intercrate_ambiguity_causes + { + let attrs = tcx.get_attrs(def_id); + let attr = attr::find_by_name(&attrs, sym::rustc_reservation_impl); + let value = attr.and_then(|a| a.value_str()); + if let Some(value) = value { + debug!("filter_negative_and_reservation_impls: \ + reservation impl ambiguity on {:?}", def_id); + intercrate_ambiguity_clauses.push( + IntercrateAmbiguityCause::ReservationImpl { + message: value.to_string() + } + ); + } + } + return Ok(None); + } + _ => {} + }; } Ok(Some(candidate)) } @@ -1453,7 +1484,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Instead, we select the right impl now but report `Bar does // not implement Clone`. if candidates.len() == 1 { - return self.filter_negative_impls(candidates.pop().unwrap()); + return self.filter_negative_and_reservation_impls(candidates.pop().unwrap()); } // Winnow, but record the exact outcome of evaluation, which @@ -1528,7 +1559,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // Just one candidate left. - self.filter_negative_impls(candidates.pop().unwrap().candidate) + self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate) } fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option { @@ -1785,7 +1816,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // before we go into the whole placeholder thing, just // quickly check if the self-type is a projection at all. - match obligation.predicate.skip_binder().trait_ref.self_ty().sty { + match obligation.predicate.skip_binder().trait_ref.self_ty().kind { ty::Projection(_) | ty::Opaque(..) => {} ty::Infer(ty::TyVar(_)) => { span_bug!( @@ -1823,7 +1854,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { placeholder_trait_predicate, ); - let (def_id, substs) = match placeholder_trait_predicate.trait_ref.self_ty().sty { + let (def_id, substs) = match placeholder_trait_predicate.trait_ref.self_ty().kind { ty::Projection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs), ty::Opaque(def_id, substs) => (def_id, substs), _ => { @@ -1971,7 +2002,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // touch bound regions, they just capture the in-scope // type/region parameters. let self_ty = *obligation.self_ty().skip_binder(); - match self_ty.sty { + match self_ty.kind { ty::Generator(..) => { debug!( "assemble_generator_candidates: self_ty={:?} obligation={:?}", @@ -2014,13 +2045,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Okay to skip binder because the substs on closure types never // touch bound regions, they just capture the in-scope // type/region parameters - match obligation.self_ty().skip_binder().sty { + match obligation.self_ty().skip_binder().kind { ty::Closure(closure_def_id, closure_substs) => { debug!( "assemble_unboxed_candidates: kind={:?} obligation={:?}", kind, obligation ); - match self.infcx.closure_kind(closure_def_id, closure_substs) { + match self.infcx.closure_kind( + closure_def_id, + closure_substs + ) { Some(closure_kind) => { debug!( "assemble_unboxed_candidates: closure_kind = {:?}", @@ -2063,7 +2097,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Okay to skip binder because what we are inspecting doesn't involve bound regions let self_ty = *obligation.self_ty().skip_binder(); - match self_ty.sty { + match self_ty.kind { ty::Infer(ty::TyVar(_)) => { debug!("assemble_fn_pointer_candidates: ambiguous self-type"); candidates.ambiguous = true; // could wind up being a fn() type @@ -2125,7 +2159,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let def_id = obligation.predicate.def_id(); if self.tcx().trait_is_auto(def_id) { - match self_ty.sty { + match self_ty.kind { ty::Dynamic(..) => { // For object types, we don't know what the closed // over types are. This means we conservatively @@ -2198,7 +2232,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // self-ty here doesn't escape this probe, so just erase // any LBR. let self_ty = self.tcx().erase_late_bound_regions(&obligation.self_ty()); - let poly_trait_ref = match self_ty.sty { + let poly_trait_ref = match self_ty.kind { ty::Dynamic(ref data, ..) => { if data.auto_traits() .any(|did| did == obligation.predicate.def_id()) @@ -2294,7 +2328,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { source, target ); - let may_apply = match (&source.sty, &target.sty) { + let may_apply = match (&source.kind, &target.kind) { // Trait+Kx+'a -> Trait+Ky+'b (upcasts). (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { // Upcasts permit two things: @@ -2460,7 +2494,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if other.evaluation.must_apply_modulo_regions() { match victim.candidate { ImplCandidate(victim_def) => { - let tcx = self.tcx().global_tcx(); + let tcx = self.tcx(); return tcx.specializes((other_def, victim_def)) || tcx.impls_are_allowed_to_overlap( other_def, victim_def).is_some(); @@ -2532,7 +2566,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = self.infcx .shallow_resolve(obligation.predicate.skip_binder().self_ty()); - match self_ty.sty { + match self_ty.kind { ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) | ty::Uint(_) @@ -2598,7 +2632,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { use self::BuiltinImplConditions::{Ambiguous, None, Where}; - match self_ty.sty { + match self_ty.kind { ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) | ty::FnDef(..) @@ -2638,7 +2672,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Closure(def_id, substs) => { // (*) binder moved here Where(ty::Binder::bind( - substs.upvar_tys(def_id, self.tcx()).collect(), + substs.as_closure().upvar_tys(def_id, self.tcx()).collect(), )) } @@ -2680,7 +2714,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Zed where enum Zed { A(T), B(u32) } -> [i32, u32] /// ``` fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec> { - match t.sty { + match t.kind { ty::Uint(_) | ty::Int(_) | ty::Bool @@ -2722,11 +2756,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { tys.iter().map(|k| k.expect_ty()).collect() } - ty::Closure(def_id, ref substs) => substs.upvar_tys(def_id, self.tcx()).collect(), + ty::Closure(def_id, ref substs) => substs.as_closure() + .upvar_tys(def_id, self.tcx()) + .collect(), ty::Generator(def_id, ref substs, _) => { - let witness = substs.witness(def_id, self.tcx()); + let witness = substs.as_generator().witness(def_id, self.tcx()); substs + .as_generator() .upvar_tys(def_id, self.tcx()) .chain(iter::once(witness)) .collect() @@ -2782,7 +2819,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // binder moved -\ let ty: ty::Binder> = ty::Binder::bind(ty); // <----/ - self.infcx.in_snapshot(|_| { + self.infcx.commit_unconditionally(|_| { let (skol_ty, _) = self.infcx .replace_bound_vars_with_placeholders(&ty); let Normalized { @@ -2895,7 +2932,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) { - self.infcx.in_snapshot(|snapshot| { + self.infcx.commit_unconditionally(|snapshot| { let result = self.match_projection_obligation_against_definition_bounds( obligation, @@ -3017,19 +3054,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested, ); - let trait_obligations: Vec> = self.infcx.in_snapshot(|_| { - let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let (trait_ref, _) = self.infcx - .replace_bound_vars_with_placeholders(&poly_trait_ref); - let cause = obligation.derived_cause(ImplDerivedObligation); - self.impl_or_trait_obligations( - cause, - obligation.recursion_depth + 1, - obligation.param_env, - trait_def_id, - &trait_ref.substs, - ) - }); + let trait_obligations: Vec> = + self.infcx.commit_unconditionally(|_| { + let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); + let (trait_ref, _) = self.infcx + .replace_bound_vars_with_placeholders(&poly_trait_ref); + let cause = obligation.derived_cause(ImplDerivedObligation); + self.impl_or_trait_obligations( + cause, + obligation.recursion_depth + 1, + obligation.param_env, + trait_def_id, + &trait_ref.substs, + ) + }); // Adds the predicates from the trait. Note that this contains a `Self: Trait` // predicate as usual. It won't have any effect since auto traits are coinductive. @@ -3052,7 +3090,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // First, create the substitutions by matching the impl again, // this time not in a probe. - self.infcx.in_snapshot(|snapshot| { + self.infcx.commit_unconditionally(|snapshot| { let substs = self.rematch_impl(impl_def_id, obligation, snapshot); debug!("confirm_impl_candidate: substs={:?}", substs); let cause = obligation.derived_cause(ImplDerivedObligation); @@ -3118,7 +3156,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // results. let self_ty = self.infcx .shallow_resolve(*obligation.self_ty().skip_binder()); - let poly_trait_ref = match self_ty.sty { + let poly_trait_ref = match self_ty.kind { ty::Dynamic(ref data, ..) => data.principal().unwrap_or_else(|| { span_bug!(obligation.cause.span, "object candidate with no principal") @@ -3216,7 +3254,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation, alias_def_id ); - self.infcx.in_snapshot(|_| { + self.infcx.commit_unconditionally(|_| { let (predicate, _) = self.infcx() .replace_bound_vars_with_placeholders(&obligation.predicate); let trait_ref = predicate.trait_ref; @@ -3252,7 +3290,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // touch bound regions, they just capture the in-scope // type/region parameters. let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let (generator_def_id, substs) = match self_ty.sty { + let (generator_def_id, substs) = match self_ty.kind { ty::Generator(id, substs, _) => (id, substs), _ => bug!("closure candidate for non-closure {:?}", obligation), }; @@ -3288,8 +3326,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { )?); Ok(VtableGeneratorData { - generator_def_id: generator_def_id, - substs: substs.clone(), + generator_def_id, + substs, nested: obligations, }) } @@ -3309,7 +3347,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // touch bound regions, they just capture the in-scope // type/region parameters. let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let (closure_def_id, substs) = match self_ty.sty { + let (closure_def_id, substs) = match self_ty.kind { ty::Closure(id, substs) => (id, substs), _ => bug!("closure candidate for non-closure {:?}", obligation), }; @@ -3339,17 +3377,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { )?); // FIXME: chalk + if !self.tcx().sess.opts.debugging_opts.chalk { obligations.push(Obligation::new( obligation.cause.clone(), obligation.param_env, - ty::Predicate::ClosureKind(closure_def_id, substs, kind), + ty::Predicate::ClosureKind( + closure_def_id, + substs, + kind + ), )); } Ok(VtableClosureData { closure_def_id, - substs: substs.clone(), + substs: substs, nested: obligations, }) } @@ -3418,7 +3461,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); let mut nested = vec![]; - match (&source.sty, &target.sty) { + match (&source.kind, &target.kind) { // Trait+Kx+'a -> Trait+Ky+'b (upcasts). (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { // See assemble_candidates_for_unsizing for more info. @@ -3513,7 +3556,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // We can only make objects from sized types. let tr = ty::TraitRef { - def_id: tcx.require_lang_item(lang_items::SizedTraitLangItem), + def_id: tcx.require_lang_item(lang_items::SizedTraitLangItem, None), substs: tcx.mk_substs_trait(source, &[]), }; nested.push(predicate_to_obligation(tr.to_predicate())); @@ -3550,7 +3593,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut ty_params = GrowableBitSet::new_empty(); let mut found = false; for ty in field.walk() { - if let ty::Param(p) = ty.sty { + if let ty::Param(p) = ty.kind { ty_params.insert(p.index as usize); found = true; } @@ -3728,6 +3771,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(()); } + if self.intercrate.is_none() + && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation + { + debug!("match_impl: reservation impls only apply in intercrate mode"); + return Err(()); + } + debug!("match_impl: success impl_substs={:?}", impl_substs); Ok(Normalized { value: impl_substs, @@ -3831,7 +3881,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, closure_def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, + substs: SubstsRef<'tcx>, ) -> ty::PolyTraitRef<'tcx> { debug!( "closure_trait_ref_unnormalized(obligation={:?}, closure_def_id={:?}, substs={:?})", @@ -3863,9 +3913,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, closure_def_id: DefId, - substs: ty::GeneratorSubsts<'tcx>, + substs: SubstsRef<'tcx>, ) -> ty::PolyTraitRef<'tcx> { - let gen_sig = substs.poly_sig(closure_def_id, self.tcx()); + let gen_sig = substs.as_generator().poly_sig(closure_def_id, self.tcx()); // (1) Feels icky to skip the binder here, but OTOH we know // that the self-type is an generator type and hence is @@ -3901,7 +3951,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // each predicate must be preceded by the obligations required // to normalize it. // for example, if we have: - // impl> Foo for V where U::Item: Copy + // impl, V: Iterator> Foo for V // the impl will have the following predicates: // ::Item = U, // U: Iterator, U: Sized, diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index f0389bb037ac5..9c80ef7d4a23e 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -125,7 +125,7 @@ pub fn find_associated_item<'tcx>( let trait_def = tcx.trait_def(trait_def_id); let ancestors = trait_def.ancestors(tcx, impl_data.impl_def_id); - match ancestors.defs(tcx, item.ident, item.kind, trait_def_id).next() { + match ancestors.leaf_def(tcx, item.ident, item.kind) { Some(node_item) => { let substs = tcx.infer_ctxt().enter(|infcx| { let param_env = param_env.with_reveal_all(); diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index b43881defdb85..c64d6748ea97d 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -2,13 +2,11 @@ use super::OverlapError; use crate::hir::def_id::DefId; use crate::ich::{self, StableHashingContext}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, - StableHasherResult}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use crate::traits; use crate::ty::{self, TyCtxt, TypeFoldable}; use crate::ty::fast_reject::{self, SimplifiedType}; use syntax::ast::Ident; -use crate::util::captures::Captures; use crate::util::nodemap::{DefIdMap, FxHashMap}; /// A per-trait graph of impls in specialization order. At the moment, this @@ -85,11 +83,11 @@ impl<'tcx> Children { /// Insert an impl into this set of children without comparing to any existing impls. fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); - if let Some(sty) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { - debug!("insert_blindly: impl_def_id={:?} sty={:?}", impl_def_id, sty); - self.nonblanket_impls.entry(sty).or_default().push(impl_def_id) + if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { + debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st); + self.nonblanket_impls.entry(st).or_default().push(impl_def_id) } else { - debug!("insert_blindly: impl_def_id={:?} sty=None", impl_def_id); + debug!("insert_blindly: impl_def_id={:?} st=None", impl_def_id); self.blanket_impls.push(impl_def_id) } } @@ -100,11 +98,11 @@ impl<'tcx> Children { fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); let vec: &mut Vec; - if let Some(sty) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { - debug!("remove_existing: impl_def_id={:?} sty={:?}", impl_def_id, sty); - vec = self.nonblanket_impls.get_mut(&sty).unwrap(); + if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { + debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st); + vec = self.nonblanket_impls.get_mut(&st).unwrap(); } else { - debug!("remove_existing: impl_def_id={:?} sty=None", impl_def_id); + debug!("remove_existing: impl_def_id={:?} st=None", impl_def_id); vec = &mut self.blanket_impls; } @@ -130,7 +128,7 @@ impl<'tcx> Children { ); let possible_siblings = match simplified_self { - Some(sty) => PotentialSiblings::Filtered(self.filtered(sty)), + Some(st) => PotentialSiblings::Filtered(self.filtered(st)), None => PotentialSiblings::Unfiltered(self.iter()), }; @@ -162,7 +160,6 @@ impl<'tcx> Children { } }; - let tcx = tcx.global_tcx(); let (le, ge) = traits::overlapping_impls( tcx, possible_sibling, @@ -249,8 +246,8 @@ impl<'tcx> Children { self.blanket_impls.iter().chain(nonblanket).cloned() } - fn filtered(&mut self, sty: SimplifiedType) -> impl Iterator + '_ { - let nonblanket = self.nonblanket_impls.entry(sty).or_default().iter(); + fn filtered(&mut self, st: SimplifiedType) -> impl Iterator + '_ { + let nonblanket = self.nonblanket_impls.entry(st).or_default().iter(); self.blanket_impls.iter().chain(nonblanket).cloned() } } @@ -395,7 +392,7 @@ impl<'tcx> Graph { /// The parent of a given impl, which is the `DefId` of the trait when the /// impl is a "specialization root". pub fn parent(&self, child: DefId) -> DefId { - *self.parent.get(&child).unwrap() + *self.parent.get(&child).unwrap_or_else(|| panic!("Failed to get parent for {:?}", child)) } } @@ -421,6 +418,35 @@ impl<'tcx> Node { tcx.associated_items(self.def_id()) } + /// Finds an associated item defined in this node. + /// + /// If this returns `None`, the item can potentially still be found in + /// parents of this node. + pub fn item( + &self, + tcx: TyCtxt<'tcx>, + trait_item_name: Ident, + trait_item_kind: ty::AssocKind, + trait_def_id: DefId, + ) -> Option { + use crate::ty::AssocKind::*; + + tcx.associated_items(self.def_id()) + .find(move |impl_item| match (trait_item_kind, impl_item.kind) { + | (Const, Const) + | (Method, Method) + | (Type, Type) + | (Type, OpaqueTy) // assoc. types can be made opaque in impls + => tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id), + + | (Const, _) + | (Method, _) + | (Type, _) + | (OpaqueTy, _) + => false, + }) + } + pub fn def_id(&self) -> DefId { match *self { Node::Impl(did) => did, @@ -429,6 +455,7 @@ impl<'tcx> Node { } } +#[derive(Copy, Clone)] pub struct Ancestors<'tcx> { trait_def_id: DefId, specialization_graph: &'tcx Graph, @@ -467,32 +494,18 @@ impl NodeItem { } impl<'tcx> Ancestors<'tcx> { - /// Search the items from the given ancestors, returning each definition - /// with the given name and the given kind. - // FIXME(#35870): avoid closures being unexported due to `impl Trait`. - #[inline] - pub fn defs( - self, + /// Finds the bottom-most (ie. most specialized) definition of an associated + /// item. + pub fn leaf_def( + mut self, tcx: TyCtxt<'tcx>, trait_item_name: Ident, trait_item_kind: ty::AssocKind, - trait_def_id: DefId, - ) -> impl Iterator> + Captures<'tcx> + 'tcx { - self.flat_map(move |node| { - use crate::ty::AssocKind::*; - node.items(tcx).filter(move |impl_item| match (trait_item_kind, impl_item.kind) { - | (Const, Const) - | (Method, Method) - | (Type, Type) - | (Type, OpaqueTy) - => tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id), - - | (Const, _) - | (Method, _) - | (Type, _) - | (OpaqueTy, _) - => false, - }).map(move |item| NodeItem { node: node, item: item }) + ) -> Option> { + let trait_def_id = self.trait_def_id; + self.find_map(|node| { + node.item(tcx, trait_item_name, trait_item_kind, trait_def_id) + .map(|item| NodeItem { node, item }) }) } } @@ -513,9 +526,7 @@ pub fn ancestors( } impl<'a> HashStable> for Children { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let Children { ref nonblanket_impls, ref blanket_impls, diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 129a400d28f4c..dab62a6bcb5b1 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -312,7 +312,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector { } fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.sty { + match t.kind { ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { self.types.insert( bound_ty.var.as_u32(), @@ -472,6 +472,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::TupleElem => Some(super::TupleElem), super::ProjectionWf(proj) => tcx.lift(&proj).map(super::ProjectionWf), super::ItemObligation(def_id) => Some(super::ItemObligation(def_id)), + super::BindingObligation(def_id, span) => Some(super::BindingObligation(def_id, span)), super::ReferenceOutlivesReferent(ty) => { tcx.lift(&ty).map(super::ReferenceOutlivesReferent) } @@ -484,7 +485,8 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::TupleInitializerSized => Some(super::TupleInitializerSized), super::StructInitializerSized => Some(super::StructInitializerSized), super::VariableType(id) => Some(super::VariableType(id)), - super::ReturnType(id) => Some(super::ReturnType(id)), + super::ReturnValue(id) => Some(super::ReturnValue(id)), + super::ReturnType => Some(super::ReturnType), super::SizedArgumentType => Some(super::SizedArgumentType), super::SizedReturnType => Some(super::SizedReturnType), super::SizedYieldType => Some(super::SizedYieldType), @@ -508,31 +510,33 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { trait_item_def_id, }), super::ExprAssignable => Some(super::ExprAssignable), - super::MatchExpressionArm { + super::MatchExpressionArm(box super::MatchExpressionArmCause { arm_span, source, ref prior_arms, last_ty, discrim_hir_id, - } => { + }) => { tcx.lift(&last_ty).map(|last_ty| { - super::MatchExpressionArm { + super::MatchExpressionArm(box super::MatchExpressionArmCause { arm_span, source, prior_arms: prior_arms.clone(), last_ty, discrim_hir_id, - } + }) }) } super::MatchExpressionArmPattern { span, ty } => { tcx.lift(&ty).map(|ty| super::MatchExpressionArmPattern { span, ty }) } - super::IfExpression { then, outer, semicolon } => Some(super::IfExpression { - then, - outer, - semicolon, - }), + super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }) => { + Some(super::IfExpression(box super::IfExpressionCause { + then, + outer, + semicolon, + })) + } super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse), super::MainFunctionType => Some(super::MainFunctionType), super::StartFunctionType => Some(super::StartFunctionType), @@ -980,8 +984,7 @@ EnumTypeFoldableImpl! { (chalk_engine::DelayedLiteral::Negative)(a), (chalk_engine::DelayedLiteral::Positive)(a, b), } where - C: chalk_engine::context::Context + Clone, - C::CanonicalConstrainedSubst: TypeFoldable<'tcx>, + C: chalk_engine::context::Context> + Clone, } EnumTypeFoldableImpl! { @@ -989,8 +992,7 @@ EnumTypeFoldableImpl! { (chalk_engine::Literal::Negative)(a), (chalk_engine::Literal::Positive)(a), } where - C: chalk_engine::context::Context + Clone, - C::GoalInEnvironment: Clone + TypeFoldable<'tcx>, + C: chalk_engine::context::Context> + Clone, } CloneTypeFoldableAndLiftImpls! { diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 07d6f633143a2..d8b1effe09bf4 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -4,10 +4,9 @@ use syntax_pos::Span; use crate::hir; use crate::hir::def_id::DefId; -use crate::traits::specialize::specialization_graph::NodeItem; use crate::ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef}; use crate::ty::outlives::Component; -use crate::ty::subst::{Kind, Subst, SubstsRef}; +use crate::ty::subst::{GenericArg, Subst, SubstsRef}; use crate::util::nodemap::FxHashSet; use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized}; @@ -512,21 +511,20 @@ pub fn impl_trait_ref_and_oblig<'a, 'tcx>( (impl_trait_ref, impl_obligations) } -/// See `super::obligations_for_generics` -pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, - recursion_depth: usize, - param_env: ty::ParamEnv<'tcx>, - generic_bounds: &ty::InstantiatedPredicates<'tcx>) - -> Vec> -{ - debug!("predicates_for_generics(generic_bounds={:?})", - generic_bounds); - - generic_bounds.predicates.iter().map(|predicate| { - Obligation { cause: cause.clone(), - recursion_depth, - param_env, - predicate: predicate.clone() } +/// See [`super::obligations_for_generics`]. +pub fn predicates_for_generics<'tcx>( + cause: ObligationCause<'tcx>, + recursion_depth: usize, + param_env: ty::ParamEnv<'tcx>, + generic_bounds: &ty::InstantiatedPredicates<'tcx>, +) -> Vec> { + debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds); + + generic_bounds.predicates.iter().map(|predicate| Obligation { + cause: cause.clone(), + recursion_depth, + param_env, + predicate: predicate.clone(), }).collect() } @@ -552,7 +550,7 @@ impl<'tcx> TyCtxt<'tcx> { trait_def_id: DefId, recursion_depth: usize, self_ty: Ty<'tcx>, - params: &[Kind<'tcx>]) + params: &[GenericArg<'tcx>]) -> PredicateObligation<'tcx> { let trait_ref = ty::TraitRef { @@ -562,7 +560,7 @@ impl<'tcx> TyCtxt<'tcx> { predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth) } - /// Cast a trait reference into a reference to one of its super + /// Casts a trait reference into a reference to one of its super /// traits; returns `None` if `target_trait_def_id` is not a /// supertrait. pub fn upcast_choices(self, @@ -571,7 +569,7 @@ impl<'tcx> TyCtxt<'tcx> { -> Vec> { if source_trait_ref.def_id() == target_trait_def_id { - return vec![source_trait_ref]; // shorcut the most common case + return vec![source_trait_ref]; // Shortcut the most common case. } supertraits(self, source_trait_ref) @@ -655,22 +653,21 @@ impl<'tcx> TyCtxt<'tcx> { match self.hir().as_local_hir_id(node_item_def_id) { Some(hir_id) => { let item = self.hir().expect_item(hir_id); - if let hir::ItemKind::Impl(_, _, defaultness, ..) = item.node { + if let hir::ItemKind::Impl(_, _, defaultness, ..) = item.kind { defaultness.is_default() } else { false } } None => { - self.global_tcx() - .impl_defaultness(node_item_def_id) + self.impl_defaultness(node_item_def_id) .is_default() } } } - pub fn impl_item_is_final(self, node_item: &NodeItem) -> bool { - node_item.item.is_final() && !self.impl_is_default(node_item.node.def_id()) + pub fn impl_item_is_final(self, assoc_item: &ty::AssocItem) -> bool { + assoc_item.defaultness.is_final() && !self.impl_is_default(assoc_item.container.id()) } } diff --git a/src/librustc/ty/_match.rs b/src/librustc/ty/_match.rs index f800a70e0becf..a0d22789dae35 100644 --- a/src/librustc/ty/_match.rs +++ b/src/librustc/ty/_match.rs @@ -59,7 +59,7 @@ impl TypeRelation<'tcx> for Match<'tcx> { a, b); if a == b { return Ok(a); } - match (&a.sty, &b.sty) { + match (&a.kind, &b.kind) { (_, &ty::Infer(ty::FreshTy(_))) | (_, &ty::Infer(ty::FreshIntTy(_))) | (_, &ty::Infer(ty::FreshFloatTy(_))) => { diff --git a/src/librustc/ty/cast.rs b/src/librustc/ty/cast.rs index 7ea5c73c5b749..bc12412312deb 100644 --- a/src/librustc/ty/cast.rs +++ b/src/librustc/ty/cast.rs @@ -52,7 +52,7 @@ impl<'tcx> CastTy<'tcx> { /// Returns `Some` for integral/pointer casts. /// casts like unsizing casts will return `None` pub fn from_ty(t: Ty<'tcx>) -> Option> { - match t.sty { + match t.kind { ty::Bool => Some(CastTy::Int(IntTy::Bool)), ty::Char => Some(CastTy::Int(IntTy::Char)), ty::Int(_) => Some(CastTy::Int(IntTy::I)), diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs index e3c6eca02d554..bd4913c88fd1f 100644 --- a/src/librustc/ty/codec.rs +++ b/src/librustc/ty/codec.rs @@ -27,11 +27,11 @@ pub trait EncodableWithShorthand: Clone + Eq + Hash { fn variant(&self) -> &Self::Variant; } -#[cfg_attr(not(bootstrap), allow(rustc::usage_of_ty_tykind))] +#[allow(rustc::usage_of_ty_tykind)] impl<'tcx> EncodableWithShorthand for Ty<'tcx> { type Variant = ty::TyKind<'tcx>; fn variant(&self) -> &Self::Variant { - &self.sty + &self.kind } } @@ -160,7 +160,7 @@ where Ok(decoder.map_encoded_cnum_to_current(cnum)) } -#[cfg_attr(not(bootstrap), allow(rustc::usage_of_ty_tykind))] +#[allow(rustc::usage_of_ty_tykind)] #[inline] pub fn decode_ty(decoder: &mut D) -> Result, D::Error> where @@ -284,9 +284,11 @@ where #[macro_export] macro_rules! __impl_decoder_methods { ($($name:ident -> $ty:ty;)*) => { - $(fn $name(&mut self) -> Result<$ty, Self::Error> { - self.opaque.$name() - })* + $( + fn $name(&mut self) -> Result<$ty, Self::Error> { + self.opaque.$name() + } + )* } } @@ -327,14 +329,17 @@ macro_rules! impl_arena_allocatable_decoders { macro_rules! implement_ty_decoder { ($DecoderName:ident <$($typaram:tt),*>) => { mod __ty_decoder_impl { - use super::$DecoderName; + use std::borrow::Cow; + + use rustc_serialize::{Decoder, SpecializedDecoder}; + use $crate::infer::canonical::CanonicalVarInfos; use $crate::ty; use $crate::ty::codec::*; use $crate::ty::subst::SubstsRef; use $crate::hir::def_id::{CrateNum}; - use rustc_serialize::{Decoder, SpecializedDecoder}; - use std::borrow::Cow; + + use super::$DecoderName; impl<$($typaram ),*> Decoder for $DecoderName<$($typaram),*> { type Error = String; @@ -368,8 +373,8 @@ macro_rules! implement_ty_decoder { } } - // FIXME(#36588) These impls are horribly unsound as they allow - // the caller to pick any lifetime for 'tcx, including 'static, + // FIXME(#36588): These impls are horribly unsound as they allow + // the caller to pick any lifetime for `'tcx`, including `'static`, // by using the unspecialized proxies to them. arena_types!(impl_arena_allocatable_decoders, [$DecoderName [$($typaram),*]], 'tcx); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index dadc126eba48e..cd52f8fa92c5a 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -7,7 +7,7 @@ use crate::session::Session; use crate::session::config::{BorrowckMode, OutputFilenames}; use crate::session::config::CrateType; use crate::middle; -use crate::hir::{TraitCandidate, HirId, ItemKind, ItemLocalId, Node}; +use crate::hir::{self, TraitCandidate, HirId, ItemKind, ItemLocalId, Node}; use crate::hir::def::{Res, DefKind, Export}; use crate::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use crate::hir::map as hir_map; @@ -21,15 +21,15 @@ use crate::middle::cstore::EncodedMetadata; use crate::middle::lang_items; use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use crate::middle::stability; -use crate::mir::{Body, interpret, ProjectionKind}; +use crate::mir::{Body, interpret, ProjectionKind, Promoted}; use crate::mir::interpret::{ConstValue, Allocation, Scalar}; -use crate::ty::subst::{Kind, InternalSubsts, SubstsRef, Subst}; +use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef, Subst}; use crate::ty::ReprOptions; use crate::traits; use crate::traits::{Clause, Clauses, GoalKind, Goal, Goals}; use crate::ty::{self, DefIdTree, Ty, TypeAndMut}; use crate::ty::{TyS, TyKind, List}; -use crate::ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorSubsts, Region, Const}; +use crate::ty::{AdtKind, AdtDef, Region, Const}; use crate::ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predicate}; use crate::ty::RegionKind; use crate::ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid, ConstVid}; @@ -39,21 +39,23 @@ use crate::ty::GenericParamDefKind; use crate::ty::layout::{LayoutDetails, TargetDataLayout, VariantIdx}; use crate::ty::query; use crate::ty::steal::Steal; -use crate::ty::subst::{UserSubsts, UnpackedKind}; +use crate::ty::subst::{UserSubsts, GenericArgKind}; use crate::ty::{BoundVar, BindingMode}; use crate::ty::CanonicalPolyFnSig; use crate::util::common::ErrorReported; use crate::util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap, ItemLocalSet}; use crate::util::nodemap::{FxHashMap, FxHashSet}; +use crate::util::profiling::SelfProfilerRef; + use errors::DiagnosticBuilder; -use smallvec::SmallVec; -use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap, - StableHasher, StableHasherResult, - StableVec}; use arena::SyncDroplessArena; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal}; +use smallvec::SmallVec; +use rustc_data_structures::stable_hasher::{ + HashStable, StableHasher, StableVec, hash_stable_hashmap, +}; +use rustc_index::vec::{Idx, IndexVec}; use rustc_data_structures::sharded::ShardedHashMap; +use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal}; use std::any::Any; use std::borrow::Borrow; use std::cmp::Ordering; @@ -63,7 +65,6 @@ use std::fmt; use std::mem; use std::ops::{Deref, Bound}; use std::iter; -use std::sync::mpsc; use std::sync::Arc; use rustc_target::spec::abi; use rustc_macros::HashStable; @@ -74,8 +75,6 @@ use syntax::feature_gate; use syntax::symbol::{Symbol, InternedString, kw, sym}; use syntax_pos::Span; -use crate::hir; - pub struct AllArenas { pub interner: SyncDroplessArena, } @@ -91,10 +90,10 @@ impl AllArenas { type InternedSet<'tcx, T> = ShardedHashMap, ()>; pub struct CtxtInterners<'tcx> { - /// The arena that types, regions, etc are allocated from + /// The arena that types, regions, etc. are allocated from. arena: &'tcx SyncDroplessArena, - /// Specifically use a speedy hash algorithm for these hash sets, + /// Specifically use a speedy hash algorithm for these hash sets, since /// they're accessed quite often. type_: InternedSet<'tcx, TyS<'tcx>>, type_list: InternedSet<'tcx, List>>, @@ -129,22 +128,21 @@ impl<'tcx> CtxtInterners<'tcx> { } } - /// Intern a type - #[cfg_attr(not(bootstrap), allow(rustc::usage_of_ty_tykind))] + /// Interns a type. + #[allow(rustc::usage_of_ty_tykind)] #[inline(never)] fn intern_ty(&self, - st: TyKind<'tcx> + kind: TyKind<'tcx> ) -> Ty<'tcx> { - self.type_.intern(st, |st| { - let flags = super::flags::FlagComputation::for_sty(&st); + self.type_.intern(kind, |kind| { + let flags = super::flags::FlagComputation::for_kind(&kind); let ty_struct = TyS { - sty: st, + kind, flags: flags.flags, outer_exclusive_binder: flags.outer_exclusive_binder, }; - Interned(self.arena.alloc(ty_struct)) }).0 } @@ -173,6 +171,7 @@ pub struct CommonTypes<'tcx> { pub f32: Ty<'tcx>, pub f64: Ty<'tcx>, pub never: Ty<'tcx>, + pub self_param: Ty<'tcx>, pub err: Ty<'tcx>, /// Dummy type used for the `Self` of a `TraitRef` created for converting @@ -206,26 +205,24 @@ pub struct LocalTableInContext<'a, V> { fn validate_hir_id_for_typeck_tables(local_id_root: Option, hir_id: hir::HirId, mut_access: bool) { - if cfg!(debug_assertions) { - if let Some(local_id_root) = local_id_root { - if hir_id.owner != local_id_root.index { - ty::tls::with(|tcx| { - bug!("node {} with HirId::owner {:?} cannot be placed in \ - TypeckTables with local_id_root {:?}", - tcx.hir().node_to_string(hir_id), - DefId::local(hir_id.owner), - local_id_root) - }); - } - } else { - // We use "Null Object" TypeckTables in some of the analysis passes. - // These are just expected to be empty and their `local_id_root` is - // `None`. Therefore we cannot verify whether a given `HirId` would - // be a valid key for the given table. Instead we make sure that - // nobody tries to write to such a Null Object table. - if mut_access { - bug!("access to invalid TypeckTables") - } + if let Some(local_id_root) = local_id_root { + if hir_id.owner != local_id_root.index { + ty::tls::with(|tcx| { + bug!("node {} with HirId::owner {:?} cannot be placed in \ + TypeckTables with local_id_root {:?}", + tcx.hir().node_to_string(hir_id), + DefId::local(hir_id.owner), + local_id_root) + }); + } + } else { + // We use "Null Object" TypeckTables in some of the analysis passes. + // These are just expected to be empty and their `local_id_root` is + // `None`. Therefore we cannot verify whether a given `HirId` would + // be a valid key for the given table. Instead we make sure that + // nobody tries to write to such a Null Object table. + if mut_access { + bug!("access to invalid TypeckTables") } } } @@ -292,6 +289,40 @@ pub struct ResolvedOpaqueTy<'tcx> { pub substs: SubstsRef<'tcx>, } +/// Whenever a value may be live across a generator yield, the type of that value winds up in the +/// `GeneratorInteriorTypeCause` struct. This struct adds additional information about such +/// captured types that can be useful for diagnostics. In particular, it stores the span that +/// caused a given type to be recorded, along with the scope that enclosed the value (which can +/// be used to find the await that the value is live across). +/// +/// For example: +/// +/// ```ignore (pseudo-Rust) +/// async move { +/// let x: T = ...; +/// foo.await +/// ... +/// } +/// ``` +/// +/// Here, we would store the type `T`, the span of the value `x`, and the "scope-span" for +/// the scope that contains `x`. +#[derive(RustcEncodable, RustcDecodable, Clone, Debug, Eq, Hash, HashStable, PartialEq)] +pub struct GeneratorInteriorTypeCause<'tcx> { + /// Type of the captured binding. + pub ty: Ty<'tcx>, + /// Span of the binding that was captured. + pub span: Span, + /// Span of the scope of the captured binding. + pub scope_span: Option, +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for GeneratorInteriorTypeCause<'tcx> { + ty, span, scope_span + } +} + #[derive(RustcEncodable, RustcDecodable, Debug)] pub struct TypeckTables<'tcx> { /// The HirId::owner all ItemLocalIds in this table are relative to. @@ -401,6 +432,10 @@ pub struct TypeckTables<'tcx> { /// leading to the member of the struct or tuple that is used instead of the /// entire variable. pub upvar_list: ty::UpvarListMap, + + /// Stores the type, span and optional scope span of all types + /// that are live across the yield of this generator (if a generator). + pub generator_interior_types: Vec>, } impl<'tcx> TypeckTables<'tcx> { @@ -426,6 +461,7 @@ impl<'tcx> TypeckTables<'tcx> { free_region_map: Default::default(), concrete_opaque_types: Default::default(), upvar_list: Default::default(), + generator_interior_types: Default::default(), } } @@ -607,7 +643,7 @@ impl<'tcx> TypeckTables<'tcx> { pub fn is_method_call(&self, expr: &hir::Expr) -> bool { // Only paths and method calls/overloaded operators have // entries in type_dependent_defs, ignore the former here. - if let hir::ExprKind::Path(_) = expr.node { + if let hir::ExprKind::Path(_) = expr.kind { return false; } @@ -709,9 +745,7 @@ impl<'tcx> TypeckTables<'tcx> { } impl<'a, 'tcx> HashStable> for TypeckTables<'tcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ty::TypeckTables { local_id_root, ref type_dependent_defs, @@ -735,6 +769,7 @@ impl<'a, 'tcx> HashStable> for TypeckTables<'tcx> { ref free_region_map, ref concrete_opaque_types, ref upvar_list, + ref generator_interior_types, } = *self; @@ -779,11 +814,12 @@ impl<'a, 'tcx> HashStable> for TypeckTables<'tcx> { free_region_map.hash_stable(hcx, hasher); concrete_opaque_types.hash_stable(hcx, hasher); upvar_list.hash_stable(hcx, hasher); + generator_interior_types.hash_stable(hcx, hasher); }) } } -newtype_index! { +rustc_index::newtype_index! { pub struct UserTypeAnnotationIndex { derive [HashStable] DEBUG_FORMAT = "UserType({})", @@ -831,7 +867,7 @@ impl CanonicalUserType<'tcx> { user_substs.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| { match kind.unpack() { - UnpackedKind::Type(ty) => match ty.sty { + GenericArgKind::Type(ty) => match ty.kind { ty::Bound(debruijn, b) => { // We only allow a `ty::INNERMOST` index in substitutions. assert_eq!(debruijn, ty::INNERMOST); @@ -840,7 +876,7 @@ impl CanonicalUserType<'tcx> { _ => false, }, - UnpackedKind::Lifetime(r) => match r { + GenericArgKind::Lifetime(r) => match r { ty::ReLateBound(debruijn, br) => { // We only allow a `ty::INNERMOST` index in substitutions. assert_eq!(*debruijn, ty::INNERMOST); @@ -849,7 +885,7 @@ impl CanonicalUserType<'tcx> { _ => false, }, - UnpackedKind::Const(ct) => match ct.val { + GenericArgKind::Const(ct) => match ct.val { ConstValue::Infer(InferConst::Canonical(debruijn, b)) => { // We only allow a `ty::INNERMOST` index in substitutions. assert_eq!(debruijn, ty::INNERMOST); @@ -893,7 +929,7 @@ EnumLiftImpl! { impl<'tcx> CommonTypes<'tcx> { fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> { - let mk = |sty| interners.intern_ty(sty); + let mk = |ty| interners.intern_ty(ty); CommonTypes { unit: mk(Tuple(List::empty())), @@ -915,6 +951,10 @@ impl<'tcx> CommonTypes<'tcx> { u128: mk(Uint(ast::UintTy::U128)), f32: mk(Float(ast::FloatTy::F32)), f64: mk(Float(ast::FloatTy::F64)), + self_param: mk(ty::Param(ty::ParamTy { + index: 0, + name: kw::SelfUpper.as_interned_str(), + })), trait_object_dummy_self: mk(Infer(ty::FreshTy(0))), } @@ -973,6 +1013,7 @@ pub struct FreeRegionInfo { /// /// [rustc guide]: https://rust-lang.github.io/rustc-guide/ty.html #[derive(Copy, Clone)] +#[rustc_diagnostic_item = "TyCtxt"] pub struct TyCtxt<'tcx> { gcx: &'tcx GlobalCtxt<'tcx>, } @@ -996,6 +1037,8 @@ pub struct GlobalCtxt<'tcx> { pub dep_graph: DepGraph, + pub prof: SelfProfilerRef, + /// Common objects. pub common: Common<'tcx>, @@ -1019,7 +1062,7 @@ pub struct GlobalCtxt<'tcx> { hir_map: hir_map::Map<'tcx>, - /// A map from DefPathHash -> DefId. Includes DefIds from the local crate + /// A map from `DefPathHash` -> `DefId`. Includes `DefId`s from the local crate /// as well as all upstream crates. Only populated in incremental mode. pub def_path_hash_to_def_id: Option>, @@ -1062,26 +1105,10 @@ pub struct GlobalCtxt<'tcx> { layout_interner: ShardedHashMap<&'tcx LayoutDetails, ()>, - /// A general purpose channel to throw data out the back towards LLVM worker - /// threads. - /// - /// This is intended to only get used during the codegen phase of the compiler - /// when satisfying the query for a particular codegen unit. Internally in - /// the query it'll send data along this channel to get processed later. - pub tx_to_llvm_workers: Lock>>, - output_filenames: Arc, } impl<'tcx> TyCtxt<'tcx> { - /// Gets the global `TyCtxt`. - #[inline] - pub fn global_tcx(self) -> TyCtxt<'tcx> { - TyCtxt { - gcx: self.gcx, - } - } - #[inline(always)] pub fn hir(self) -> &'tcx hir_map::Map<'tcx> { &self.hir_map @@ -1091,6 +1118,16 @@ impl<'tcx> TyCtxt<'tcx> { self.arena.alloc(Steal::new(mir)) } + pub fn alloc_steal_promoted(self, promoted: IndexVec>) -> + &'tcx Steal>> { + self.arena.alloc(Steal::new(promoted)) + } + + pub fn intern_promoted(self, promoted: IndexVec>) -> + &'tcx IndexVec> { + self.arena.alloc(promoted) + } + pub fn alloc_adt_def( self, did: DefId, @@ -1108,9 +1145,9 @@ impl<'tcx> TyCtxt<'tcx> { }) } - /// Allocates a byte or string literal for `mir::interpret`, read-only + /// Allocates a read-only byte or string literal for `mir::interpret`. pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId { - // create an allocation that just contains these bytes + // Create an allocation that just contains these bytes. let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes); let alloc = self.intern_const_alloc(alloc); self.alloc_map.lock().create_memory_alloc(alloc) @@ -1138,7 +1175,7 @@ impl<'tcx> TyCtxt<'tcx> { None => return Bound::Unbounded, }; for meta in attr.meta_item_list().expect("rustc_layout_scalar_valid_range takes args") { - match meta.literal().expect("attribute takes lit").node { + match meta.literal().expect("attribute takes lit").kind { ast::LitKind::Int(a, _) => return Bound::Included(a), _ => span_bug!(attr.span, "rustc_layout_scalar_valid_range expects int arg"), } @@ -1153,11 +1190,6 @@ impl<'tcx> TyCtxt<'tcx> { value.lift_to_tcx(self) } - /// Like lift, but only tries in the global tcx. - pub fn lift_to_global>(self, value: &T) -> Option { - value.lift_to_tcx(self.global_tcx()) - } - /// Creates a type context and call the closure with a `TyCtxt` reference /// to the context. The closure enforces that the type context and any interned /// value (types, substs, etc.) can only be used while `ty::tls` has a valid @@ -1172,7 +1204,6 @@ impl<'tcx> TyCtxt<'tcx> { hir: hir_map::Map<'tcx>, on_disk_query_result_cache: query::OnDiskCache<'tcx>, crate_name: &str, - tx: mpsc::Sender>, output_filenames: &OutputFilenames, ) -> GlobalCtxt<'tcx> { let data_layout = TargetDataLayout::parse(&s.target.target).unwrap_or_else(|err| { @@ -1238,6 +1269,7 @@ impl<'tcx> TyCtxt<'tcx> { arena: WorkerLocal::new(|_| Arena::default()), interners, dep_graph, + prof: s.prof.clone(), common, types: common_types, lifetimes: common_lifetimes, @@ -1279,7 +1311,6 @@ impl<'tcx> TyCtxt<'tcx> { stability_interner: Default::default(), allocation_interner: Default::default(), alloc_map: Lock::new(interpret::AllocMap::new()), - tx_to_llvm_workers: Lock::new(tx), output_filenames: Arc::new(output_filenames.clone()), } } @@ -1293,10 +1324,22 @@ impl<'tcx> TyCtxt<'tcx> { self.get_lib_features(LOCAL_CRATE) } + /// Obtain all lang items of this crate and all dependencies (recursively) pub fn lang_items(self) -> &'tcx middle::lang_items::LanguageItems { self.get_lang_items(LOCAL_CRATE) } + /// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to + /// compare against another `DefId`, since `is_diagnostic_item` is cheaper. + pub fn get_diagnostic_item(self, name: Symbol) -> Option { + self.all_diagnostic_items(LOCAL_CRATE).get(&name).copied() + } + + /// Check whether the diagnostic item with the given `name` has the given `DefId`. + pub fn is_diagnostic_item(self, name: Symbol, did: DefId) -> bool { + self.diagnostic_items(did.krate).get(&name) == Some(&did) + } + pub fn stability(self) -> &'tcx stability::Index<'tcx> { self.stability_index(LOCAL_CRATE) } @@ -1318,7 +1361,7 @@ impl<'tcx> TyCtxt<'tcx> { } /// Converts a `DefId` into its fully expanded `DefPath` (every - /// `DefId` is really just an interned def-path). + /// `DefId` is really just an interned `DefPath`). /// /// Note that if `id` is not local to this crate, the result will /// be a non-local `DefPath`. @@ -1374,6 +1417,10 @@ impl<'tcx> TyCtxt<'tcx> { self.cstore.metadata_encoding_version().to_vec() } + pub fn encode_metadata(self)-> EncodedMetadata { + self.cstore.encode_metadata(self) + } + // Note that this is *untracked* and should only be used within the query // system if the result is otherwise tracked through queries pub fn crate_data_as_rc_any(self, cnum: CrateNum) -> Lrc { @@ -1415,28 +1462,22 @@ impl<'tcx> TyCtxt<'tcx> { -> Result<(), E::Error> where E: ty::codec::TyEncoder { - self.queries.on_disk_cache.serialize(self.global_tcx(), encoder) - } - - /// If true, we should use the AST-based borrowck (we may *also* use - /// the MIR-based borrowck). - pub fn use_ast_borrowck(self) -> bool { - self.borrowck_mode().use_ast() + self.queries.on_disk_cache.serialize(self, encoder) } - /// If true, we should use the MIR-based borrow check, but also - /// fall back on the AST borrow check if the MIR-based one errors. + /// If `true`, we should use the MIR-based borrowck, but also + /// fall back on the AST borrowck if the MIR-based one errors. pub fn migrate_borrowck(self) -> bool { self.borrowck_mode().migrate() } - /// If true, make MIR codegen for `match` emit a temp that holds a + /// If `true`, make MIR codegen for `match` emit a temp that holds a /// borrow of the input to the match expression. pub fn generate_borrow_of_any_match_input(&self) -> bool { self.emit_read_for_match() } - /// If true, make MIR codegen for `match` emit FakeRead + /// If `true`, make MIR codegen for `match` emit FakeRead /// statements (which simulate the maximal effect of executing the /// patterns in a match arm). pub fn emit_read_for_match(&self) -> bool { @@ -1482,14 +1523,14 @@ impl<'tcx> TyCtxt<'tcx> { CrateType::Executable | CrateType::Staticlib | CrateType::ProcMacro | + CrateType::Dylib | CrateType::Cdylib => false, - CrateType::Rlib | - CrateType::Dylib => true, + CrateType::Rlib => true, } }) } - // This method returns the DefId and the BoundRegion corresponding to the given region. + // Returns the `DefId` and the `BoundRegion` corresponding to the given region. pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option { let (suitable_region_binding_scope, bound_region) = match *region { ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region), @@ -1522,22 +1563,22 @@ impl<'tcx> TyCtxt<'tcx> { &self, scope_def_id: DefId, ) -> Option> { - // HACK: `type_of_def_id()` will fail on these (#55796), so return None + // HACK: `type_of_def_id()` will fail on these (#55796), so return `None`. let hir_id = self.hir().as_local_hir_id(scope_def_id).unwrap(); match self.hir().get(hir_id) { Node::Item(item) => { - match item.node { - ItemKind::Fn(..) => { /* type_of_def_id() will work */ } + match item.kind { + ItemKind::Fn(..) => { /* `type_of_def_id()` will work */ } _ => { return None; } } } - _ => { /* type_of_def_id() will work or panic */ } + _ => { /* `type_of_def_id()` will work or panic */ } } let ret_ty = self.type_of(scope_def_id); - match ret_ty.sty { + match ret_ty.kind { ty::FnDef(_, _) => { let sig = ret_ty.fn_sig(*self); let output = self.erase_late_bound_regions(&sig.output()); @@ -1551,7 +1592,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - // Here we check if the bound region is in Impl Item. + // Checks if the bound region is in Impl Item. pub fn is_bound_region_in_impl_item( &self, suitable_region_binding_scope: DefId, @@ -1571,23 +1612,15 @@ impl<'tcx> TyCtxt<'tcx> { false } - /// Determine whether identifiers in the assembly have strict naming rules. + /// Determines whether identifiers in the assembly have strict naming rules. /// Currently, only NVPTX* targets need it. pub fn has_strict_asm_symbol_naming(&self) -> bool { - self.gcx.sess.target.target.arch.contains("nvptx") - } -} - -impl<'tcx> TyCtxt<'tcx> { - pub fn encode_metadata(self) - -> EncodedMetadata - { - self.cstore.encode_metadata(self) + self.sess.target.target.arch.contains("nvptx") } } impl<'tcx> GlobalCtxt<'tcx> { - /// Call the closure with a local `TyCtxt` using the given arena. + /// Calls the closure with a local `TyCtxt` using the given arena. /// `interners` is a slot passed so we can create a CtxtInterners /// with the same lifetime as `arena`. pub fn enter_local(&'tcx self, f: F) -> R @@ -1597,7 +1630,7 @@ impl<'tcx> GlobalCtxt<'tcx> { let tcx = TyCtxt { gcx: self, }; - ty::tls::with_related_context(tcx.global_tcx(), |icx| { + ty::tls::with_related_context(tcx, |icx| { let new_icx = ty::tls::ImplicitCtxt { tcx, query: icx.query.clone(), @@ -1623,7 +1656,7 @@ impl<'tcx> GlobalCtxt<'tcx> { /// It would be more efficient if `TypedArena` provided a way to /// determine whether the address is in the allocated range. /// -/// None is returned if the value or one of the components is not part +/// `None` is returned if the value or one of the components is not part /// of the provided context. /// For `Ty`, `None` can be returned if either the type interner doesn't /// contain the `TyKind` key or if the address of the interned @@ -1634,7 +1667,6 @@ pub trait Lift<'tcx>: fmt::Debug { fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option; } - macro_rules! nop_lift { ($ty:ty => $lifted:ty) => { impl<'a, 'tcx> Lift<'tcx> for $ty { @@ -1681,8 +1713,8 @@ nop_list_lift!{Predicate<'a> => Predicate<'tcx>} nop_list_lift!{CanonicalVarInfo => CanonicalVarInfo} nop_list_lift!{ProjectionKind => ProjectionKind} -// this is the impl for `&'a InternalSubsts<'a>` -nop_list_lift!{Kind<'a> => Kind<'tcx>} +// This is the impl for `&'a InternalSubsts<'a>`. +nop_list_lift!{GenericArg<'a> => GenericArg<'tcx>} pub mod tls { use super::{GlobalCtxt, TyCtxt, ptr_eq}; @@ -1704,43 +1736,43 @@ pub mod tls { use rustc_rayon_core as rayon_core; /// This is the implicit state of rustc. It contains the current - /// TyCtxt and query. It is updated when creating a local interner or - /// executing a new query. Whenever there's a TyCtxt value available - /// you should also have access to an ImplicitCtxt through the functions + /// `TyCtxt` and query. It is updated when creating a local interner or + /// executing a new query. Whenever there's a `TyCtxt` value available + /// you should also have access to an `ImplicitCtxt` through the functions /// in this module. #[derive(Clone)] pub struct ImplicitCtxt<'a, 'tcx> { - /// The current TyCtxt. Initially created by `enter_global` and updated - /// by `enter_local` with a new local interner + /// The current `TyCtxt`. Initially created by `enter_global` and updated + /// by `enter_local` with a new local interner. pub tcx: TyCtxt<'tcx>, - /// The current query job, if any. This is updated by JobOwner::start in - /// ty::query::plumbing when executing a query + /// The current query job, if any. This is updated by `JobOwner::start` in + /// `ty::query::plumbing` when executing a query. pub query: Option>>, /// Where to store diagnostics for the current query job, if any. - /// This is updated by JobOwner::start in ty::query::plumbing when executing a query + /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query. pub diagnostics: Option<&'a Lock>>, /// Used to prevent layout from recursing too deeply. pub layout_depth: usize, /// The current dep graph task. This is used to add dependencies to queries - /// when executing them + /// when executing them. pub task_deps: Option<&'a Lock>, } - /// Sets Rayon's thread local variable which is preserved for Rayon jobs + /// Sets Rayon's thread-local variable, which is preserved for Rayon jobs /// to `value` during the call to `f`. It is restored to its previous value after. - /// This is used to set the pointer to the new ImplicitCtxt. + /// This is used to set the pointer to the new `ImplicitCtxt`. #[cfg(parallel_compiler)] #[inline] fn set_tlv R, R>(value: usize, f: F) -> R { rayon_core::tlv::with(value, f) } - /// Gets Rayon's thread local variable which is preserved for Rayon jobs. - /// This is used to get the pointer to the current ImplicitCtxt. + /// Gets Rayon's thread-local variable, which is preserved for Rayon jobs. + /// This is used to get the pointer to the current `ImplicitCtxt`. #[cfg(parallel_compiler)] #[inline] fn get_tlv() -> usize { @@ -1749,13 +1781,13 @@ pub mod tls { #[cfg(not(parallel_compiler))] thread_local! { - /// A thread local variable which stores a pointer to the current ImplicitCtxt. + /// A thread local variable that stores a pointer to the current `ImplicitCtxt`. static TLV: Cell = Cell::new(0); } /// Sets TLV to `value` during the call to `f`. /// It is restored to its previous value after. - /// This is used to set the pointer to the new ImplicitCtxt. + /// This is used to set the pointer to the new `ImplicitCtxt`. #[cfg(not(parallel_compiler))] #[inline] fn set_tlv R, R>(value: usize, f: F) -> R { @@ -1765,14 +1797,14 @@ pub mod tls { f() } - /// This is used to get the pointer to the current ImplicitCtxt. + /// Gets the pointer to the current `ImplicitCtxt`. #[cfg(not(parallel_compiler))] fn get_tlv() -> usize { TLV.with(|tlv| tlv.get()) } /// This is a callback from libsyntax as it cannot access the implicit state - /// in librustc otherwise + /// in librustc otherwise. fn span_debug(span: syntax_pos::Span, f: &mut fmt::Formatter<'_>) -> fmt::Result { with_opt(|tcx| { if let Some(tcx) = tcx { @@ -1797,7 +1829,7 @@ pub mod tls { }) } - /// Sets up the callbacks from libsyntax on the current thread + /// Sets up the callbacks from libsyntax on the current thread. pub fn with_thread_locals(f: F) -> R where F: FnOnce() -> R { @@ -1822,7 +1854,7 @@ pub mod tls { }) } - /// Sets `context` as the new current ImplicitCtxt for the duration of the function `f` + /// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`. #[inline] pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R where @@ -1833,19 +1865,19 @@ pub mod tls { }) } - /// Enters GlobalCtxt by setting up libsyntax callbacks and - /// creating a initial TyCtxt and ImplicitCtxt. - /// This happens once per rustc session and TyCtxts only exists + /// Enters `GlobalCtxt` by setting up libsyntax callbacks and + /// creating a initial `TyCtxt` and `ImplicitCtxt`. + /// This happens once per rustc session and `TyCtxt`s only exists /// inside the `f` function. pub fn enter_global<'tcx, F, R>(gcx: &'tcx GlobalCtxt<'tcx>, f: F) -> R where F: FnOnce(TyCtxt<'tcx>) -> R, { - // Update GCX_PTR to indicate there's a GlobalCtxt available + // Update `GCX_PTR` to indicate there's a `GlobalCtxt` available. GCX_PTR.with(|lock| { *lock.lock() = gcx as *const _ as usize; }); - // Set GCX_PTR back to 0 when we exit + // Set `GCX_PTR` back to 0 when we exit. let _on_drop = OnDrop(move || { GCX_PTR.with(|lock| *lock.lock() = 0); }); @@ -1866,12 +1898,12 @@ pub mod tls { } scoped_thread_local! { - /// Stores a pointer to the GlobalCtxt if one is available. - /// This is used to access the GlobalCtxt in the deadlock handler given to Rayon. + /// Stores a pointer to the `GlobalCtxt` if one is available. + /// This is used to access the `GlobalCtxt` in the deadlock handler given to Rayon. pub static GCX_PTR: Lock } - /// Creates a TyCtxt and ImplicitCtxt based on the GCX_PTR thread local. + /// Creates a `TyCtxt` and `ImplicitCtxt` based on the `GCX_PTR` thread local. /// This is used in the deadlock handler. pub unsafe fn with_global(f: F) -> R where @@ -1893,7 +1925,7 @@ pub mod tls { enter_context(&icx, |_| f(tcx)) } - /// Allows access to the current ImplicitCtxt in a closure if one is available + /// Allows access to the current `ImplicitCtxt` in a closure if one is available. #[inline] pub fn with_context_opt(f: F) -> R where @@ -1903,16 +1935,16 @@ pub mod tls { if context == 0 { f(None) } else { - // We could get a ImplicitCtxt pointer from another thread. - // Ensure that ImplicitCtxt is Sync + // We could get a `ImplicitCtxt` pointer from another thread. + // Ensure that `ImplicitCtxt` is `Sync`. sync::assert_sync::>(); unsafe { f(Some(&*(context as *const ImplicitCtxt<'_, '_>))) } } } - /// Allows access to the current ImplicitCtxt. - /// Panics if there is no ImplicitCtxt available + /// Allows access to the current `ImplicitCtxt`. + /// Panics if there is no `ImplicitCtxt` available. #[inline] pub fn with_context(f: F) -> R where @@ -1921,11 +1953,11 @@ pub mod tls { with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls"))) } - /// Allows access to the current ImplicitCtxt whose tcx field has the same global - /// interner as the tcx argument passed in. This means the closure is given an ImplicitCtxt - /// with the same 'tcx lifetime as the TyCtxt passed in. - /// This will panic if you pass it a TyCtxt which has a different global interner from - /// the current ImplicitCtxt's tcx field. + /// Allows access to the current `ImplicitCtxt` whose tcx field has the same global + /// interner as the tcx argument passed in. This means the closure is given an `ImplicitCtxt` + /// with the same `'tcx` lifetime as the `TyCtxt` passed in. + /// This will panic if you pass it a `TyCtxt` which has a different global interner from + /// the current `ImplicitCtxt`'s `tcx` field. #[inline] pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R where @@ -1940,8 +1972,8 @@ pub mod tls { }) } - /// Allows access to the TyCtxt in the current ImplicitCtxt. - /// Panics if there is no ImplicitCtxt available + /// Allows access to the `TyCtxt` in the current `ImplicitCtxt`. + /// Panics if there is no `ImplicitCtxt` available. #[inline] pub fn with(f: F) -> R where @@ -1950,8 +1982,8 @@ pub mod tls { with_context(|context| f(context.tcx)) } - /// Allows access to the TyCtxt in the current ImplicitCtxt. - /// The closure is passed None if there is no ImplicitCtxt available + /// Allows access to the `TyCtxt` in the current `ImplicitCtxt`. + /// The closure is passed None if there is no `ImplicitCtxt` available. #[inline] pub fn with_opt(f: F) -> R where @@ -1963,7 +1995,7 @@ pub mod tls { macro_rules! sty_debug_print { ($ctxt: expr, $($variant: ident),*) => {{ - // curious inner module to allow variant names to be used as + // Curious inner module to allow variant names to be used as // variable names. #[allow(non_snake_case)] mod inner { @@ -1992,7 +2024,7 @@ macro_rules! sty_debug_print { let shards = tcx.interners.type_.lock_shards(); let types = shards.iter().flat_map(|shard| shard.keys()); for &Interned(t) in types { - let variant = match t.sty { + let variant = match t.kind { ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Str | ty::Never => continue, ty::Error => /* unimportant */ continue, @@ -2061,10 +2093,10 @@ impl<'tcx, T: 'tcx+?Sized> Clone for Interned<'tcx, T> { } impl<'tcx, T: 'tcx+?Sized> Copy for Interned<'tcx, T> {} -// N.B., an `Interned` compares and hashes as a sty. +// N.B., an `Interned` compares and hashes as a `TyKind`. impl<'tcx> PartialEq for Interned<'tcx, TyS<'tcx>> { fn eq(&self, other: &Interned<'tcx, TyS<'tcx>>) -> bool { - self.0.sty == other.0.sty + self.0.kind == other.0.kind } } @@ -2072,14 +2104,14 @@ impl<'tcx> Eq for Interned<'tcx, TyS<'tcx>> {} impl<'tcx> Hash for Interned<'tcx, TyS<'tcx>> { fn hash(&self, s: &mut H) { - self.0.sty.hash(s) + self.0.kind.hash(s) } } -#[cfg_attr(not(bootstrap), allow(rustc::usage_of_ty_tykind))] +#[allow(rustc::usage_of_ty_tykind)] impl<'tcx> Borrow> for Interned<'tcx, TyS<'tcx>> { fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> { - &self.0.sty + &self.0.kind } } @@ -2110,8 +2142,8 @@ impl<'tcx> Borrow<[CanonicalVarInfo]> for Interned<'tcx, List> } } -impl<'tcx> Borrow<[Kind<'tcx>]> for Interned<'tcx, InternalSubsts<'tcx>> { - fn borrow<'a>(&'a self) -> &'a [Kind<'tcx>] { +impl<'tcx> Borrow<[GenericArg<'tcx>]> for Interned<'tcx, InternalSubsts<'tcx>> { + fn borrow<'a>(&'a self) -> &'a [GenericArg<'tcx>] { &self.0[..] } } @@ -2167,44 +2199,29 @@ impl<'tcx> Borrow<[Goal<'tcx>]> for Interned<'tcx, List>> { } } -macro_rules! intern_method { - ($lt_tcx:tt, $name:ident: $method:ident($alloc:ty, - $alloc_method:expr, - $alloc_to_key:expr) -> $ty:ty) => { - impl<$lt_tcx> TyCtxt<$lt_tcx> { - pub fn $method(self, v: $alloc) -> &$lt_tcx $ty { - let key = ($alloc_to_key)(&v); - - self.interners.$name.intern_ref(key, || { - Interned($alloc_method(&self.interners.arena, v)) - - }).0 - } - } - } -} - macro_rules! direct_interners { - ($lt_tcx:tt, $($name:ident: $method:ident($ty:ty)),+) => { - $(impl<$lt_tcx> PartialEq for Interned<$lt_tcx, $ty> { + ($($name:ident: $method:ident($ty:ty)),+) => { + $(impl<'tcx> PartialEq for Interned<'tcx, $ty> { fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } - impl<$lt_tcx> Eq for Interned<$lt_tcx, $ty> {} + impl<'tcx> Eq for Interned<'tcx, $ty> {} - impl<$lt_tcx> Hash for Interned<$lt_tcx, $ty> { + impl<'tcx> Hash for Interned<'tcx, $ty> { fn hash(&self, s: &mut H) { self.0.hash(s) } } - intern_method!( - $lt_tcx, - $name: $method($ty, - |a: &$lt_tcx SyncDroplessArena, v| -> &$lt_tcx $ty { a.alloc(v) }, - |x| x) -> $ty);)+ + impl<'tcx> TyCtxt<'tcx> { + pub fn $method(self, v: $ty) -> &'tcx $ty { + self.interners.$name.intern_ref(&v, || { + Interned(self.interners.arena.alloc(v)) + }).0 + } + })+ } } @@ -2212,7 +2229,7 @@ pub fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool { x.has_type_flags(ty::TypeFlags::KEEP_IN_LOCAL_TCX) } -direct_interners!('tcx, +direct_interners!( region: mk_region(RegionKind), goal: mk_goal(GoalKind<'tcx>), const_: mk_const(Const<'tcx>) @@ -2220,37 +2237,27 @@ direct_interners!('tcx, macro_rules! slice_interners { ($($field:ident: $method:ident($ty:ty)),+) => ( - $(intern_method!( 'tcx, $field: $method( - &[$ty], - |a, v| List::from_arena(a, v), - Deref::deref) -> List<$ty>);)+ + $(impl<'tcx> TyCtxt<'tcx> { + pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> { + self.interners.$field.intern_ref(v, || { + Interned(List::from_arena(&self.interners.arena, v)) + }).0 + } + })+ ); } slice_interners!( + type_list: _intern_type_list(Ty<'tcx>), + substs: _intern_substs(GenericArg<'tcx>), + canonical_var_infos: _intern_canonical_var_infos(CanonicalVarInfo), existential_predicates: _intern_existential_predicates(ExistentialPredicate<'tcx>), predicates: _intern_predicates(Predicate<'tcx>), - type_list: _intern_type_list(Ty<'tcx>), - substs: _intern_substs(Kind<'tcx>), clauses: _intern_clauses(Clause<'tcx>), goal_list: _intern_goals(Goal<'tcx>), projs: _intern_projs(ProjectionKind) ); -// This isn't a perfect fit: CanonicalVarInfo slices are always -// allocated in the global arena, so this `intern_method!` macro is -// overly general. But we just return false for the code that checks -// whether they belong in the thread-local arena, so no harm done, and -// seems better than open-coding the rest. -intern_method! { - 'tcx, - canonical_var_infos: _intern_canonical_var_infos( - &[CanonicalVarInfo], - |a, v| List::from_arena(a, v), - Deref::deref - ) -> List -} - impl<'tcx> TyCtxt<'tcx> { /// Given a `fn` type, returns an equivalent `unsafe fn` type; /// that is, a `fn` type that is equivalent in every way for being @@ -2273,7 +2280,7 @@ impl<'tcx> TyCtxt<'tcx> { /// It cannot convert a closure that requires unsafe. pub fn coerce_closure_fn_ty(self, sig: PolyFnSig<'tcx>, unsafety: hir::Unsafety) -> Ty<'tcx> { let converted_sig = sig.map_bound(|s| { - let params_iter = match s.inputs()[0].sty { + let params_iter = match s.inputs()[0].kind { ty::Tuple(params) => { params.into_iter().map(|k| k.expect_ty()) } @@ -2291,7 +2298,7 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_fn_ptr(converted_sig) } - #[cfg_attr(not(bootstrap), allow(rustc::usage_of_ty_tykind))] + #[allow(rustc::usage_of_ty_tykind)] #[inline] pub fn mk_ty(&self, st: TyKind<'tcx>) -> Ty<'tcx> { self.interners.intern_ty(st) @@ -2338,7 +2345,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_adt(self, def: &'tcx AdtDef, substs: SubstsRef<'tcx>) -> Ty<'tcx> { - // take a copy of substs so that we own the vectors inside + // Take a copy of substs so that we own the vectors inside. self.mk_ty(Adt(def, substs)) } @@ -2370,13 +2377,19 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem); + let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem, None); self.mk_generic_adt(def_id, ty) } + #[inline] + pub fn mk_lang_item(self, ty: Ty<'tcx>, item: lang_items::LangItem) -> Option> { + let def_id = self.lang_items().require(item).ok()?; + Some(self.mk_generic_adt(def_id, ty)) + } + #[inline] pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem); + let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem, None); self.mk_generic_adt(def_id, ty) } @@ -2417,7 +2430,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { - self.mk_ty(Array(ty, ty::Const::from_usize(self.global_tcx(), n))) + self.mk_ty(Array(ty, ty::Const::from_usize(self, n))) } #[inline] @@ -2427,13 +2440,13 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn intern_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> { - let kinds: Vec<_> = ts.into_iter().map(|&t| Kind::from(t)).collect(); + let kinds: Vec<_> = ts.into_iter().map(|&t| GenericArg::from(t)).collect(); self.mk_ty(Tuple(self.intern_substs(&kinds))) } pub fn mk_tup], Ty<'tcx>>>(self, iter: I) -> I::Output { iter.intern_with(|ts| { - let kinds: Vec<_> = ts.into_iter().map(|&t| Kind::from(t)).collect(); + let kinds: Vec<_> = ts.into_iter().map(|&t| GenericArg::from(t)).collect(); self.mk_ty(Tuple(self.intern_substs(&kinds))) }) } @@ -2489,7 +2502,7 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn mk_closure(self, closure_id: DefId, closure_substs: ClosureSubsts<'tcx>) + pub fn mk_closure(self, closure_id: DefId, closure_substs: SubstsRef<'tcx>) -> Ty<'tcx> { self.mk_ty(Closure(closure_id, closure_substs)) } @@ -2497,7 +2510,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_generator(self, id: DefId, - generator_substs: GeneratorSubsts<'tcx>, + generator_substs: SubstsRef<'tcx>, movability: hir::GeneratorMovability) -> Ty<'tcx> { self.mk_ty(Generator(id, generator_substs, movability)) @@ -2566,12 +2579,8 @@ impl<'tcx> TyCtxt<'tcx> { }) } - #[inline] - pub fn mk_self_type(self) -> Ty<'tcx> { - self.mk_ty_param(0, kw::SelfUpper.as_interned_str()) - } - pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> Kind<'tcx> { + pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> GenericArg<'tcx> { match param.kind { GenericParamDefKind::Lifetime => { self.mk_region(ty::ReEarlyBound(param.to_early_bound_region_data())).into() @@ -2616,7 +2625,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn intern_substs(self, ts: &[Kind<'tcx>]) -> &'tcx List> { + pub fn intern_substs(self, ts: &[GenericArg<'tcx>]) -> &'tcx List> { if ts.len() == 0 { List::empty() } else { @@ -2636,7 +2645,7 @@ impl<'tcx> TyCtxt<'tcx> { if ts.len() == 0 { List::empty() } else { - self.global_tcx()._intern_canonical_var_infos(ts) + self._intern_canonical_var_infos(ts) } } @@ -2663,8 +2672,8 @@ impl<'tcx> TyCtxt<'tcx> { unsafety: hir::Unsafety, abi: abi::Abi) -> , ty::FnSig<'tcx>>>::Output - where I: Iterator, - I::Item: InternIteratorElement, ty::FnSig<'tcx>> + where + I: Iterator, ty::FnSig<'tcx>>>, { inputs.chain(iter::once(output)).intern_with(|xs| ty::FnSig { inputs_and_output: self.intern_type_list(xs), @@ -2689,14 +2698,14 @@ impl<'tcx> TyCtxt<'tcx> { iter.intern_with(|xs| self.intern_type_list(xs)) } - pub fn mk_substs], - &'tcx List>>>(self, iter: I) -> I::Output { + pub fn mk_substs], + &'tcx List>>>(self, iter: I) -> I::Output { iter.intern_with(|xs| self.intern_substs(xs)) } pub fn mk_substs_trait(self, self_ty: Ty<'tcx>, - rest: &[Kind<'tcx>]) + rest: &[GenericArg<'tcx>]) -> SubstsRef<'tcx> { self.mk_substs(iter::once(self_ty.into()).chain(rest.iter().cloned())) @@ -2859,8 +2868,29 @@ impl<'a, T, R> InternIteratorElement for &'a T impl InternIteratorElement for Result { type Output = Result; - fn intern_with, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output { - Ok(f(&iter.collect::, _>>()?)) + fn intern_with, F: FnOnce(&[T]) -> R>(mut iter: I, f: F) + -> Self::Output { + // This code is hot enough that it's worth specializing for the most + // common length lists, to avoid the overhead of `SmallVec` creation. + // The match arms are in order of frequency. The 1, 2, and 0 cases are + // typically hit in ~95% of cases. We assume that if the upper and + // lower bounds from `size_hint` agree they are correct. + Ok(match iter.size_hint() { + (1, Some(1)) => { + f(&[iter.next().unwrap()?]) + } + (2, Some(2)) => { + let t0 = iter.next().unwrap()?; + let t1 = iter.next().unwrap()?; + f(&[t0, t1]) + } + (0, Some(0)) => { + f(&[]) + } + _ => { + f(&iter.collect::, _>>()?) + } + }) } } @@ -2885,6 +2915,14 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { assert_eq!(id, LOCAL_CRATE); tcx.arena.alloc(middle::lang_items::collect(tcx)) }; + providers.diagnostic_items = |tcx, id| { + assert_eq!(id, LOCAL_CRATE); + middle::diagnostic_items::collect(tcx) + }; + providers.all_diagnostic_items = |tcx, id| { + assert_eq!(id, LOCAL_CRATE); + middle::diagnostic_items::collect_all(tcx) + }; providers.maybe_unused_trait_import = |tcx, id| { tcx.maybe_unused_trait_imports.contains(&id) }; diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 4a72794b61a64..5851a48a8d377 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -4,6 +4,7 @@ use std::borrow::Cow; use std::fmt; use rustc_target::spec::abi; use syntax::ast; +use syntax::errors::pluralise; use errors::{Applicability, DiagnosticBuilder}; use syntax_pos::Span; @@ -46,6 +47,8 @@ pub enum TypeError<'tcx> { ExistentialMismatch(ExpectedFound<&'tcx ty::List>>), ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>), + + IntrinsicCast, } #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] @@ -80,12 +83,6 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { } }; - macro_rules! pluralise { - ($x:expr) => { - if $x != 1 { "s" } else { "" } - }; - } - match *self { CyclicTy(_) => write!(f, "cyclic type of infinite size"), Mismatch => write!(f, "types differ"), @@ -179,13 +176,16 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { ConstMismatch(ref values) => { write!(f, "expected `{}`, found `{}`", values.expected, values.found) } + IntrinsicCast => { + write!(f, "cannot coerce intrinsics to function pointers") + } } } } impl<'tcx> ty::TyS<'tcx> { pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> { - match self.sty { + match self.kind { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => self.to_string().into(), ty::Tuple(ref tys) if tys.is_empty() => self.to_string().into(), @@ -193,9 +193,11 @@ impl<'tcx> ty::TyS<'tcx> { ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.def_path_str(def.did)).into(), ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(), ty::Array(_, n) => { - let n = tcx.lift_to_global(&n).unwrap(); + let n = tcx.lift(&n).unwrap(); match n.try_eval_usize(tcx, ty::ParamEnv::empty()) { - Some(n) => format!("array of {} elements", n).into(), + Some(n) => { + format!("array of {} element{}", n, pluralise!(n)).into() + } None => "array".into(), } } @@ -239,13 +241,7 @@ impl<'tcx> ty::TyS<'tcx> { ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(), ty::Projection(_) => "associated type".into(), ty::UnnormalizedProjection(_) => "non-normalized associated type".into(), - ty::Param(ref p) => { - if p.is_self() { - "Self".into() - } else { - "type parameter".into() - } - } + ty::Param(_) => "type parameter".into(), ty::Opaque(..) => "opaque type".into(), ty::Error => "type error".into(), } @@ -253,13 +249,15 @@ impl<'tcx> ty::TyS<'tcx> { } impl<'tcx> TyCtxt<'tcx> { - pub fn note_and_explain_type_err(self, - db: &mut DiagnosticBuilder<'_>, - err: &TypeError<'tcx>, - sp: Span) { + pub fn note_and_explain_type_err( + self, + db: &mut DiagnosticBuilder<'_>, + err: &TypeError<'tcx>, + sp: Span, + ) { use self::TypeError::*; - match err.clone() { + match err { Sorts(values) => { let expected_str = values.expected.sort_string(self); let found_str = values.found.sort_string(self); @@ -267,10 +265,20 @@ impl<'tcx> TyCtxt<'tcx> { db.note("no two closures, even if identical, have the same type"); db.help("consider boxing your closure and/or using it as a trait object"); } - if let (ty::Infer(ty::IntVar(_)), ty::Float(_)) = - (&values.found.sty, &values.expected.sty) // Issue #53280 - { - if let Ok(snippet) = self.sess.source_map().span_to_snippet(sp) { + if expected_str == found_str && expected_str == "opaque type" { // Issue #63167 + db.note("distinct uses of `impl Trait` result in different opaque types"); + let e_str = values.expected.to_string(); + let f_str = values.found.to_string(); + if &e_str == &f_str && &e_str == "impl std::future::Future" { + // FIXME: use non-string based check. + db.help("if both `Future`s have the same `Output` type, consider \ + `.await`ing on both of them"); + } + } + match (&values.expected.kind, &values.found.kind) { + (ty::Float(_), ty::Infer(ty::IntVar(_))) => if let Ok( // Issue #53280 + snippet, + ) = self.sess.source_map().span_to_snippet(sp) { if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') { db.span_suggestion( sp, @@ -279,8 +287,96 @@ impl<'tcx> TyCtxt<'tcx> { Applicability::MachineApplicable ); } + }, + (ty::Param(_), ty::Param(_)) => { + db.note("a type parameter was expected, but a different one was found; \ + you might be missing a type parameter or trait bound"); + db.note("for more information, visit \ + https://doc.rust-lang.org/book/ch10-02-traits.html\ + #traits-as-parameters"); + } + (ty::Projection(_), ty::Projection(_)) => { + db.note("an associated type was expected, but a different one was found"); + } + (ty::Param(_), ty::Projection(_)) | (ty::Projection(_), ty::Param(_)) => { + db.note("you might be missing a type parameter or trait bound"); + } + (ty::Param(_), _) | (_, ty::Param(_)) => { + db.help("type parameters must be constrained to match other types"); + if self.sess.teach(&db.get_code().unwrap()) { + db.help("given a type parameter `T` and a method `foo`: +``` +trait Trait { fn foo(&self) -> T; } +``` +the only ways to implement method `foo` are: +- constrain `T` with an explicit type: +``` +impl Trait for X { + fn foo(&self) -> String { String::new() } +} +``` +- add a trait bound to `T` and call a method on that trait that returns `Self`: +``` +impl Trait for X { + fn foo(&self) -> T { ::default() } +} +``` +- change `foo` to return an argument of type `T`: +``` +impl Trait for X { + fn foo(&self, x: T) -> T { x } +} +```"); + } + db.note("for more information, visit \ + https://doc.rust-lang.org/book/ch10-02-traits.html\ + #traits-as-parameters"); + } + (ty::Projection(_), _) => { + db.note(&format!( + "consider constraining the associated type `{}` to `{}` or calling a \ + method that returns `{}`", + values.expected, + values.found, + values.expected, + )); + if self.sess.teach(&db.get_code().unwrap()) { + db.help("given an associated type `T` and a method `foo`: +``` +trait Trait { + type T; + fn foo(&self) -> Self::T; +} +``` +the only way of implementing method `foo` is to constrain `T` with an explicit associated type: +``` +impl Trait for X { + type T = String; + fn foo(&self) -> Self::T { String::new() } +} +```"); + } + db.note("for more information, visit \ + https://doc.rust-lang.org/book/ch19-03-advanced-traits.html"); + } + (_, ty::Projection(_)) => { + db.note(&format!( + "consider constraining the associated type `{}` to `{}`", + values.found, + values.expected, + )); + db.note("for more information, visit \ + https://doc.rust-lang.org/book/ch19-03-advanced-traits.html"); } + _ => {} } + debug!( + "note_and_explain_type_err expected={:?} ({:?}) found={:?} ({:?})", + values.expected, + values.expected.kind, + values.found, + values.found.kind, + ); }, CyclicTy(ty) => { // Watch out for various cases of cyclic types and try to explain. diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index ee0d33dbe345c..038b54f1f26dd 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -1,7 +1,6 @@ use crate::hir::def_id::DefId; use crate::ich::StableHashingContext; -use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, - HashStable}; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use std::fmt::Debug; use std::hash::Hash; use std::mem; @@ -60,7 +59,7 @@ pub fn simplify_type( ty: Ty<'_>, can_simplify_params: bool, ) -> Option { - match ty.sty { + match ty.kind { ty::Bool => Some(BoolSimplifiedType), ty::Char => Some(CharSimplifiedType), ty::Int(int_type) => Some(IntSimplifiedType(int_type)), @@ -158,9 +157,7 @@ impl<'a, D> HashStable> for SimplifiedTypeGen where D: Copy + Debug + Ord + Eq + Hash + HashStable>, { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { BoolSimplifiedType | diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 411b18e043a20..d3a3f51cfa47b 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -1,5 +1,5 @@ -use crate::ty::subst::{SubstsRef, UnpackedKind}; -use crate::ty::{self, Ty, TypeFlags, TypeFoldable, InferConst}; +use crate::ty::subst::{SubstsRef, GenericArgKind}; +use crate::ty::{self, Ty, TypeFlags, InferConst}; use crate::mir::interpret::ConstValue; #[derive(Debug)] @@ -18,10 +18,10 @@ impl FlagComputation { } } - #[cfg_attr(not(bootstrap), allow(rustc::usage_of_ty_tykind))] - pub fn for_sty(st: &ty::TyKind<'_>) -> FlagComputation { + #[allow(rustc::usage_of_ty_tykind)] + pub fn for_kind(kind: &ty::TyKind<'_>) -> FlagComputation { let mut result = FlagComputation::new(); - result.add_sty(st); + result.add_kind(kind); result } @@ -62,9 +62,9 @@ impl FlagComputation { } // otherwise, this binder captures nothing } - #[cfg_attr(not(bootstrap), allow(rustc::usage_of_ty_tykind))] - fn add_sty(&mut self, st: &ty::TyKind<'_>) { - match st { + #[allow(rustc::usage_of_ty_tykind)] + fn add_kind(&mut self, kind: &ty::TyKind<'_>) { + match kind { &ty::Bool | &ty::Char | &ty::Int(_) | @@ -86,19 +86,15 @@ impl FlagComputation { self.add_flags(TypeFlags::HAS_TY_ERR) } - &ty::Param(ref p) => { + &ty::Param(_) => { self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); - if p.is_self() { - self.add_flags(TypeFlags::HAS_SELF); - } else { - self.add_flags(TypeFlags::HAS_PARAMS); - } + self.add_flags(TypeFlags::HAS_PARAMS); } &ty::Generator(_, ref substs, _) => { self.add_flags(TypeFlags::HAS_TY_CLOSURE); self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); - self.add_substs(&substs.substs); + self.add_substs(substs); } &ty::GeneratorWitness(ref ts) => { @@ -110,7 +106,7 @@ impl FlagComputation { &ty::Closure(_, ref substs) => { self.add_flags(TypeFlags::HAS_TY_CLOSURE); self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); - self.add_substs(&substs.substs); + self.add_substs(substs); } &ty::Bound(debruijn, _) => { @@ -143,11 +139,6 @@ impl FlagComputation { } &ty::Projection(ref data) => { - // currently we can't normalize projections that - // include bound regions, so track those separately. - if !data.has_escaping_bound_vars() { - self.add_flags(TypeFlags::HAS_NORMALIZABLE_PROJECTION); - } self.add_flags(TypeFlags::HAS_PROJECTION); self.add_projection_ty(data); } @@ -243,7 +234,7 @@ impl FlagComputation { match c.val { ConstValue::Unevaluated(_, substs) => { self.add_substs(substs); - self.add_flags(TypeFlags::HAS_NORMALIZABLE_PROJECTION | TypeFlags::HAS_PROJECTION); + self.add_flags(TypeFlags::HAS_PROJECTION); }, ConstValue::Infer(infer) => { self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES | TypeFlags::HAS_CT_INFER); @@ -259,7 +250,9 @@ impl FlagComputation { ConstValue::Placeholder(_) => { self.add_flags(TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_CT_PLACEHOLDER); } - _ => {}, + ConstValue::Scalar(_) => { } + ConstValue::Slice { data: _, start: _, end: _ } => { } + ConstValue::ByRef { alloc: _, offset: _ } => { } } } @@ -275,9 +268,9 @@ impl FlagComputation { fn add_substs(&mut self, substs: SubstsRef<'_>) { for kind in substs { match kind.unpack() { - UnpackedKind::Type(ty) => self.add_ty(ty), - UnpackedKind::Lifetime(lt) => self.add_region(lt), - UnpackedKind::Const(ct) => self.add_const(ct), + GenericArgKind::Type(ty) => self.add_ty(ty), + GenericArgKind::Lifetime(lt) => self.add_region(lt), + GenericArgKind::Const(ct) => self.add_const(ct), } } } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index ab7df8e4e845b..5192075c26e98 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -39,8 +39,8 @@ use std::collections::BTreeMap; use std::fmt; use crate::util::nodemap::FxHashSet; -/// The TypeFoldable trait is implemented for every type that can be folded. -/// Basically, every type that has a corresponding method in TypeFolder. +/// This trait is implemented for every type that can be folded. +/// Basically, every type that has a corresponding method in `TypeFolder`. /// /// To implement this conveniently, use the /// `BraceStructTypeFoldableImpl` etc macros found in `macros.rs`. @@ -85,9 +85,6 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn has_param_types(&self) -> bool { self.has_type_flags(TypeFlags::HAS_PARAMS) } - fn has_self_ty(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_SELF) - } fn has_infer_types(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_INFER) } @@ -475,7 +472,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.sty { + match t.kind { ty::Bound(debruijn, bound_ty) => { if debruijn == self.current_index { let fld_t = &mut self.fld_t; @@ -779,7 +776,7 @@ impl TypeFolder<'tcx> for Shifter<'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.sty { + match ty.kind { ty::Bound(debruijn, bound_ty) => { if self.amount == 0 || debruijn < self.current_index { ty @@ -914,13 +911,15 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { } fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> bool { - if let ty::Const { - val: ConstValue::Infer(ty::InferConst::Canonical(debruijn, _)), - .. - } = *ct { - debruijn >= self.outer_index - } else { - false + // we don't have a `visit_infer_const` callback, so we have to + // hook in here to catch this case (annoying...), but + // otherwise we do want to remember to visit the rest of the + // const, as it has types/regions embedded in a lot of other + // places. + match ct.val { + ConstValue::Infer(ty::InferConst::Canonical(debruijn, _)) + if debruijn >= self.outer_index => true, + _ => ct.super_visit_with(self), } } } @@ -988,7 +987,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { // ignore the inputs to a projection, as they may not appear // in the normalized form if self.just_constrained { - match t.sty { + match t.kind { ty::Projection(..) | ty::Opaque(..) => { return false; } _ => { } } diff --git a/src/librustc/ty/inhabitedness/def_id_forest.rs b/src/librustc/ty/inhabitedness/def_id_forest.rs index 4453624fa4502..63cc60d80aada 100644 --- a/src/librustc/ty/inhabitedness/def_id_forest.rs +++ b/src/librustc/ty/inhabitedness/def_id_forest.rs @@ -4,20 +4,20 @@ use rustc::hir::CRATE_HIR_ID; use crate::ty::context::TyCtxt; use crate::ty::{DefId, DefIdTree}; -/// Represents a forest of DefIds closed under the ancestor relation. That is, -/// if a DefId representing a module is contained in the forest then all -/// DefIds defined in that module or submodules are also implicitly contained +/// Represents a forest of `DefId`s closed under the ancestor relation. That is, +/// if a `DefId` representing a module is contained in the forest then all +/// `DefId`s defined in that module or submodules are also implicitly contained /// in the forest. /// /// This is used to represent a set of modules in which a type is visibly /// uninhabited. #[derive(Clone)] pub struct DefIdForest { - /// The minimal set of DefIds required to represent the whole set. - /// If A and B are DefIds in the DefIdForest, and A is a descendant - /// of B, then only B will be in root_ids. - /// We use a SmallVec here because (for its use for caching inhabitedness) - /// its rare that this will contain even two ids. + /// The minimal set of `DefId`s required to represent the whole set. + /// If A and B are DefIds in the `DefIdForest`, and A is a descendant + /// of B, then only B will be in `root_ids`. + /// We use a `SmallVec` here because (for its use for caching inhabitedness) + /// its rare that this will contain even two IDs. root_ids: SmallVec<[DefId; 1]>, } @@ -37,7 +37,7 @@ impl<'tcx> DefIdForest { DefIdForest::from_id(crate_id) } - /// Creates a forest containing a DefId and all its descendants. + /// Creates a forest containing a `DefId` and all its descendants. pub fn from_id(id: DefId) -> DefIdForest { let mut root_ids = SmallVec::new(); root_ids.push(id); diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 2b3291656653f..bc0cf4deaa47b 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -1,3 +1,5 @@ +pub use self::def_id_forest::DefIdForest; + use crate::ty::context::TyCtxt; use crate::ty::{AdtDef, VariantDef, FieldDef, Ty, TyS}; use crate::ty::{DefId, SubstsRef}; @@ -5,12 +7,10 @@ use crate::ty::{AdtKind, Visibility}; use crate::ty::TyKind::*; use crate::ty; -pub use self::def_id_forest::DefIdForest; - mod def_id_forest; -// The methods in this module calculate DefIdForests of modules in which a -// AdtDef/VariantDef/FieldDef is visibly uninhabited. +// The methods in this module calculate `DefIdForest`s of modules in which a +// `AdtDef`/`VariantDef`/`FieldDef` is visibly uninhabited. // // # Example // ```rust @@ -36,24 +36,25 @@ mod def_id_forest; // y: c::AlsoSecretlyUninhabited, // } // ``` -// In this code, the type Foo will only be visibly uninhabited inside the -// modules b, c and d. Calling uninhabited_from on Foo or its AdtDef will -// return the forest of modules {b, c->d} (represented in a DefIdForest by the -// set {b, c}) +// In this code, the type `Foo` will only be visibly uninhabited inside the +// modules `b`, `c` and `d`. Calling `uninhabited_from` on `Foo` or its `AdtDef` will +// return the forest of modules {`b`, `c`->`d`} (represented in a `DefIdForest` by the +// set {`b`, `c`}). // -// We need this information for pattern-matching on Foo or types that contain -// Foo. +// We need this information for pattern-matching on `Foo` or types that contain +// `Foo`. // // # Example // ```rust // let foo_result: Result = ... ; // let Ok(t) = foo_result; // ``` -// This code should only compile in modules where the uninhabitedness of Foo is +// This code should only compile in modules where the uninhabitedness of `Foo` is // visible. impl<'tcx> TyCtxt<'tcx> { /// Checks whether a type is visibly uninhabited from a particular module. + /// /// # Example /// ```rust /// enum Void {} @@ -91,7 +92,7 @@ impl<'tcx> TyCtxt<'tcx> { /// visible. pub fn is_ty_uninhabited_from(self, module: DefId, ty: Ty<'tcx>) -> bool { // To check whether this type is uninhabited at all (not just from the - // given node) you could check whether the forest is empty. + // given node), you could check whether the forest is empty. // ``` // forest.is_empty() // ``` @@ -108,7 +109,7 @@ impl<'tcx> TyCtxt<'tcx> { } impl<'tcx> AdtDef { - /// Calculate the forest of DefIds from which this adt is visibly uninhabited. + /// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited. fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>) -> DefIdForest { // Non-exhaustive ADTs from other crates are always considered inhabited. if self.is_variant_list_non_exhaustive() && !self.did.is_local() { @@ -122,7 +123,7 @@ impl<'tcx> AdtDef { } impl<'tcx> VariantDef { - /// Calculate the forest of DefIds from which this variant is visibly uninhabited. + /// Calculates the forest of `DefId`s from which this variant is visibly uninhabited. pub fn uninhabited_from( &self, tcx: TyCtxt<'tcx>, @@ -148,7 +149,7 @@ impl<'tcx> VariantDef { } impl<'tcx> FieldDef { - /// Calculate the forest of DefIds from which this field is visibly uninhabited. + /// Calculates the forest of `DefId`s from which this field is visibly uninhabited. fn uninhabited_from( &self, tcx: TyCtxt<'tcx>, @@ -159,7 +160,7 @@ impl<'tcx> FieldDef { self.ty(tcx, substs).uninhabited_from(tcx) }; // FIXME(canndrew): Currently enum fields are (incorrectly) stored with - // Visibility::Invisible so we need to override self.vis if we're + // `Visibility::Invisible` so we need to override `self.vis` if we're // dealing with an enum. if is_enum { data_uninhabitedness() @@ -178,9 +179,9 @@ impl<'tcx> FieldDef { } impl<'tcx> TyS<'tcx> { - /// Calculate the forest of DefIds from which this type is visibly uninhabited. + /// Calculates the forest of `DefId`s from which this type is visibly uninhabited. fn uninhabited_from(&self, tcx: TyCtxt<'tcx>) -> DefIdForest { - match self.sty { + match self.kind { Adt(def, substs) => def.uninhabited_from(tcx, substs), Never => DefIdForest::full(tcx), diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 457d018f017d7..5139c8085a583 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -1,3 +1,4 @@ +use crate::hir::CodegenFnAttrFlags; use crate::hir::Unsafety; use crate::hir::def::Namespace; use crate::hir::def_id::DefId; @@ -25,6 +26,14 @@ pub enum InstanceDef<'tcx> { /// `::method` where `method` receives unsizeable `self: Self`. VtableShim(DefId), + /// `fn()` pointer where the function itself cannot be turned into a pointer. + /// + /// One example in the compiler today is functions annotated with `#[track_caller]`, which + /// must have their implicit caller location argument populated for a call. Because this is a + /// required part of the function's ABI but can't be tracked as a property of the function + /// pointer, we create a single "caller location" at the site where the function is reified. + ReifyShim(DefId), + /// `::call_*` /// `DefId` is `FnTrait::call_*` FnPtrShim(DefId, Ty<'tcx>), @@ -54,12 +63,12 @@ impl<'tcx> Instance<'tcx> { fn fn_sig_noadjust(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { let ty = self.ty(tcx); - match ty.sty { + match ty.kind { ty::FnDef(..) | // Shims currently have type FnPtr. Not sure this should remain. ty::FnPtr(_) => ty.fn_sig(tcx), ty::Closure(def_id, substs) => { - let sig = substs.closure_sig(def_id, tcx); + let sig = substs.as_closure().sig(def_id, tcx); let env_ty = tcx.closure_env_ty(def_id, substs).unwrap(); sig.map_bound(|sig| tcx.mk_fn_sig( @@ -71,7 +80,7 @@ impl<'tcx> Instance<'tcx> { )) } ty::Generator(def_id, substs, _) => { - let sig = substs.poly_sig(def_id, tcx); + let sig = substs.as_generator().poly_sig(def_id, tcx); let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); @@ -123,6 +132,7 @@ impl<'tcx> InstanceDef<'tcx> { match *self { InstanceDef::Item(def_id) | InstanceDef::VtableShim(def_id) | + InstanceDef::ReifyShim(def_id) | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) | InstanceDef::Intrinsic(def_id, ) | @@ -178,6 +188,9 @@ impl<'tcx> fmt::Display for Instance<'tcx> { InstanceDef::VtableShim(_) => { write!(f, " - shim(vtable)") } + InstanceDef::ReifyShim(_) => { + write!(f, " - shim(reify)") + } InstanceDef::Intrinsic(_) => { write!(f, " - intrinsic") } @@ -210,7 +223,7 @@ impl<'tcx> Instance<'tcx> { } pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> { - Instance::new(def_id, tcx.global_tcx().empty_substs_for_def_id(def_id)) + Instance::new(def_id, tcx.empty_substs_for_def_id(def_id)) } #[inline] @@ -255,7 +268,7 @@ impl<'tcx> Instance<'tcx> { &ty, ); - let def = match item_type.sty { + let def = match item_type.kind { ty::FnDef(..) if { let f = item_type.fn_sig(tcx); f.abi() == Abi::RustIntrinsic || @@ -290,6 +303,30 @@ impl<'tcx> Instance<'tcx> { result } + pub fn resolve_for_fn_ptr( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + def_id: DefId, + substs: SubstsRef<'tcx>, + ) -> Option> { + debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); + Instance::resolve(tcx, param_env, def_id, substs).map(|resolved| { + let has_track_caller = |def| tcx.codegen_fn_attrs(def).flags + .contains(CodegenFnAttrFlags::TRACK_CALLER); + + match resolved.def { + InstanceDef::Item(def_id) if has_track_caller(def_id) => { + debug!(" => fn pointer created for function with #[track_caller]"); + Instance { + def: InstanceDef::ReifyShim(def_id), + substs, + } + }, + _ => resolved, + } + }) + } + pub fn resolve_for_vtable( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -298,8 +335,9 @@ impl<'tcx> Instance<'tcx> { ) -> Option> { debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); let fn_sig = tcx.fn_sig(def_id); - let is_vtable_shim = - fn_sig.inputs().skip_binder().len() > 0 && fn_sig.input(0).skip_binder().is_self(); + let is_vtable_shim = fn_sig.inputs().skip_binder().len() > 0 + && fn_sig.input(0).skip_binder().is_param(0) + && tcx.generics_of(def_id).has_self; if is_vtable_shim { debug!(" => associated item with unsizeable self: Self"); Some(Instance { @@ -314,19 +352,19 @@ impl<'tcx> Instance<'tcx> { pub fn resolve_closure( tcx: TyCtxt<'tcx>, def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, + substs: ty::SubstsRef<'tcx>, requested_kind: ty::ClosureKind, ) -> Instance<'tcx> { - let actual_kind = substs.closure_kind(def_id, tcx); + let actual_kind = substs.as_closure().kind(def_id, tcx); match needs_fn_once_adapter_shim(actual_kind, requested_kind) { Ok(true) => Instance::fn_once_adapter_instance(tcx, def_id, substs), - _ => Instance::new(def_id, substs.substs) + _ => Instance::new(def_id, substs) } } pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { - let def_id = tcx.require_lang_item(DropInPlaceFnLangItem); + let def_id = tcx.require_lang_item(DropInPlaceFnLangItem, None); let substs = tcx.intern_substs(&[ty.into()]); Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap() } @@ -334,7 +372,7 @@ impl<'tcx> Instance<'tcx> { pub fn fn_once_adapter_instance( tcx: TyCtxt<'tcx>, closure_did: DefId, - substs: ty::ClosureSubsts<'tcx>, + substs: ty::SubstsRef<'tcx>, ) -> Instance<'tcx> { debug!("fn_once_adapter_shim({:?}, {:?})", closure_did, @@ -347,7 +385,7 @@ impl<'tcx> Instance<'tcx> { let self_ty = tcx.mk_closure(closure_did, substs); - let sig = substs.closure_sig(closure_did, tcx); + let sig = substs.as_closure().sig(closure_did, tcx); let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); assert_eq!(sig.inputs().len(), 1); let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]); @@ -394,7 +432,7 @@ fn resolve_associated_item<'tcx>( traits::VtableGenerator(generator_data) => { Some(Instance { def: ty::InstanceDef::Item(generator_data.generator_def_id), - substs: generator_data.substs.substs + substs: generator_data.substs }) } traits::VtableClosure(closure_data) => { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 1c9a5ad621854..ce7e1822d9ab5 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1,5 +1,5 @@ use crate::session::{self, DataTypeKind}; -use crate::ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions}; +use crate::ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, subst::SubstsRef}; use syntax::ast::{self, Ident, IntTy, UintTy}; use syntax::attr; @@ -15,17 +15,15 @@ use std::ops::Bound; use crate::hir; use crate::ich::StableHashingContext; use crate::mir::{GeneratorLayout, GeneratorSavedLocal}; -use crate::ty::GeneratorSubsts; use crate::ty::subst::Subst; -use rustc_data_structures::bit_set::BitSet; -use rustc_data_structures::indexed_vec::{IndexVec, Idx}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, - StableHasherResult}; +use rustc_index::bit_set::BitSet; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_index::vec::{IndexVec, Idx}; pub use rustc_target::abi::*; use rustc_target::spec::{HasTargetSpec, abi::Abi as SpecAbi}; use rustc_target::abi::call::{ - ArgAttribute, ArgAttributes, ArgType, Conv, FnType, IgnoreMode, PassMode, Reg, RegKind + ArgAttribute, ArgAttributes, ArgType, Conv, FnType, PassMode, Reg, RegKind }; pub trait IntegerExt { @@ -127,6 +125,7 @@ impl IntegerExt for Integer { pub trait PrimitiveExt { fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; + fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; } impl PrimitiveExt for Primitive { @@ -138,6 +137,16 @@ impl PrimitiveExt for Primitive { Pointer => tcx.mk_mut_ptr(tcx.mk_unit()), } } + + /// Return an *integer* type matching this primitive. + /// Useful in particular when dealing with enum discriminants. + fn to_int_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + match *self { + Int(i, signed) => i.to_ty(tcx, signed), + Pointer => tcx.types.usize, + Float(..) => bug!("floats do not have an int type"), + } + } } /// The first half of a fat pointer. @@ -273,14 +282,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { repr: &ReprOptions, kind: StructKind) -> Result> { let dl = self.data_layout(); - let packed = repr.packed(); - if packed && repr.align > 0 { + let pack = repr.pack; + if pack.is_some() && repr.align.is_some() { bug!("struct cannot be packed and aligned"); } - let pack = Align::from_bytes(repr.pack as u64).unwrap(); - - let mut align = if packed { + let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align @@ -303,7 +310,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { }; let optimizing = &mut inverse_memory_index[..end]; let field_align = |f: &TyLayout<'_>| { - if packed { f.align.abi.min(pack) } else { f.align.abi } + if let Some(pack) = pack { f.align.abi.min(pack) } else { f.align.abi } }; match kind { StructKind::AlwaysSized | @@ -334,7 +341,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let mut largest_niche_available = 0; if let StructKind::Prefixed(prefix_size, prefix_align) = kind { - let prefix_align = if packed { + let prefix_align = if let Some(pack) = pack { prefix_align.min(pack) } else { prefix_align @@ -355,7 +362,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } // Invariant: offset < dl.obj_size_bound() <= 1<<61 - let field_align = if packed { + let field_align = if let Some(pack) = pack { field.align.min(AbiAndPrefAlign::new(pack)) } else { field.align @@ -379,10 +386,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { .ok_or(LayoutError::SizeOverflow(ty))?; } - if repr.align > 0 { - let repr_align = repr.align as u64; - align = align.max(AbiAndPrefAlign::new(Align::from_bytes(repr_align).unwrap())); - debug!("univariant repr_align: {:?}", repr_align); + if let Some(repr_align) = repr.align { + align = align.max(AbiAndPrefAlign::new(repr_align)); } debug!("univariant min_size: {:?}", offset); @@ -513,7 +518,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { }; debug_assert!(!ty.has_infer_types()); - Ok(match ty.sty { + Ok(match ty.kind { // Basic scalars. ty::Bool => { tcx.intern_layout(LayoutDetails::scalar(self, Scalar { @@ -566,7 +571,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env); - let metadata = match unsized_part.sty { + let metadata = match unsized_part.kind { ty::Foreign(..) => { return Ok(tcx.intern_layout(LayoutDetails::scalar(self, data_ptr))); } @@ -665,10 +670,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { tcx.intern_layout(unit) } - ty::Generator(def_id, substs, _) => self.generator_layout(ty, def_id, &substs)?, + ty::Generator(def_id, substs, _) => self.generator_layout(ty, def_id, substs)?, ty::Closure(def_id, ref substs) => { - let tys = substs.upvar_tys(def_id, tcx); + let tys = substs.as_closure().upvar_tys(def_id, tcx); univariant(&tys.map(|ty| self.layout_of(ty)).collect::, _>>()?, &ReprOptions::default(), StructKind::AlwaysSized)? @@ -730,23 +735,18 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { }).collect::, _>>()?; if def.is_union() { - let packed = def.repr.packed(); - if packed && def.repr.align > 0 { - bug!("Union cannot be packed and aligned"); + if def.repr.pack.is_some() && def.repr.align.is_some() { + bug!("union cannot be packed and aligned"); } - let pack = Align::from_bytes(def.repr.pack as u64).unwrap(); - - let mut align = if packed { + let mut align = if def.repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align }; - if def.repr.align > 0 { - let repr_align = def.repr.align as u64; - align = align.max( - AbiAndPrefAlign::new(Align::from_bytes(repr_align).unwrap())); + if let Some(repr_align) = def.repr.align { + align = align.max(AbiAndPrefAlign::new(repr_align)); } let optimize = !def.repr.inhibit_union_abi_opt(); @@ -755,13 +755,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let index = VariantIdx::new(0); for field in &variants[index] { assert!(!field.is_unsized()); - - let field_align = if packed { - field.align.min(AbiAndPrefAlign::new(pack)) - } else { - field.align - }; - align = align.max(field_align); + align = align.max(field.align); // If all non-ZST fields have the same ABI, forward this ABI if optimize && !field.is_zst() { @@ -796,6 +790,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { size = cmp::max(size, field.size); } + if let Some(pack) = def.repr.pack { + align = align.min(AbiAndPrefAlign::new(pack)); + } + return Ok(tcx.intern_layout(LayoutDetails { variants: Variants::Single { index }, fields: FieldPlacement::Union(variants[index].len()), @@ -1407,12 +1405,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { &self, ty: Ty<'tcx>, def_id: hir::def_id::DefId, - substs: &GeneratorSubsts<'tcx>, + substs: SubstsRef<'tcx>, ) -> Result<&'tcx LayoutDetails, LayoutError<'tcx>> { use SavedLocalEligibility::*; let tcx = self.tcx; - let subst_field = |ty: Ty<'tcx>| { ty.subst(tcx, substs.substs) }; + let subst_field = |ty: Ty<'tcx>| { ty.subst(tcx, substs) }; let info = tcx.generator_layout(def_id); let (ineligible_locals, assignments) = self.generator_saved_local_eligibility(&info); @@ -1420,9 +1418,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Build a prefix layout, including "promoting" all ineligible // locals as part of the prefix. We compute the layout of all of // these fields at once to get optimal packing. - let discr_index = substs.prefix_tys(def_id, tcx).count(); + let discr_index = substs.as_generator().prefix_tys(def_id, tcx).count(); // FIXME(eddyb) set the correct vaidity range for the discriminant. - let discr_layout = self.layout_of(substs.discr_ty(tcx))?; + let discr_layout = self.layout_of(substs.as_generator().discr_ty(tcx))?; let discr = match &discr_layout.abi { Abi::Scalar(s) => s.clone(), _ => bug!(), @@ -1431,7 +1429,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { .map(|local| subst_field(info.field_tys[local])) .map(|ty| tcx.mk_maybe_uninit(ty)) .map(|ty| self.layout_of(ty)); - let prefix_layouts = substs.prefix_tys(def_id, tcx) + let prefix_layouts = substs.as_generator().prefix_tys(def_id, tcx) .map(|ty| self.layout_of(ty)) .chain(iter::once(Ok(discr_layout))) .chain(promoted_layouts) @@ -1601,7 +1599,6 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // resulting from the final codegen session. if layout.ty.has_param_types() || - layout.ty.has_self_ty() || !self.param_env.caller_bounds.is_empty() { return; @@ -1619,7 +1616,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { variants); }; - let adt_def = match layout.ty.sty { + let adt_def = match layout.ty.kind { ty::Adt(ref adt_def, _) => { debug!("print-type-size t: `{:?}` process adt", layout.ty); adt_def @@ -1638,7 +1635,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { }; let adt_kind = adt_def.adt_kind(); - let adt_packed = adt_def.repr.packed(); + let adt_packed = adt_def.repr.pack.is_some(); let build_variant_info = |n: Option, flds: &[ast::Name], @@ -1760,14 +1757,14 @@ impl<'tcx> SizeSkeleton<'tcx> { Err(err) => err }; - match ty.sty { + match ty.kind { ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { let non_zero = !ty.is_unsafe_ptr(); let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env); - match tail.sty { + match tail.kind { ty::Param(_) | ty::Projection(_) => { - debug_assert!(tail.has_param_types() || tail.has_self_ty()); + debug_assert!(tail.has_param_types()); Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(&tail) @@ -1884,7 +1881,7 @@ impl<'tcx> HasDataLayout for TyCtxt<'tcx> { impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { - self.global_tcx() + *self } } @@ -2004,7 +2001,7 @@ impl TyCtxt<'tcx> { pub fn layout_of(self, param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result, LayoutError<'tcx>> { let cx = LayoutCx { - tcx: self.global_tcx(), + tcx: self, param_env: param_env_and_ty.param_env }; cx.layout_of(param_env_and_ty.value) @@ -2018,7 +2015,7 @@ impl ty::query::TyCtxtAt<'tcx> { pub fn layout_of(self, param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result, LayoutError<'tcx>> { let cx = LayoutCx { - tcx: self.global_tcx().at(self.span), + tcx: self.at(self.span), param_env: param_env_and_ty.param_env }; cx.layout_of(param_env_and_ty.value) @@ -2027,9 +2024,9 @@ impl ty::query::TyCtxtAt<'tcx> { impl<'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> where - C: LayoutOf> + HasTyCtxt<'tcx>, - C::TyLayout: MaybeResult>, - C: HasParamEnv<'tcx>, + C: LayoutOf, TyLayout: MaybeResult>> + + HasTyCtxt<'tcx> + + HasParamEnv<'tcx>, { fn for_variant(this: TyLayout<'tcx>, cx: &C, variant_index: VariantIdx) -> TyLayout<'tcx> { let details = match this.variants { @@ -2041,7 +2038,7 @@ where assert_eq!(layout.variants, Variants::Single { index }); } - let fields = match this.ty.sty { + let fields = match this.ty.kind { ty::Adt(def, _) => def.variants[variant_index].fields.len(), _ => bug!() }; @@ -2079,7 +2076,7 @@ where })) }; - cx.layout_of(match this.ty.sty { + cx.layout_of(match this.ty.kind { ty::Bool | ty::Char | ty::Int(_) | @@ -2116,7 +2113,7 @@ where })); } - match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).sty { + match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind { ty::Slice(_) | ty::Str => tcx.types.usize, ty::Dynamic(_, _) => { @@ -2149,13 +2146,13 @@ where // Tuples, generators and closures. ty::Closure(def_id, ref substs) => { - substs.upvar_tys(def_id, tcx).nth(i).unwrap() + substs.as_closure().upvar_tys(def_id, tcx).nth(i).unwrap() } ty::Generator(def_id, ref substs, _) => { match this.variants { Variants::Single { index } => { - substs.state_tys(def_id, tcx) + substs.as_generator().state_tys(def_id, tcx) .nth(index.as_usize()).unwrap() .nth(i).unwrap() } @@ -2163,7 +2160,7 @@ where if i == discr_index { return discr_layout(discr); } - substs.prefix_tys(def_id, tcx).nth(i).unwrap() + substs.as_generator().prefix_tys(def_id, tcx).nth(i).unwrap() } } } @@ -2203,7 +2200,7 @@ where cx: &C, offset: Size, ) -> Option { - match this.ty.sty { + match this.ty.kind { ty::RawPtr(mt) if offset.bytes() == 0 => { cx.layout_of(mt.ty).to_result().ok() .map(|layout| PointeeInfo { @@ -2310,7 +2307,7 @@ where // FIXME(eddyb) This should be for `ptr::Unique`, not `Box`. if let Some(ref mut pointee) = result { - if let ty::Adt(def, _) = this.ty.sty { + if let ty::Adt(def, _) = this.ty.kind { if def.is_box() && offset.bytes() == 0 { pointee.safe = Some(PointerKind::UniqueOwned); } @@ -2324,9 +2321,7 @@ where } impl<'a> HashStable> for Variants { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use crate::ty::layout::Variants::*; mem::discriminant(self).hash_stable(hcx, hasher); @@ -2350,9 +2345,7 @@ impl<'a> HashStable> for Variants { } impl<'a> HashStable> for DiscriminantKind { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use crate::ty::layout::DiscriminantKind::*; mem::discriminant(self).hash_stable(hcx, hasher); @@ -2373,9 +2366,7 @@ impl<'a> HashStable> for DiscriminantKind { } impl<'a> HashStable> for FieldPlacement { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use crate::ty::layout::FieldPlacement::*; mem::discriminant(self).hash_stable(hcx, hasher); @@ -2396,19 +2387,13 @@ impl<'a> HashStable> for FieldPlacement { } impl<'a> HashStable> for VariantIdx { - fn hash_stable( - &self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher, - ) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.as_u32().hash_stable(hcx, hasher) } } impl<'a> HashStable> for Abi { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use crate::ty::layout::Abi::*; mem::discriminant(self).hash_stable(hcx, hasher); @@ -2433,9 +2418,7 @@ impl<'a> HashStable> for Abi { } impl<'a> HashStable> for Scalar { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let Scalar { value, ref valid_range } = *self; value.hash_stable(hcx, hasher); valid_range.start().hash_stable(hcx, hasher); @@ -2477,29 +2460,19 @@ impl_stable_hash_for!(struct crate::ty::layout::AbiAndPrefAlign { }); impl<'tcx> HashStable> for Align { - fn hash_stable( - &self, - hcx: &mut StableHashingContext<'tcx>, - hasher: &mut StableHasher, - ) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { self.bytes().hash_stable(hcx, hasher); } } impl<'tcx> HashStable> for Size { - fn hash_stable( - &self, - hcx: &mut StableHashingContext<'tcx>, - hasher: &mut StableHasher, - ) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { self.bytes().hash_stable(hcx, hasher); } } impl<'a, 'tcx> HashStable> for LayoutError<'tcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use crate::ty::layout::LayoutError::*; mem::discriminant(self).hash_stable(hcx, hasher); @@ -2518,7 +2491,7 @@ where + HasTyCtxt<'tcx> + HasParamEnv<'tcx>, { - fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self; + fn of_instance(cx: &C, instance: ty::Instance<'tcx>) -> Self; fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; fn new_internal( @@ -2538,7 +2511,7 @@ where + HasTyCtxt<'tcx> + HasParamEnv<'tcx>, { - fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self { + fn of_instance(cx: &C, instance: ty::Instance<'tcx>) -> Self { let sig = instance.fn_sig(cx.tcx()); let sig = cx .tcx() @@ -2642,7 +2615,7 @@ where let extra_args = if sig.abi == RustCall { assert!(!sig.c_variadic && extra_args.is_empty()); - match sig.inputs().last().unwrap().sty { + match sig.inputs().last().unwrap().kind { ty::Tuple(tupled_arguments) => { inputs = &sig.inputs()[0..sig.inputs().len() - 1]; tupled_arguments.iter().map(|k| k.expect_ty()).collect() @@ -2723,14 +2696,6 @@ where } }; - // Store the index of the last argument. This is useful for working with - // C-compatible variadic arguments. - let last_arg_idx = if sig.inputs().is_empty() { - None - } else { - Some(sig.inputs().len() - 1) - }; - let arg_of = |ty: Ty<'tcx>, arg_idx: Option| { let is_return = arg_idx.is_none(); let mut arg = mk_arg_type(ty, arg_idx); @@ -2740,30 +2705,7 @@ where // The same is true for s390x-unknown-linux-gnu // and sparc64-unknown-linux-gnu. if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) { - arg.mode = PassMode::Ignore(IgnoreMode::Zst); - } - } - - // If this is a C-variadic function, this is not the return value, - // and there is one or more fixed arguments; ensure that the `VaListImpl` - // is ignored as an argument. - if sig.c_variadic { - match (last_arg_idx, arg_idx) { - (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => { - let va_list_did = match cx.tcx().lang_items().va_list() { - Some(did) => did, - None => bug!("`va_list` lang item required for C-variadic functions"), - }; - match ty.sty { - ty::Adt(def, _) if def.did == va_list_did => { - // This is the "spoofed" `VaListImpl`. Set the arguments mode - // so that it will be ignored. - arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs); - } - _ => (), - } - } - _ => {} + arg.mode = PassMode::Ignore; } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index a10578b0a4390..3692caada577c 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -33,6 +33,7 @@ use arena::SyncDroplessArena; use crate::session::DataTypeKind; use rustc_serialize::{self, Encodable, Encoder}; +use rustc_target::abi::Align; use std::cell::RefCell; use std::cmp::{self, Ordering}; use std::fmt; @@ -45,14 +46,13 @@ use std::ops::Range; use syntax::ast::{self, Name, Ident, NodeId}; use syntax::attr; use syntax::ext::hygiene::ExpnId; -use syntax::symbol::{kw, sym, Symbol, LocalInternedString, InternedString}; +use syntax::symbol::{kw, sym, Symbol, InternedString}; use syntax_pos::Span; use smallvec; use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, - HashStable}; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; +use rustc_index::vec::{Idx, IndexVec}; use crate::hir; @@ -75,7 +75,7 @@ pub use self::binding::BindingMode; pub use self::binding::BindingMode::*; pub use self::context::{TyCtxt, FreeRegionInfo, AllArenas, tls, keep_local}; -pub use self::context::{Lift, TypeckTables, CtxtInterners, GlobalCtxt}; +pub use self::context::{Lift, GeneratorInteriorTypeCause, TypeckTables, CtxtInterners, GlobalCtxt}; pub use self::context::{ UserTypeAnnotationIndex, UserType, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, ResolvedOpaqueTy, @@ -166,6 +166,19 @@ pub struct ImplHeader<'tcx> { pub predicates: Vec>, } +#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] +pub enum ImplPolarity { + /// `impl Trait for Type` + Positive, + /// `impl !Trait for Type` + Negative, + /// `#[rustc_reservation_impl] impl Trait for Type` + /// + /// This is a "stability hack", not a real Rust feature. + /// See #64631 for details. + Reservation, +} + #[derive(Copy, Clone, Debug, PartialEq, HashStable)] pub struct AssocItem { pub def_id: DefId, @@ -414,61 +427,53 @@ pub struct CReaderCacheKey { bitflags! { pub struct TypeFlags: u32 { const HAS_PARAMS = 1 << 0; - const HAS_SELF = 1 << 1; - const HAS_TY_INFER = 1 << 2; - const HAS_RE_INFER = 1 << 3; - const HAS_RE_PLACEHOLDER = 1 << 4; + const HAS_TY_INFER = 1 << 1; + const HAS_RE_INFER = 1 << 2; + const HAS_RE_PLACEHOLDER = 1 << 3; /// Does this have any `ReEarlyBound` regions? Used to /// determine whether substitition is required, since those /// represent regions that are bound in a `ty::Generics` and /// hence may be substituted. - const HAS_RE_EARLY_BOUND = 1 << 5; + const HAS_RE_EARLY_BOUND = 1 << 4; /// Does this have any region that "appears free" in the type? /// Basically anything but `ReLateBound` and `ReErased`. - const HAS_FREE_REGIONS = 1 << 6; + const HAS_FREE_REGIONS = 1 << 5; /// Is an error type reachable? - const HAS_TY_ERR = 1 << 7; - const HAS_PROJECTION = 1 << 8; + const HAS_TY_ERR = 1 << 6; + const HAS_PROJECTION = 1 << 7; // FIXME: Rename this to the actual property since it's used for generators too - const HAS_TY_CLOSURE = 1 << 9; + const HAS_TY_CLOSURE = 1 << 8; /// `true` if there are "names" of types and regions and so forth /// that are local to a particular fn - const HAS_FREE_LOCAL_NAMES = 1 << 10; + const HAS_FREE_LOCAL_NAMES = 1 << 9; /// Present if the type belongs in a local type context. /// Only set for Infer other than Fresh. - const KEEP_IN_LOCAL_TCX = 1 << 11; - - // Is there a projection that does not involve a bound region? - // Currently we can't normalize projections w/ bound regions. - const HAS_NORMALIZABLE_PROJECTION = 1 << 12; + const KEEP_IN_LOCAL_TCX = 1 << 10; /// Does this have any `ReLateBound` regions? Used to check /// if a global bound is safe to evaluate. - const HAS_RE_LATE_BOUND = 1 << 13; + const HAS_RE_LATE_BOUND = 1 << 11; - const HAS_TY_PLACEHOLDER = 1 << 14; + const HAS_TY_PLACEHOLDER = 1 << 12; - const HAS_CT_INFER = 1 << 15; - const HAS_CT_PLACEHOLDER = 1 << 16; + const HAS_CT_INFER = 1 << 13; + const HAS_CT_PLACEHOLDER = 1 << 14; const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | - TypeFlags::HAS_SELF.bits | TypeFlags::HAS_RE_EARLY_BOUND.bits; /// Flags representing the nominal content of a type, /// computed by FlagsComputation. If you add a new nominal /// flag, it should be added here too. const NOMINAL_FLAGS = TypeFlags::HAS_PARAMS.bits | - TypeFlags::HAS_SELF.bits | TypeFlags::HAS_TY_INFER.bits | TypeFlags::HAS_RE_INFER.bits | - TypeFlags::HAS_CT_INFER.bits | TypeFlags::HAS_RE_PLACEHOLDER.bits | TypeFlags::HAS_RE_EARLY_BOUND.bits | TypeFlags::HAS_FREE_REGIONS.bits | @@ -479,13 +484,14 @@ bitflags! { TypeFlags::KEEP_IN_LOCAL_TCX.bits | TypeFlags::HAS_RE_LATE_BOUND.bits | TypeFlags::HAS_TY_PLACEHOLDER.bits | + TypeFlags::HAS_CT_INFER.bits | TypeFlags::HAS_CT_PLACEHOLDER.bits; } } -#[cfg_attr(not(bootstrap), allow(rustc::usage_of_ty_tykind))] +#[allow(rustc::usage_of_ty_tykind)] pub struct TyS<'tcx> { - pub sty: TyKind<'tcx>, + pub kind: TyKind<'tcx>, pub flags: TypeFlags, /// This is a kind of confusing thing: it stores the smallest @@ -514,13 +520,13 @@ static_assert_size!(TyS<'_>, 32); impl<'tcx> Ord for TyS<'tcx> { fn cmp(&self, other: &TyS<'tcx>) -> Ordering { - self.sty.cmp(&other.sty) + self.kind.cmp(&other.kind) } } impl<'tcx> PartialOrd for TyS<'tcx> { fn partial_cmp(&self, other: &TyS<'tcx>) -> Option { - Some(self.sty.cmp(&other.sty)) + Some(self.kind.cmp(&other.kind)) } } @@ -540,7 +546,7 @@ impl<'tcx> Hash for TyS<'tcx> { impl<'tcx> TyS<'tcx> { pub fn is_primitive_ty(&self) -> bool { - match self.sty { + match self.kind { Bool | Char | Int(_) | @@ -556,7 +562,7 @@ impl<'tcx> TyS<'tcx> { } pub fn is_suggestable(&self) -> bool { - match self.sty { + match self.kind { Opaque(..) | FnDef(..) | FnPtr(..) | @@ -570,23 +576,22 @@ impl<'tcx> TyS<'tcx> { } impl<'a, 'tcx> HashStable> for ty::TyS<'tcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ty::TyS { - ref sty, + ref kind, // The other fields just provide fast access to information that is - // also contained in `sty`, so no need to hash them. + // also contained in `kind`, so no need to hash them. flags: _, outer_exclusive_binder: _, } = *self; - sty.hash_stable(hcx, hasher); + kind.hash_stable(hcx, hasher); } } +#[rustc_diagnostic_item = "Ty"] pub type Ty<'tcx> = &'tcx TyS<'tcx>; impl<'tcx> rustc_serialize::UseSpecializedEncodable for Ty<'tcx> {} @@ -595,7 +600,8 @@ impl<'tcx> rustc_serialize::UseSpecializedDecodable for Ty<'tcx> {} pub type CanonicalTy<'tcx> = Canonical<'tcx, Ty<'tcx>>; extern { - /// A dummy type used to force List to by unsized without requiring fat pointers + /// A dummy type used to force `List` to be unsized while not requiring references to it be wide + /// pointers. type OpaqueListContents; } @@ -1105,7 +1111,7 @@ pub enum Predicate<'tcx> { /// No direct syntax. May be thought of as `where T: FnFoo<...>` /// for some substitutions `...` and `T` being a closure type. /// Satisfied (or refuted) once we know the closure's kind. - ClosureKind(DefId, ClosureSubsts<'tcx>, ClosureKind), + ClosureKind(DefId, SubstsRef<'tcx>, ClosureKind), /// `T1 <: T2` Subtype(PolySubtypePredicate<'tcx>), @@ -1452,7 +1458,7 @@ impl<'tcx> Predicate<'tcx> { WalkTysIter::None } ty::Predicate::ClosureKind(_closure_def_id, closure_substs, _kind) => { - WalkTysIter::Types(closure_substs.substs.types()) + WalkTysIter::Types(closure_substs.types()) } ty::Predicate::ConstEvaluatable(_, substs) => { WalkTysIter::Types(substs.types()) @@ -1531,7 +1537,7 @@ impl<'tcx> InstantiatedPredicates<'tcx> { } } -newtype_index! { +rustc_index::newtype_index! { /// "Universes" are used during type- and trait-checking in the /// presence of `for<..>` binders to control what sets of names are /// visible. Universes are arranged into a tree: the root universe @@ -1625,11 +1631,7 @@ impl<'a, T> HashStable> for Placeholder where T: HashStable>, { - fn hash_stable( - &self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher - ) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.universe.hash_stable(hcx, hasher); self.name.hash_stable(hcx, hasher); } @@ -1734,7 +1736,6 @@ impl<'tcx> ParamEnv<'tcx> { if value.has_placeholders() || value.needs_infer() || value.has_param_types() - || value.has_self_ty() { ParamEnvAnd { param_env: self, @@ -1767,9 +1768,7 @@ impl<'a, 'tcx, T> HashStable> for ParamEnvAnd<'tcx, T> where T: HashStable>, { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ParamEnvAnd { ref param_env, ref value @@ -1842,7 +1841,8 @@ pub struct VariantDef { pub ctor_kind: CtorKind, /// Flags of the variant (e.g. is field list non-exhaustive)? flags: VariantFlags, - /// Recovered? + /// Variant is obtained as part of recovering from a syntactic error. + /// May be incomplete or bogus. pub recovered: bool, } @@ -1943,13 +1943,19 @@ pub struct FieldDef { pub vis: Visibility, } -/// The definition of an abstract data type -- a struct or enum. +/// The definition of a user-defined type, e.g., a `struct`, `enum`, or `union`. /// /// These are all interned (by `intern_adt_def`) into the `adt_defs` table. +/// +/// The initialism *"Adt"* stands for an [*algebraic data type (ADT)*][adt]. +/// This is slightly wrong because `union`s are not ADTs. +/// Moreover, Rust only allows recursive data types through indirection. +/// +/// [adt]: https://en.wikipedia.org/wiki/Algebraic_data_type pub struct AdtDef { /// `DefId` of the struct, enum or union item. pub did: DefId, - /// Variants of the ADT. If this is a struct or enum, then there will be a single variant. + /// Variants of the ADT. If this is a struct or union, then there will be a single variant. pub variants: IndexVec, /// Flags of the ADT (e.g. is this a struct? is this non-exhaustive?) flags: AdtFlags, @@ -1996,9 +2002,7 @@ impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx AdtDef {} impl<'a> HashStable> for AdtDef { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { thread_local! { static CACHE: RefCell> = Default::default(); } @@ -2064,8 +2068,8 @@ impl_stable_hash_for!(struct ReprFlags { #[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)] pub struct ReprOptions { pub int: Option, - pub align: u32, - pub pack: u32, + pub align: Option, + pub pack: Option, pub flags: ReprFlags, } @@ -2080,18 +2084,19 @@ impl ReprOptions { pub fn new(tcx: TyCtxt<'_>, did: DefId) -> ReprOptions { let mut flags = ReprFlags::empty(); let mut size = None; - let mut max_align = 0; - let mut min_pack = 0; + let mut max_align: Option = None; + let mut min_pack: Option = None; for attr in tcx.get_attrs(did).iter() { for r in attr::find_repr_attrs(&tcx.sess.parse_sess, attr) { flags.insert(match r { attr::ReprC => ReprFlags::IS_C, attr::ReprPacked(pack) => { - min_pack = if min_pack > 0 { - cmp::min(pack, min_pack) + let pack = Align::from_bytes(pack as u64).unwrap(); + min_pack = Some(if let Some(min_pack) = min_pack { + min_pack.min(pack) } else { pack - }; + }); ReprFlags::empty() }, attr::ReprTransparent => ReprFlags::IS_TRANSPARENT, @@ -2101,7 +2106,7 @@ impl ReprOptions { ReprFlags::empty() }, attr::ReprAlign(align) => { - max_align = cmp::max(align, max_align); + max_align = max_align.max(Some(Align::from_bytes(align as u64).unwrap())); ReprFlags::empty() }, }); @@ -2120,7 +2125,7 @@ impl ReprOptions { #[inline] pub fn c(&self) -> bool { self.flags.contains(ReprFlags::IS_C) } #[inline] - pub fn packed(&self) -> bool { self.pack > 0 } + pub fn packed(&self) -> bool { self.pack.is_some() } #[inline] pub fn transparent(&self) -> bool { self.flags.contains(ReprFlags::IS_TRANSPARENT) } #[inline] @@ -2140,8 +2145,12 @@ impl ReprOptions { /// Returns `true` if this `#[repr()]` should inhibit struct field reordering /// optimizations, such as with `repr(C)`, `repr(packed(1))`, or `repr()`. pub fn inhibit_struct_field_reordering_opt(&self) -> bool { - self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.pack == 1 || - self.int.is_some() + if let Some(pack) = self.pack { + if pack.bytes() == 1 { + return true; + } + } + self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.int.is_some() } /// Returns `true` if this `#[repr()]` should inhibit union ABI optimisations. @@ -2359,7 +2368,7 @@ impl<'tcx> AdtDef { pub fn eval_explicit_discr(&self, tcx: TyCtxt<'tcx>, expr_did: DefId) -> Option> { let param_env = tcx.param_env(expr_did); let repr_type = self.repr.discr_type(); - let substs = InternalSubsts::identity_for_item(tcx.global_tcx(), expr_did); + let substs = InternalSubsts::identity_for_item(tcx, expr_did); let instance = ty::Instance::new(expr_did, substs); let cid = GlobalId { instance, @@ -2368,7 +2377,7 @@ impl<'tcx> AdtDef { match tcx.const_eval(param_env.and(cid)) { Ok(val) => { // FIXME: Find the right type and use it instead of `val.ty` here - if let Some(b) = val.try_eval_bits(tcx.global_tcx(), param_env, val.ty) { + if let Some(b) = val.try_eval_bits(tcx, param_env, val.ty) { trace!("discriminants: {} ({:?})", b, repr_type); Some(Discr { val: b, @@ -2404,7 +2413,7 @@ impl<'tcx> AdtDef { tcx: TyCtxt<'tcx>, ) -> impl Iterator)> + Captures<'tcx> { let repr_type = self.repr.discr_type(); - let initial = repr_type.initial_discriminant(tcx.global_tcx()); + let initial = repr_type.initial_discriminant(tcx); let mut prev_discr = None::>; self.variants.iter_enumerated().map(move |(i, v)| { let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx)); @@ -2438,7 +2447,7 @@ impl<'tcx> AdtDef { let (val, offset) = self.discriminant_def_for_variant(variant_index); let explicit_value = val .and_then(|expr_did| self.eval_explicit_discr(tcx, expr_did)) - .unwrap_or_else(|| self.repr.discr_type().initial_discriminant(tcx.global_tcx())); + .unwrap_or_else(|| self.repr.discr_type().initial_discriminant(tcx)); explicit_value.checked_add(tcx, offset as u128).0 } @@ -2488,7 +2497,7 @@ impl<'tcx> AdtDef { } fn sized_constraint_for_ty(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec> { - let result = match ty.sty { + let result = match ty.kind { Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..) | FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => { @@ -2565,6 +2574,8 @@ impl<'tcx> AdtDef { } impl<'tcx> FieldDef { + /// Returns the type of this field. The `subst` is typically obtained + /// via the second field of `TyKind::AdtDef`. pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> { tcx.type_of(self.did).subst(tcx, subst) } @@ -2593,12 +2604,12 @@ impl<'tcx> ClosureKind { pub fn trait_did(&self, tcx: TyCtxt<'tcx>) -> DefId { match *self { - ClosureKind::Fn => tcx.require_lang_item(FnTraitLangItem), + ClosureKind::Fn => tcx.require_lang_item(FnTraitLangItem, None), ClosureKind::FnMut => { - tcx.require_lang_item(FnMutTraitLangItem) + tcx.require_lang_item(FnMutTraitLangItem, None) } ClosureKind::FnOnce => { - tcx.require_lang_item(FnOnceTraitLangItem) + tcx.require_lang_item(FnOnceTraitLangItem, None) } } } @@ -2789,6 +2800,10 @@ impl<'tcx> TyCtxt<'tcx> { }) } + pub fn opt_item_name(self, def_id: DefId) -> Option { + self.hir().as_local_hir_id(def_id).and_then(|hir_id| self.hir().get(hir_id).ident()) + } + pub fn opt_associated_item(self, def_id: DefId) -> Option { let is_associated_item = if let Some(hir_id) = self.hir().as_local_hir_id(def_id) { match self.hir().get(hir_id) { @@ -2892,7 +2907,33 @@ impl<'tcx> TyCtxt<'tcx> { pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> Option { - let is_legit = if self.features().overlapping_marker_traits { + // If either trait impl references an error, they're allowed to overlap, + // as one of them essentially doesn't exist. + if self.impl_trait_ref(def_id1).map_or(false, |tr| tr.references_error()) || + self.impl_trait_ref(def_id2).map_or(false, |tr| tr.references_error()) { + return Some(ImplOverlapKind::Permitted); + } + + match (self.impl_polarity(def_id1), self.impl_polarity(def_id2)) { + (ImplPolarity::Reservation, _) | + (_, ImplPolarity::Reservation) => { + // `#[rustc_reservation_impl]` impls don't overlap with anything + debug!("impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) (reservations)", + def_id1, def_id2); + return Some(ImplOverlapKind::Permitted); + } + (ImplPolarity::Positive, ImplPolarity::Negative) | + (ImplPolarity::Negative, ImplPolarity::Positive) => { + // `impl AutoTrait for Type` + `impl !AutoTrait for Type` + debug!("impls_are_allowed_to_overlap({:?}, {:?}) - None (differing polarities)", + def_id1, def_id2); + return None; + } + (ImplPolarity::Positive, ImplPolarity::Positive) | + (ImplPolarity::Negative, ImplPolarity::Negative) => {} + }; + + let is_marker_overlap = if self.features().overlapping_marker_traits { let trait1_is_empty = self.impl_trait_ref(def_id1) .map_or(false, |trait_ref| { self.associated_item_def_ids(trait_ref.def_id).is_empty() @@ -2901,22 +2942,19 @@ impl<'tcx> TyCtxt<'tcx> { .map_or(false, |trait_ref| { self.associated_item_def_ids(trait_ref.def_id).is_empty() }); - self.impl_polarity(def_id1) == self.impl_polarity(def_id2) - && trait1_is_empty - && trait2_is_empty + trait1_is_empty && trait2_is_empty } else { let is_marker_impl = |def_id: DefId| -> bool { let trait_ref = self.impl_trait_ref(def_id); trait_ref.map_or(false, |tr| self.trait_def(tr.def_id).is_marker) }; - self.impl_polarity(def_id1) == self.impl_polarity(def_id2) - && is_marker_impl(def_id1) - && is_marker_impl(def_id2) + is_marker_impl(def_id1) && is_marker_impl(def_id2) }; - if is_legit { - debug!("impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted)", - def_id1, def_id2); + + if is_marker_overlap { + debug!("impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) (marker overlap)", + def_id1, def_id2); Some(ImplOverlapKind::Permitted) } else { if let Some(self_ty1) = self.issue33140_self_ty(def_id1) { @@ -2988,6 +3026,7 @@ impl<'tcx> TyCtxt<'tcx> { self.optimized_mir(did) } ty::InstanceDef::VtableShim(..) | + ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::Virtual(..) | @@ -3116,7 +3155,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> AssocItem { let parent_id = tcx.hir().get_parent_item(id); let parent_def_id = tcx.hir().local_def_id(parent_id); let parent_item = tcx.hir().expect_item(parent_id); - match parent_item.node { + match parent_item.kind { hir::ItemKind::Impl(.., ref impl_item_refs) => { if let Some(impl_item_ref) = impl_item_refs.iter().find(|i| i.id.hir_id == id) { let assoc_item = tcx.associated_item_from_impl_item_ref(parent_def_id, @@ -3141,7 +3180,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> AssocItem { span_bug!(parent_item.span, "unexpected parent of trait or impl item or item not found: {:?}", - parent_item.node) + parent_item.kind) } #[derive(Clone, HashStable)] @@ -3173,7 +3212,7 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> AdtSizedConstraint<'_ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { let id = tcx.hir().as_local_hir_id(def_id).unwrap(); let item = tcx.hir().expect_item(id); - match item.node { + match item.kind { hir::ItemKind::Trait(.., ref trait_item_refs) => { tcx.arena.alloc_from_iter( trait_item_refs.iter() @@ -3214,7 +3253,7 @@ fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option { pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option { if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) { if let Node::Item(item) = tcx.hir().get(hir_id) { - if let hir::ItemKind::OpaqueTy(ref opaque_ty) = item.node { + if let hir::ItemKind::OpaqueTy(ref opaque_ty) = item.kind { return opaque_ty.impl_trait_fn; } } @@ -3298,7 +3337,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { debug!("issue33140_self_ty({:?}), trait-ref={:?}", def_id, trait_ref); let is_marker_like = - tcx.impl_polarity(def_id) == hir::ImplPolarity::Positive && + tcx.impl_polarity(def_id) == ty::ImplPolarity::Positive && tcx.associated_item_def_ids(trait_ref.def_id).is_empty(); // Check whether these impls would be ok for a marker trait. @@ -3320,7 +3359,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { } let self_ty = trait_ref.self_ty(); - let self_ty_matches = match self_ty.sty { + let self_ty_matches = match self_ty.kind { ty::Dynamic(ref data, ty::ReStatic) => data.principal().is_none(), _ => false }; @@ -3334,6 +3373,22 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { } } +/// Check if a function is async. +fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap_or_else(|| { + bug!("asyncness: expected local `DefId`, got `{:?}`", def_id) + }); + + let node = tcx.hir().get(hir_id); + + let fn_like = hir::map::blocks::FnLikeNode::from_node(node).unwrap_or_else(|| { + bug!("asyncness: expected fn-like node but got `{:?}`", def_id); + }); + + fn_like.asyncness() +} + + pub fn provide(providers: &mut ty::query::Providers<'_>) { context::provide(providers); erase_regions::provide(providers); @@ -3341,6 +3396,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { util::provide(providers); constness::provide(providers); *providers = ty::query::Providers { + asyncness, associated_item, associated_item_def_ids, adt_sized_constraint, @@ -3384,10 +3440,6 @@ impl SymbolName { name: InternedString::intern(name) } } - - pub fn as_str(&self) -> LocalInternedString { - self.name.as_str() - } } impl fmt::Display for SymbolName { diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index 7d1403d1e9662..80e77cdfad0b6 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -60,16 +60,16 @@ impl<'tcx> TyCtxt<'tcx> { // with `collect()` because of the need to sometimes skip subtrees // in the `subtys` iterator (e.g., when encountering a // projection). - match ty.sty { + match ty.kind { ty::Closure(def_id, ref substs) => { - for upvar_ty in substs.upvar_tys(def_id, *self) { + for upvar_ty in substs.as_closure().upvar_tys(def_id, *self) { self.compute_components(upvar_ty, out); } } ty::Generator(def_id, ref substs, _) => { // Same as the closure case - for upvar_ty in substs.upvar_tys(def_id, *self) { + for upvar_ty in substs.as_generator().upvar_tys(def_id, *self) { self.compute_components(upvar_ty, out); } diff --git a/src/librustc/ty/print/mod.rs b/src/librustc/ty/print/mod.rs index 092e7c6f3fffb..d216c81f8a6c2 100644 --- a/src/librustc/ty/print/mod.rs +++ b/src/librustc/ty/print/mod.rs @@ -1,7 +1,7 @@ use crate::hir::map::{DefPathData, DisambiguatedDefPathData}; use crate::hir::def_id::{CrateNum, DefId}; use crate::ty::{self, DefIdTree, Ty, TyCtxt}; -use crate::ty::subst::{Kind, Subst}; +use crate::ty::subst::{GenericArg, Subst}; use rustc_data_structures::fx::FxHashSet; @@ -27,7 +27,8 @@ pub trait Print<'tcx, P> { /// which the associated types allow passing through the methods. /// /// For pretty-printing/formatting in particular, see `PrettyPrinter`. -// FIXME(eddyb) find a better name, this is more general than "printing". +// +// FIXME(eddyb) find a better name; this is more general than "printing". pub trait Printer<'tcx>: Sized { type Error; @@ -42,14 +43,15 @@ pub trait Printer<'tcx>: Sized { fn print_def_path( self, def_id: DefId, - substs: &'tcx [Kind<'tcx>], + substs: &'tcx [GenericArg<'tcx>], ) -> Result { self.default_print_def_path(def_id, substs) } + fn print_impl_path( self, impl_def_id: DefId, - substs: &'tcx [Kind<'tcx>], + substs: &'tcx [GenericArg<'tcx>], self_ty: Ty<'tcx>, trait_ref: Option>, ) -> Result { @@ -80,6 +82,7 @@ pub trait Printer<'tcx>: Sized { self, cnum: CrateNum, ) -> Result; + fn path_qualified( self, self_ty: Ty<'tcx>, @@ -93,15 +96,17 @@ pub trait Printer<'tcx>: Sized { self_ty: Ty<'tcx>, trait_ref: Option>, ) -> Result; + fn path_append( self, print_prefix: impl FnOnce(Self) -> Result, disambiguated_data: &DisambiguatedDefPathData, ) -> Result; + fn path_generic_args( self, print_prefix: impl FnOnce(Self) -> Result, - args: &[Kind<'tcx>], + args: &[GenericArg<'tcx>], ) -> Result; // Defaults (should not be overriden): @@ -109,7 +114,7 @@ pub trait Printer<'tcx>: Sized { fn default_print_def_path( self, def_id: DefId, - substs: &'tcx [Kind<'tcx>], + substs: &'tcx [GenericArg<'tcx>], ) -> Result { debug!("default_print_def_path: def_id={:?}, substs={:?}", def_id, substs); let key = self.tcx().def_key(def_id); @@ -184,8 +189,8 @@ pub trait Printer<'tcx>: Sized { fn generic_args_to_print( &self, generics: &'tcx ty::Generics, - substs: &'tcx [Kind<'tcx>], - ) -> &'tcx [Kind<'tcx>] { + substs: &'tcx [GenericArg<'tcx>], + ) -> &'tcx [GenericArg<'tcx>] { let mut own_params = generics.parent_count..generics.count(); // Don't print args for `Self` parameters (of traits). @@ -198,7 +203,7 @@ pub trait Printer<'tcx>: Sized { match param.kind { ty::GenericParamDefKind::Lifetime => false, ty::GenericParamDefKind::Type { has_default, .. } => { - has_default && substs[param.index as usize] == Kind::from( + has_default && substs[param.index as usize] == GenericArg::from( self.tcx().type_of(param.def_id).subst(self.tcx(), substs) ) } @@ -212,7 +217,7 @@ pub trait Printer<'tcx>: Sized { fn default_print_impl_path( self, impl_def_id: DefId, - _substs: &'tcx [Kind<'tcx>], + _substs: &'tcx [GenericArg<'tcx>], self_ty: Ty<'tcx>, impl_trait_ref: Option>, ) -> Result { @@ -261,7 +266,7 @@ pub trait Printer<'tcx>: Sized { /// type. It's just a heuristic so it makes some questionable /// decisions and we may want to adjust it later. pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option { - match ty.sty { + match ty.kind { ty::Adt(adt_def, _) => Some(adt_def.did), ty::Dynamic(data, ..) => data.principal_def_id(), diff --git a/src/librustc/ty/print/obsolete.rs b/src/librustc/ty/print/obsolete.rs index b68e6a744872f..df39d0ccc9eed 100644 --- a/src/librustc/ty/print/obsolete.rs +++ b/src/librustc/ty/print/obsolete.rs @@ -8,7 +8,7 @@ use rustc::hir::def_id::DefId; use rustc::mir::interpret::ConstValue; use rustc::ty::subst::SubstsRef; -use rustc::ty::{self, ClosureSubsts, Const, GeneratorSubsts, Instance, Ty, TyCtxt}; +use rustc::ty::{self, Const, Instance, Ty, TyCtxt}; use rustc::{bug, hir}; use std::fmt::Write; use std::iter; @@ -34,7 +34,7 @@ impl DefPathBasedNames<'tcx> { // When being used for codegen purposes, `debug` should be set to `false` // in order to catch unexpected types that should never end up in a type name. pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) { - match t.sty { + match t.kind { ty::Bool => output.push_str("bool"), ty::Char => output.push_str("char"), ty::Str => output.push_str("str"), @@ -154,8 +154,8 @@ impl DefPathBasedNames<'tcx> { self.push_type_name(sig.output(), output, debug); } } - ty::Generator(def_id, GeneratorSubsts { ref substs }, _) - | ty::Closure(def_id, ClosureSubsts { ref substs }) => { + ty::Generator(def_id, substs, _) + | ty::Closure(def_id, substs) => { self.push_def_path(def_id, output); let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id)); let substs = substs.truncate_to(self.tcx, generics); diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index bf6741dde43b5..c4967f8d66da2 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -5,13 +5,14 @@ use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use crate::middle::cstore::{ExternCrate, ExternCrateSource}; use crate::middle::region; use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable}; -use crate::ty::subst::{Kind, Subst, UnpackedKind}; +use crate::ty::subst::{GenericArg, Subst, GenericArgKind}; use crate::ty::layout::{Integer, IntegerExt, Size}; use crate::mir::interpret::{ConstValue, sign_extend, Scalar, truncate}; -use syntax::ast; + use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; use rustc_target::spec::abi::Abi; +use syntax::ast; use syntax::attr::{SignedInt, UnsignedInt}; use syntax::symbol::{kw, InternedString}; @@ -182,7 +183,7 @@ pub trait PrettyPrinter<'tcx>: fn print_value_path( self, def_id: DefId, - substs: &'tcx [Kind<'tcx>], + substs: &'tcx [GenericArg<'tcx>], ) -> Result { self.print_def_path(def_id, substs) } @@ -194,7 +195,7 @@ pub trait PrettyPrinter<'tcx>: value.skip_binder().print(self) } - /// Print comma-separated elements. + /// Prints comma-separated elements. fn comma_sep(mut self, mut elems: impl Iterator) -> Result where T: Print<'tcx, Self, Output = Self, Error = Self::Error>, @@ -209,14 +210,14 @@ pub trait PrettyPrinter<'tcx>: Ok(self) } - /// Print `<...>` around what `f` prints. + /// Prints `<...>` around what `f` prints. fn generic_delimiters( self, f: impl FnOnce(Self) -> Result, ) -> Result; - /// Return `true` if the region should be printed in - /// optional positions, e.g. `&'a T` or `dyn Tr + 'b`. + /// Returns `true` if the region should be printed in + /// optional positions, e.g., `&'a T` or `dyn Tr + 'b`. /// This is typically the case for all non-`'_` regions. fn region_should_not_be_omitted( &self, @@ -226,7 +227,7 @@ pub trait PrettyPrinter<'tcx>: // Defaults (should not be overriden): /// If possible, this returns a global path resolving to `def_id` that is visible - /// from at least one local module and returns true. If the crate defining `def_id` is + /// from at least one local module, and returns `true`. If the crate defining `def_id` is /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`. fn try_print_visible_def_path( self, @@ -267,17 +268,17 @@ pub trait PrettyPrinter<'tcx>: // In local mode, when we encounter a crate other than // LOCAL_CRATE, execution proceeds in one of two ways: // - // 1. for a direct dependency, where user added an + // 1. For a direct dependency, where user added an // `extern crate` manually, we put the `extern // crate` as the parent. So you wind up with // something relative to the current crate. - // 2. for an extern inferred from a path or an indirect crate, + // 2. For an extern inferred from a path or an indirect crate, // where there is no explicit `extern crate`, we just prepend // the crate name. match self.tcx().extern_crate(def_id) { Some(&ExternCrate { src: ExternCrateSource::Extern(def_id), - direct: true, + dependency_of: LOCAL_CRATE, span, .. }) => { @@ -304,13 +305,13 @@ pub trait PrettyPrinter<'tcx>: let mut cur_def_key = self.tcx().def_key(def_id); debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key); - // For a constructor we want the name of its parent rather than . + // For a constructor, we want the name of its parent rather than . match cur_def_key.disambiguated_data.data { DefPathData::Ctor => { let parent = DefId { krate: def_id.krate, index: cur_def_key.parent - .expect("DefPathData::Ctor/VariantData missing a parent"), + .expect("`DefPathData::Ctor` / `VariantData` missing a parent"), }; cur_def_key = self.tcx().def_key(parent); @@ -413,7 +414,7 @@ pub trait PrettyPrinter<'tcx>: // Inherent impls. Try to print `Foo::bar` for an inherent // impl on `Foo`, but fallback to `::bar` if self-type is // anything other than a simple path. - match self_ty.sty { + match self_ty.kind { ty::Adt(..) | ty::Foreign(_) | ty::Bool | ty::Char | ty::Str | ty::Int(_) | ty::Uint(_) | ty::Float(_) => { @@ -462,7 +463,7 @@ pub trait PrettyPrinter<'tcx>: ) -> Result { define_scoped_cx!(self); - match ty.sty { + match ty.kind { ty::Bool => p!(write("bool")), ty::Char => p!(write("char")), ty::Int(t) => p!(write("{}", t.ty_to_string())), @@ -604,8 +605,8 @@ pub trait PrettyPrinter<'tcx>: } ty::Str => p!(write("str")), ty::Generator(did, substs, movability) => { - let upvar_tys = substs.upvar_tys(did, self.tcx()); - let witness = substs.witness(did, self.tcx()); + let upvar_tys = substs.as_generator().upvar_tys(did, self.tcx()); + let witness = substs.as_generator().witness(did, self.tcx()); if movability == hir::GeneratorMovability::Movable { p!(write("[generator")); } else { @@ -630,7 +631,7 @@ pub trait PrettyPrinter<'tcx>: sep = ", "; } } else { - // cross-crate closure types should only be + // Cross-crate closure types should only be // visible in codegen bug reports, I imagine. p!(write("@{:?}", did)); let mut sep = " "; @@ -648,7 +649,7 @@ pub trait PrettyPrinter<'tcx>: p!(in_binder(&types)); } ty::Closure(did, substs) => { - let upvar_tys = substs.upvar_tys(did, self.tcx()); + let upvar_tys = substs.as_closure().upvar_tys(did, self.tcx()); p!(write("[closure")); // FIXME(eddyb) should use `def_span`. @@ -673,7 +674,7 @@ pub trait PrettyPrinter<'tcx>: sep = ", "; } } else { - // cross-crate closure types should only be + // Cross-crate closure types should only be // visible in codegen bug reports, I imagine. p!(write("@{:?}", did)); let mut sep = " "; @@ -688,8 +689,8 @@ pub trait PrettyPrinter<'tcx>: if self.tcx().sess.verbose() { p!(write( " closure_kind_ty={:?} closure_sig_ty={:?}", - substs.closure_kind_ty(did, self.tcx()), - substs.closure_sig_ty(did, self.tcx()) + substs.as_closure().kind_ty(did, self.tcx()), + substs.as_closure().sig_ty(did, self.tcx()) )); } @@ -697,7 +698,9 @@ pub trait PrettyPrinter<'tcx>: }, ty::Array(ty, sz) => { p!(write("["), print(ty), write("; ")); - if let ConstValue::Unevaluated(..) = sz.val { + if self.tcx().sess.verbose() { + p!(write("{:?}", sz)); + } else if let ConstValue::Unevaluated(..) = sz.val { // do not try to evalute unevaluated constants. If we are const evaluating an // array length anon const, rustc will (with debug assertions) print the // constant's path. Which will end up here again. @@ -738,7 +741,7 @@ pub trait PrettyPrinter<'tcx>: // Special-case `Fn(...) -> ...` and resugar it. let fn_trait_kind = self.tcx().lang_items().fn_trait_kind(principal.def_id); if !self.tcx().sess.verbose() && fn_trait_kind.is_some() { - if let ty::Tuple(ref args) = principal.substs.type_at(0).sty { + if let ty::Tuple(ref args) = principal.substs.type_at(0).kind { let mut projections = predicates.projection_bounds(); if let (Some(proj), None) = (projections.next(), projections.next()) { let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect(); @@ -763,13 +766,13 @@ pub trait PrettyPrinter<'tcx>: // Don't print `'_` if there's no unerased regions. let print_regions = args.iter().any(|arg| { match arg.unpack() { - UnpackedKind::Lifetime(r) => *r != ty::ReErased, + GenericArgKind::Lifetime(r) => *r != ty::ReErased, _ => false, } }); let mut args = args.iter().cloned().filter(|arg| { match arg.unpack() { - UnpackedKind::Lifetime(_) => print_regions, + GenericArgKind::Lifetime(_) => print_regions, _ => true, } }); @@ -854,120 +857,127 @@ pub trait PrettyPrinter<'tcx>: ) -> Result { define_scoped_cx!(self); - let u8 = self.tcx().types.u8; - if let ty::FnDef(did, substs) = ct.ty.sty { - p!(print_value_path(did, substs)); + if self.tcx().sess.verbose() { + p!(write("Const({:?}: {:?})", ct.val, ct.ty)); return Ok(self); } - if let ConstValue::Unevaluated(did, substs) = ct.val { - match self.tcx().def_kind(did) { - | Some(DefKind::Static) - | Some(DefKind::Const) - | Some(DefKind::AssocConst) => p!(print_value_path(did, substs)), - _ => if did.is_local() { - let span = self.tcx().def_span(did); - if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) { - p!(write("{}", snip)) + + let u8 = self.tcx().types.u8; + + match (ct.val, &ct.ty.kind) { + (_, ty::FnDef(did, substs)) => p!(print_value_path(*did, substs)), + (ConstValue::Unevaluated(did, substs), _) => { + match self.tcx().def_kind(did) { + | Some(DefKind::Static) + | Some(DefKind::Const) + | Some(DefKind::AssocConst) => p!(print_value_path(did, substs)), + _ => if did.is_local() { + let span = self.tcx().def_span(did); + if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) { + p!(write("{}", snip)) + } else { + p!(write("_: "), print(ct.ty)) + } } else { p!(write("_: "), print(ct.ty)) - } + }, + } + }, + (ConstValue::Infer(..), _) => p!(write("_: "), print(ct.ty)), + (ConstValue::Param(ParamConst { name, .. }), _) => p!(write("{}", name)), + (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Bool) => + p!(write("{}", if data == 0 { "false" } else { "true" })), + (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F32)) => + p!(write("{}f32", Single::from_bits(data))), + (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F64)) => + p!(write("{}f64", Double::from_bits(data))), + (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Uint(ui)) => { + let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size(); + let max = truncate(u128::max_value(), bit_size); + + if data == max { + p!(write("std::{}::MAX", ui)) } else { - p!(write("_: "), print(ct.ty)) - }, - } - return Ok(self); - } - if let ConstValue::Infer(..) = ct.val { - p!(write("_: "), print(ct.ty)); - return Ok(self); - } - if let ConstValue::Param(ParamConst { name, .. }) = ct.val { - p!(write("{}", name)); - return Ok(self); - } - if let ConstValue::Scalar(Scalar::Raw { data, .. }) = ct.val { - match ct.ty.sty { - ty::Bool => { - p!(write("{}", if data == 0 { "false" } else { "true" })); - return Ok(self); - }, - ty::Float(ast::FloatTy::F32) => { - p!(write("{}f32", Single::from_bits(data))); - return Ok(self); - }, - ty::Float(ast::FloatTy::F64) => { - p!(write("{}f64", Double::from_bits(data))); - return Ok(self); - }, - ty::Uint(ui) => { - let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(ui)).size(); - let max = truncate(u128::max_value(), bit_size); + p!(write("{}{}", data, ui)) + }; + }, + (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Int(i)) => { + let bit_size = Integer::from_attr(&self.tcx(), SignedInt(*i)) + .size().bits() as u128; + let min = 1u128 << (bit_size - 1); + let max = min - 1; + + let ty = self.tcx().lift(&ct.ty).unwrap(); + let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty)) + .unwrap() + .size; + match data { + d if d == min => p!(write("std::{}::MIN", i)), + d if d == max => p!(write("std::{}::MAX", i)), + _ => p!(write("{}{}", sign_extend(data, size) as i128, i)) + } + }, + (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Char) => + p!(write("{:?}", ::std::char::from_u32(data as u32).unwrap())), + (ConstValue::Scalar(_), ty::RawPtr(_)) => p!(write("{{pointer}}")), + (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::FnPtr(_)) => { + let instance = { + let alloc_map = self.tcx().alloc_map.lock(); + alloc_map.unwrap_fn(ptr.alloc_id) + }; + p!(print_value_path(instance.def_id(), instance.substs)); + }, + _ => { + let printed = if let ty::Ref(_, ref_ty, _) = ct.ty.kind { + let byte_str = match (ct.val, &ref_ty.kind) { + (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => { + let n = n.eval_usize(self.tcx(), ty::ParamEnv::empty()); + Some(self.tcx() + .alloc_map.lock() + .unwrap_memory(ptr.alloc_id) + .get_bytes(&self.tcx(), ptr, Size::from_bytes(n)).unwrap()) + }, + (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => { + // The `inspect` here is okay since we checked the bounds, and there are + // no relocations (we have an active slice reference here). We don't use + // this result to affect interpreter execution. + Some(data.inspect_with_undef_and_ptr_outside_interpreter(start..end)) + }, + _ => None, + }; - if data == max { - p!(write("std::{}::MAX", ui)) + if let Some(byte_str) = byte_str { + p!(write("b\"")); + for &c in byte_str { + for e in std::ascii::escape_default(c) { + self.write_char(e as char)?; + } + } + p!(write("\"")); + true + } else if let (ConstValue::Slice { data, start, end }, ty::Str) = + (ct.val, &ref_ty.kind) + { + // The `inspect` here is okay since we checked the bounds, and there are no + // relocations (we have an active `str` reference here). We don't use this + // result to affect interpreter execution. + let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end); + let s = ::std::str::from_utf8(slice) + .expect("non utf8 str from miri"); + p!(write("{:?}", s)); + true } else { - p!(write("{}{}", data, ui)) - }; - return Ok(self); - }, - ty::Int(i) =>{ - let bit_size = Integer::from_attr(&self.tcx(), SignedInt(i)) - .size().bits() as u128; - let min = 1u128 << (bit_size - 1); - let max = min - 1; - - let ty = self.tcx().lift_to_global(&ct.ty).unwrap(); - let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty)) - .unwrap() - .size; - match data { - d if d == min => p!(write("std::{}::MIN", i)), - d if d == max => p!(write("std::{}::MAX", i)), - _ => p!(write("{}{}", sign_extend(data, size) as i128, i)) - } - return Ok(self); - }, - ty::Char => { - p!(write("{:?}", ::std::char::from_u32(data as u32).unwrap())); - return Ok(self); - } - _ => {}, - } - } - if let ty::Ref(_, ref_ty, _) = ct.ty.sty { - let byte_str = match (ct.val, &ref_ty.sty) { - (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => { - let n = n.eval_usize(self.tcx(), ty::ParamEnv::empty()); - Some(self.tcx() - .alloc_map.lock() - .unwrap_memory(ptr.alloc_id) - .get_bytes(&self.tcx(), ptr, Size::from_bytes(n)).unwrap()) - }, - (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => { - Some(&data.bytes[start..end]) - }, - (ConstValue::Slice { data, start, end }, ty::Str) => { - let slice = &data.bytes[start..end]; - let s = ::std::str::from_utf8(slice) - .expect("non utf8 str from miri"); - p!(write("{:?}", s)); - return Ok(self); - }, - _ => None, - }; - if let Some(byte_str) = byte_str { - p!(write("b\"")); - for &c in byte_str { - for e in std::ascii::escape_default(c) { - self.write_char(e as char)?; + false } + } else { + false + }; + if !printed { + // fallback + p!(write("{:?} : ", ct.val), print(ct.ty)) } - p!(write("\"")); - return Ok(self); } - } - p!(write("{:?} : ", ct.val), print(ct.ty)); - + }; Ok(self) } } @@ -1074,7 +1084,7 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { fn print_def_path( mut self, def_id: DefId, - substs: &'tcx [Kind<'tcx>], + substs: &'tcx [GenericArg<'tcx>], ) -> Result { define_scoped_cx!(self); @@ -1167,6 +1177,7 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { } Ok(self) } + fn path_qualified( mut self, self_ty: Ty<'tcx>, @@ -1195,6 +1206,7 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { self.empty_path = false; Ok(self) } + fn path_append( mut self, print_prefix: impl FnOnce(Self) -> Result, @@ -1232,23 +1244,24 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { Ok(self) } + fn path_generic_args( mut self, print_prefix: impl FnOnce(Self) -> Result, - args: &[Kind<'tcx>], + args: &[GenericArg<'tcx>], ) -> Result { self = print_prefix(self)?; // Don't print `'_` if there's no unerased regions. let print_regions = args.iter().any(|arg| { match arg.unpack() { - UnpackedKind::Lifetime(r) => *r != ty::ReErased, + GenericArgKind::Lifetime(r) => *r != ty::ReErased, _ => false, } }); let args = args.iter().cloned().filter(|arg| { match arg.unpack() { - UnpackedKind::Lifetime(_) => print_regions, + GenericArgKind::Lifetime(_) => print_regions, _ => true, } }); @@ -1272,7 +1285,7 @@ impl PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { fn print_value_path( mut self, def_id: DefId, - substs: &'tcx [Kind<'tcx>], + substs: &'tcx [GenericArg<'tcx>], ) -> Result { let was_in_value = std::mem::replace(&mut self.in_value, true); self = self.print_def_path(def_id, substs)?; @@ -1768,11 +1781,11 @@ define_print_and_forward_display! { } } - Kind<'tcx> { + GenericArg<'tcx> { match self.unpack() { - UnpackedKind::Lifetime(lt) => p!(print(lt)), - UnpackedKind::Type(ty) => p!(print(ty)), - UnpackedKind::Const(ct) => p!(print(ct)), + GenericArgKind::Lifetime(lt) => p!(print(lt)), + GenericArgKind::Type(ty) => p!(print(ty)), + GenericArgKind::Const(ct) => p!(print(ct)), } } } diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index 1cc083ea93c6c..c1c6a655d96a9 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -11,7 +11,7 @@ use crate::util::profiling::ProfileCategory; use std::borrow::Cow; use std::hash::Hash; use std::fmt::Debug; -use rustc_data_structures::sync::Lock; +use rustc_data_structures::sharded::Sharded; use rustc_data_structures::fingerprint::Fingerprint; use crate::ich::StableHashingContext; @@ -34,7 +34,7 @@ pub(crate) trait QueryAccessors<'tcx>: QueryConfig<'tcx> { fn query(key: Self::Key) -> Query<'tcx>; // Don't use this method to access query results, instead use the methods on TyCtxt - fn query_cache<'a>(tcx: TyCtxt<'tcx>) -> &'a Lock>; + fn query_cache<'a>(tcx: TyCtxt<'tcx>) -> &'a Sharded>; fn to_dep_node(tcx: TyCtxt<'tcx>, key: &Self::Key) -> DepNode; @@ -73,6 +73,17 @@ impl<'tcx, M: QueryAccessors<'tcx, Key = DefId>> QueryDescription<'tcx> for M { format!("processing {:?} with query `{}`", def_id, name).into() } } + + default fn cache_on_disk(_: TyCtxt<'tcx>, _: Self::Key, _: Option<&Self::Value>) -> bool { + false + } + + default fn try_load_from_disk( + _: TyCtxt<'tcx>, + _: SerializedDepNodeIndex, + ) -> Option { + bug!("QueryDescription::load_from_disk() called for an unsupported query.") + } } impl<'tcx> QueryDescription<'tcx> for queries::analysis<'tcx> { diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs index a25560ff762a1..391ea762a083b 100644 --- a/src/librustc/ty/query/job.rs +++ b/src/librustc/ty/query/job.rs @@ -334,13 +334,13 @@ fn pick_query<'a, 'tcx, T, F: Fn(&T) -> (Span, Lrc>)>( let mut hcx = tcx.create_stable_hashing_context(); queries.iter().min_by_key(|v| { let (span, query) = f(v); - let mut stable_hasher = StableHasher::::new(); + let mut stable_hasher = StableHasher::new(); query.info.query.hash_stable(&mut hcx, &mut stable_hasher); // Prefer entry points which have valid spans for nicer error messages // We add an integer to the tuple ensuring that entry points // with valid spans are picked first let span_cmp = if span == DUMMY_SP { 1 } else { 0 }; - (span_cmp, stable_hasher.finish()) + (span_cmp, stable_hasher.finish::()) }).unwrap() } diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index fb2ad2aa54d7a..4279ca8c3daf6 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -4,7 +4,6 @@ use crate::hir::def::{DefKind, Export}; use crate::hir::{self, TraitCandidate, ItemLocalId, CodegenFnAttrs}; use crate::infer::canonical::{self, Canonical}; use crate::lint; -use crate::middle::borrowck::{BorrowCheckResult, SignalledError}; use crate::middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary, ForeignModule}; use crate::middle::cstore::{NativeLibraryKind, DepKind, CrateSource}; use crate::middle::privacy::AccessLevels; @@ -38,13 +37,13 @@ use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt, AdtSizedConst use crate::ty::steal::Steal; use crate::ty::util::NeedsDrop; use crate::ty::subst::SubstsRef; -use crate::util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet}; -use crate::util::common::{ErrorReported}; +use crate::util::nodemap::{DefIdSet, DefIdMap}; +use crate::util::common::ErrorReported; use crate::util::profiling::ProfileCategory::*; use rustc_data_structures::svh::Svh; -use rustc_data_structures::bit_set::BitSet; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; use rustc_data_structures::fx::{FxIndexMap, FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::StableVec; use rustc_data_structures::sync::Lrc; diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index 45bc89f5a84ab..1bba7fdd863ea 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -5,9 +5,6 @@ use crate::hir::map::definitions::DefPathHash; use crate::ich::{CachingSourceMapView, Fingerprint}; use crate::mir::{self, interpret}; use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState}; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque, - SpecializedDecoder, SpecializedEncoder, - UseSpecializedDecodable, UseSpecializedEncodable}; use crate::session::{CrateDisambiguator, Session}; use crate::ty::{self, Ty}; use crate::ty::codec::{self as ty_codec, TyDecoder, TyEncoder}; @@ -18,36 +15,39 @@ use errors::Diagnostic; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::thin_vec::ThinVec; use rustc_data_structures::sync::{Lrc, Lock, HashMapExt, Once}; -use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use rustc_index::vec::{IndexVec, Idx}; +use rustc_serialize::{ + Decodable, Decoder, Encodable, Encoder, SpecializedDecoder, SpecializedEncoder, + UseSpecializedDecodable, UseSpecializedEncodable, opaque, +}; use std::mem; -use syntax::ast::NodeId; +use syntax::ast::{Ident, NodeId}; use syntax::source_map::{SourceMap, StableSourceFileId}; use syntax_pos::{BytePos, Span, DUMMY_SP, SourceFile}; -use syntax_pos::hygiene::{ExpnId, SyntaxContext, ExpnInfo}; +use syntax_pos::hygiene::{ExpnId, SyntaxContext}; const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0; const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1; -const TAG_NO_EXPANSION_INFO: u8 = 0; -const TAG_EXPANSION_INFO_SHORTHAND: u8 = 1; -const TAG_EXPANSION_INFO_INLINE: u8 = 2; +const TAG_NO_EXPN_DATA: u8 = 0; +const TAG_EXPN_DATA_SHORTHAND: u8 = 1; +const TAG_EXPN_DATA_INLINE: u8 = 2; const TAG_VALID_SPAN: u8 = 0; const TAG_INVALID_SPAN: u8 = 1; -/// `OnDiskCache` provides an interface to incr. comp. data cached from the +/// Provides an interface to incremental compilation data cached from the /// previous compilation session. This data will eventually include the results /// of a few selected queries (like `typeck_tables_of` and `mir_optimized`) and /// any diagnostics that have been emitted during a query. pub struct OnDiskCache<'sess> { - // The complete cache data in serialized form. serialized_data: Vec, - // This field collects all Diagnostics emitted during the current - // compilation session. + // Collects all `Diagnostic`s emitted during the current compilation + // session. current_diagnostics: Lock>>, prev_cnums: Vec<(u32, String, CrateDisambiguator)>, @@ -56,9 +56,9 @@ pub struct OnDiskCache<'sess> { source_map: &'sess SourceMap, file_index_to_stable_id: FxHashMap, - // These two fields caches that are populated lazily during decoding. + // Caches that are populated lazily during decoding. file_index_to_file: Lock>>, - synthetic_expansion_infos: Lock>, + synthetic_syntax_contexts: Lock>, // A map from dep-node to the position of the cached query result in // `serialized_data`. @@ -78,7 +78,7 @@ struct Footer { prev_cnums: Vec<(u32, String, CrateDisambiguator)>, query_result_index: EncodedQueryResultIndex, diagnostics_index: EncodedQueryResultIndex, - // the location of all allocations + // The location of all allocations. interpret_alloc_index: Vec, } @@ -104,28 +104,28 @@ impl AbsoluteBytePos { } impl<'sess> OnDiskCache<'sess> { - /// Creates a new OnDiskCache instance from the serialized data in `data`. - pub fn new(sess: &'sess Session, data: Vec, start_pos: usize) -> OnDiskCache<'sess> { + /// Creates a new `OnDiskCache` instance from the serialized data in `data`. + pub fn new(sess: &'sess Session, data: Vec, start_pos: usize) -> Self { debug_assert!(sess.opts.incremental.is_some()); - // Wrapping in a scope so we can borrow `data` + // Wrap in a scope so we can borrow `data`. let footer: Footer = { let mut decoder = opaque::Decoder::new(&data[..], start_pos); - // Decode the *position* of the footer which can be found in the + // Decode the *position* of the footer, which can be found in the // last 8 bytes of the file. decoder.set_position(data.len() - IntEncodedWithFixedSize::ENCODED_SIZE); - let query_result_index_pos = IntEncodedWithFixedSize::decode(&mut decoder) - .expect("Error while trying to decode query result index position.") + let footer_pos = IntEncodedWithFixedSize::decode(&mut decoder) + .expect("error while trying to decode footer position") .0 as usize; - // Decoder the file footer which contains all the lookup tables, etc. - decoder.set_position(query_result_index_pos); + // Decode the file footer, which contains all the lookup tables, etc. + decoder.set_position(footer_pos); decode_tagged(&mut decoder, TAG_FILE_FOOTER) - .expect("Error while trying to decode query result index position.") + .expect("error while trying to decode footer position") }; - OnDiskCache { + Self { serialized_data: data, file_index_to_stable_id: footer.file_index_to_stable_id, file_index_to_file: Default::default(), @@ -135,13 +135,13 @@ impl<'sess> OnDiskCache<'sess> { current_diagnostics: Default::default(), query_result_index: footer.query_result_index.into_iter().collect(), prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(), - synthetic_expansion_infos: Default::default(), + synthetic_syntax_contexts: Default::default(), alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index), } } - pub fn new_empty(source_map: &'sess SourceMap) -> OnDiskCache<'sess> { - OnDiskCache { + pub fn new_empty(source_map: &'sess SourceMap) -> Self { + Self { serialized_data: Vec::new(), file_index_to_stable_id: Default::default(), file_index_to_file: Default::default(), @@ -151,18 +151,18 @@ impl<'sess> OnDiskCache<'sess> { current_diagnostics: Default::default(), query_result_index: Default::default(), prev_diagnostics_index: Default::default(), - synthetic_expansion_infos: Default::default(), + synthetic_syntax_contexts: Default::default(), alloc_decoding_state: AllocDecodingState::new(Vec::new()), } } pub fn serialize<'tcx, E>(&self, tcx: TyCtxt<'tcx>, encoder: &mut E) -> Result<(), E::Error> where - E: ty_codec::TyEncoder, + E: TyEncoder, { - // Serializing the DepGraph should not modify it: + // Serializing the `DepGraph` should not modify it. tcx.dep_graph.with_ignore(|| { - // Allocate SourceFileIndices + // Allocate `SourceFileIndex`es. let (file_to_file_index, file_index_to_stable_id) = { let files = tcx.sess.source_map().files(); let mut file_to_file_index = FxHashMap::with_capacity_and_hasher( @@ -185,7 +185,7 @@ impl<'sess> OnDiskCache<'sess> { encoder, type_shorthands: Default::default(), predicate_shorthands: Default::default(), - expn_info_shorthands: Default::default(), + expn_data_shorthands: Default::default(), interpret_allocs: Default::default(), interpret_allocs_inverse: Vec::new(), source_map: CachingSourceMapView::new(tcx.sess.source_map()), @@ -197,7 +197,7 @@ impl<'sess> OnDiskCache<'sess> { // be in memory, so this should be a cheap operation. tcx.dep_graph.exec_cache_promotions(tcx); - // Encode query results + // Encode query results. let mut query_result_index = EncodedQueryResultIndex::new(); time(tcx.sess, "encode query results", || { @@ -221,29 +221,28 @@ impl<'sess> OnDiskCache<'sess> { Ok(()) })?; - // Encode diagnostics + // Encode diagnostics. let diagnostics_index: EncodedDiagnosticsIndex = self.current_diagnostics.borrow() .iter() - .map(|(dep_node_index, diagnostics)| - { - let pos = AbsoluteBytePos::new(encoder.position()); - // Let's make sure we get the expected type here: - let diagnostics: &EncodedDiagnostics = diagnostics; - let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index()); - encoder.encode_tagged(dep_node_index, diagnostics)?; - - Ok((dep_node_index, pos)) - }) - .collect::>()?; + .map(|(dep_node_index, diagnostics)| { + let pos = AbsoluteBytePos::new(encoder.position()); + // Let's make sure we get the expected type here. + let diagnostics: &EncodedDiagnostics = diagnostics; + let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index()); + encoder.encode_tagged(dep_node_index, diagnostics)?; + + Ok((dep_node_index, pos)) + }) + .collect::>()?; let interpret_alloc_index = { let mut interpret_alloc_index = Vec::new(); let mut n = 0; loop { let new_n = encoder.interpret_allocs_inverse.len(); - // if we have found new ids, serialize those, too + // If we have found new IDs, serialize those too. if n == new_n { - // otherwise, abort + // Otherwise, abort. break; } interpret_alloc_index.reserve(new_n - n); @@ -263,13 +262,15 @@ impl<'sess> OnDiskCache<'sess> { }; let sorted_cnums = sorted_cnums_including_local_crate(tcx); - let prev_cnums: Vec<_> = sorted_cnums.iter().map(|&cnum| { - let crate_name = tcx.original_crate_name(cnum).as_str().to_string(); - let crate_disambiguator = tcx.crate_disambiguator(cnum); - (cnum.as_u32(), crate_name, crate_disambiguator) - }).collect(); - - // Encode the file footer + let prev_cnums: Vec<_> = sorted_cnums.iter() + .map(|&cnum| { + let crate_name = tcx.original_crate_name(cnum).as_str().to_string(); + let crate_disambiguator = tcx.crate_disambiguator(cnum); + (cnum.as_u32(), crate_name, crate_disambiguator) + }) + .collect(); + + // Encode the file footer. let footer_pos = encoder.position() as u64; encoder.encode_tagged(TAG_FILE_FOOTER, &Footer { file_index_to_stable_id, @@ -371,7 +372,7 @@ impl<'sess> OnDiskCache<'sess> { { let pos = index.get(&dep_node_index).cloned()?; - // Initialize the cnum_map using the value from the thread which finishes the closure first + // Initialize `cnum_map` using the value from the thread that finishes the closure first. self.cnum_map.init_nonlocking_same(|| { Self::compute_cnum_map(tcx, &self.prev_cnums[..]) }); @@ -381,25 +382,21 @@ impl<'sess> OnDiskCache<'sess> { opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()), source_map: self.source_map, cnum_map: self.cnum_map.get(), + synthetic_syntax_contexts: &self.synthetic_syntax_contexts, file_index_to_file: &self.file_index_to_file, file_index_to_stable_id: &self.file_index_to_stable_id, - synthetic_expansion_infos: &self.synthetic_expansion_infos, alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(), }; match decode_tagged(&mut decoder, dep_node_index) { - Ok(value) => { - Some(value) - } - Err(e) => { - bug!("Could not decode cached {}: {}", debug_tag, e) - } + Ok(v) => Some(v), + Err(e) => bug!("could not decode cached {}: {}", debug_tag, e), } } - // This function builds mapping from previous-session-CrateNum to - // current-session-CrateNum. There might be CrateNums from the previous - // Session that don't occur in the current one. For these, the mapping + // This function builds mapping from previous-session-`CrateNum` to + // current-session-`CrateNum`. There might be `CrateNum`s from the previous + // `Session` that don't occur in the current one. For these, the mapping // maps to None. fn compute_cnum_map( tcx: TyCtxt<'_>, @@ -432,15 +429,15 @@ impl<'sess> OnDiskCache<'sess> { //- DECODING ------------------------------------------------------------------- -/// A decoder that can read the incr. comp. cache. It is similar to the one -/// we use for crate metadata decoding in that it can rebase spans and -/// eventually will also handle things that contain `Ty` instances. +/// A decoder that can read fro the incr. comp. cache. It is similar to the one +/// we use for crate metadata decoding in that it can rebase spans and eventually +/// will also handle things that contain `Ty` instances. struct CacheDecoder<'a, 'tcx> { tcx: TyCtxt<'tcx>, opaque: opaque::Decoder<'a>, source_map: &'a SourceMap, cnum_map: &'a IndexVec>, - synthetic_expansion_infos: &'a Lock>, + synthetic_syntax_contexts: &'a Lock>, file_index_to_file: &'a Lock>>, file_index_to_stable_id: &'a FxHashMap, alloc_decoding_session: AllocDecodingSession<'a>, @@ -458,7 +455,7 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> { file_index_to_file.borrow_mut().entry(index).or_insert_with(|| { let stable_id = file_index_to_stable_id[&index]; source_map.source_file_by_stable_id(stable_id) - .expect("Failed to lookup SourceFile in new context.") + .expect("failed to lookup `SourceFile` in new context") }).clone() } } @@ -479,7 +476,7 @@ impl<'a, 'tcx> DecoderWithPosition for CacheDecoder<'a, 'tcx> { } } -// Decode something that was encoded with encode_tagged() and verify that the +// Decodes something that was encoded with `encode_tagged()` and verify that the // tag matches and the correct amount of bytes was read. fn decode_tagged(decoder: &mut D, expected_tag: T) -> Result where @@ -500,7 +497,7 @@ where Ok(value) } -impl<'a, 'tcx> ty_codec::TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { +impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { #[inline] fn tcx(&self) -> TyCtxt<'tcx> { self.tcx @@ -534,7 +531,7 @@ impl<'a, 'tcx> ty_codec::TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { } let ty = or_insert_with(self)?; - // This may overwrite the entry, but it should overwrite with the same value + // This may overwrite the entry, but it should overwrite with the same value. tcx.rcache.borrow_mut().insert_same(cache_key, ty); Ok(ty) } @@ -553,7 +550,7 @@ impl<'a, 'tcx> ty_codec::TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum { self.cnum_map[cnum].unwrap_or_else(|| { - bug!("Could not find new CrateNum for {:?}", cnum) + bug!("could not find new `CrateNum` for {:?}", cnum) }) } } @@ -586,37 +583,38 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { let lo = file_lo.lines[line_lo - 1] + col_lo; let hi = lo + len; - let expn_info_tag = u8::decode(self)?; + let expn_data_tag = u8::decode(self)?; - // FIXME(mw): This method does not restore `InternalExpnData::parent` or + // FIXME(mw): This method does not restore `ExpnData::parent` or // `SyntaxContextData::prev_ctxt` or `SyntaxContextData::opaque`. These things // don't seem to be used after HIR lowering, so everything should be fine - // as long as incremental compilation does not kick in before that. - let location = || Span::new(lo, hi, SyntaxContext::empty()); - let recover_from_expn_info = |this: &Self, expn_info, pos| { - let span = location().fresh_expansion(ExpnId::root(), expn_info); - this.synthetic_expansion_infos.borrow_mut().insert(pos, span.ctxt()); + // until we want incremental compilation to serialize Spans that we need + // full hygiene information for. + let location = || Span::with_root_ctxt(lo, hi); + let recover_from_expn_data = |this: &Self, expn_data, transparency, pos| { + let span = location().fresh_expansion_with_transparency(expn_data, transparency); + this.synthetic_syntax_contexts.borrow_mut().insert(pos, span.ctxt()); span }; - Ok(match expn_info_tag { - TAG_NO_EXPANSION_INFO => { + Ok(match expn_data_tag { + TAG_NO_EXPN_DATA => { location() } - TAG_EXPANSION_INFO_INLINE => { - let expn_info = Decodable::decode(self)?; - recover_from_expn_info( - self, expn_info, AbsoluteBytePos::new(self.opaque.position()) + TAG_EXPN_DATA_INLINE => { + let (expn_data, transparency) = Decodable::decode(self)?; + recover_from_expn_data( + self, expn_data, transparency, AbsoluteBytePos::new(self.opaque.position()) ) } - TAG_EXPANSION_INFO_SHORTHAND => { + TAG_EXPN_DATA_SHORTHAND => { let pos = AbsoluteBytePos::decode(self)?; - let cached_ctxt = self.synthetic_expansion_infos.borrow().get(&pos).cloned(); + let cached_ctxt = self.synthetic_syntax_contexts.borrow().get(&pos).cloned(); if let Some(ctxt) = cached_ctxt { Span::new(lo, hi, ctxt) } else { - let expn_info = - self.with_position(pos.to_usize(), |this| ExpnInfo::decode(this))?; - recover_from_expn_info(self, expn_info, pos) + let (expn_data, transparency) = + self.with_position(pos.to_usize(), |this| Decodable::decode(this))?; + recover_from_expn_data(self, expn_data, transparency, pos) } } _ => { @@ -626,26 +624,33 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { } } +impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result { + // FIXME: Handle hygiene in incremental + bug!("Trying to decode Ident for incremental"); + } +} + // This impl makes sure that we get a runtime error when we try decode a -// DefIndex that is not contained in a DefId. Such a case would be problematic -// because we would not know how to transform the DefIndex to the current +// `DefIndex` that is not contained in a `DefId`. Such a case would be problematic +// because we would not know how to transform the `DefIndex` to the current // context. impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { fn specialized_decode(&mut self) -> Result { - bug!("Trying to decode DefIndex outside the context of a DefId") + bug!("trying to decode `DefIndex` outside the context of a `DefId`") } } -// Both the CrateNum and the DefIndex of a DefId can change in between two -// compilation sessions. We use the DefPathHash, which is stable across -// sessions, to map the old DefId to the new one. +// Both the `CrateNum` and the `DefIndex` of a `DefId` can change in between two +// compilation sessions. We use the `DefPathHash`, which is stable across +// sessions, to map the old `DefId` to the new one. impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { #[inline] fn specialized_decode(&mut self) -> Result { - // Load the DefPathHash which is was we encoded the DefId as. + // Load the `DefPathHash` which is was we encoded the `DefId` as. let def_path_hash = DefPathHash::decode(self)?; - // Using the DefPathHash, we can lookup the new DefId + // Using the `DefPathHash`, we can lookup the new `DefId`. Ok(self.tcx().def_path_hash_to_def_id.as_ref().unwrap()[&def_path_hash]) } } @@ -659,10 +664,10 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { fn specialized_decode(&mut self) -> Result { - // Load the DefPathHash which is was we encoded the DefIndex as. + // Load the `DefPathHash` which is what we encoded the `DefIndex` as. let def_path_hash = DefPathHash::decode(self)?; - // Use the DefPathHash to map to the current DefId. + // Use the `DefPathHash` to map to the current `DefId`. let def_id = self.tcx() .def_path_hash_to_def_id .as_ref() @@ -670,10 +675,10 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { debug_assert!(def_id.is_local()); - // The ItemLocalId needs no remapping. + // The `ItemLocalId` needs no remapping. let local_id = hir::ItemLocalId::decode(self)?; - // Reconstruct the HirId and look up the corresponding NodeId in the + // Reconstruct the `HirId` and look up the corresponding `NodeId` in the // context of the current session. Ok(hir::HirId { owner: def_id.index, @@ -682,8 +687,8 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { } } -// NodeIds are not stable across compilation sessions, so we store them in their -// HirId representation. This allows use to map them to the current NodeId. +// `NodeId`s are not stable across compilation sessions, so we store them in their +// `HirId` representation. This allows use to map them to the current `NodeId`. impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { #[inline] fn specialized_decode(&mut self) -> Result { @@ -720,12 +725,13 @@ impl<'a, 'tcx, T: Decodable> SpecializedDecoder> //- ENCODING ------------------------------------------------------------------- +/// An encoder that can write the incr. comp. cache. struct CacheEncoder<'a, 'tcx, E: ty_codec::TyEncoder> { tcx: TyCtxt<'tcx>, encoder: &'a mut E, type_shorthands: FxHashMap, usize>, predicate_shorthands: FxHashMap, usize>, - expn_info_shorthands: FxHashMap, + expn_data_shorthands: FxHashMap, interpret_allocs: FxHashMap, interpret_allocs_inverse: Vec, source_map: CachingSourceMapView<'tcx>, @@ -734,7 +740,7 @@ struct CacheEncoder<'a, 'tcx, E: ty_codec::TyEncoder> { impl<'a, 'tcx, E> CacheEncoder<'a, 'tcx, E> where - E: 'a + ty_codec::TyEncoder, + E: 'a + TyEncoder, { fn source_file_index(&mut self, source_file: Lrc) -> SourceFileIndex { self.file_to_file_index[&(&*source_file as *const SourceFile)] @@ -745,11 +751,11 @@ where /// encode the specified tag, then the given value, then the number of /// bytes taken up by tag and value. On decoding, we can then verify that /// we get the expected tag and read the expected number of bytes. - fn encode_tagged(&mut self, - tag: T, - value: &V) - -> Result<(), E::Error> - { + fn encode_tagged( + &mut self, + tag: T, + value: &V + ) -> Result<(), E::Error> { let start_pos = self.position(); tag.encode(self)?; @@ -762,7 +768,7 @@ where impl<'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'a, 'tcx, E> where - E: 'a + ty_codec::TyEncoder, + E: 'a + TyEncoder, { fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> { use std::collections::hash_map::Entry; @@ -782,10 +788,9 @@ where impl<'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'a, 'tcx, E> where - E: 'a + ty_codec::TyEncoder, + E: 'a + TyEncoder, { fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> { - if *span == DUMMY_SP { return TAG_INVALID_SPAN.encode(self); } @@ -816,30 +821,39 @@ where col_lo.encode(self)?; len.encode(self)?; - if span_data.ctxt == SyntaxContext::empty() { - TAG_NO_EXPANSION_INFO.encode(self) + if span_data.ctxt == SyntaxContext::root() { + TAG_NO_EXPN_DATA.encode(self) } else { - let (expn_id, expn_info) = span_data.ctxt.outer_expn_with_info(); - if let Some(expn_info) = expn_info { - if let Some(pos) = self.expn_info_shorthands.get(&expn_id).cloned() { - TAG_EXPANSION_INFO_SHORTHAND.encode(self)?; - pos.encode(self) - } else { - TAG_EXPANSION_INFO_INLINE.encode(self)?; - let pos = AbsoluteBytePos::new(self.position()); - self.expn_info_shorthands.insert(expn_id, pos); - expn_info.encode(self) - } + let (expn_id, transparency, expn_data) = span_data.ctxt.outer_mark_with_data(); + if let Some(pos) = self.expn_data_shorthands.get(&expn_id).cloned() { + TAG_EXPN_DATA_SHORTHAND.encode(self)?; + pos.encode(self) } else { - TAG_NO_EXPANSION_INFO.encode(self) + TAG_EXPN_DATA_INLINE.encode(self)?; + let pos = AbsoluteBytePos::new(self.position()); + self.expn_data_shorthands.insert(expn_id, pos); + (expn_data, transparency).encode(self) } } } } -impl<'a, 'tcx, E> ty_codec::TyEncoder for CacheEncoder<'a, 'tcx, E> +impl<'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'a, 'tcx, E> where E: 'a + ty_codec::TyEncoder, +{ + fn specialized_encode(&mut self, _: &Ident) -> Result<(), Self::Error> { + // We don't currently encode enough information to ensure hygiene works + // with incremental, so panic rather than risk incremental bugs. + + // FIXME: handle hygiene in incremental. + bug!("trying to encode `Ident` for incremental"); + } +} + +impl<'a, 'tcx, E> ty_codec::TyEncoder for CacheEncoder<'a, 'tcx, E> +where + E: 'a + TyEncoder, { #[inline] fn position(&self) -> usize { @@ -849,7 +863,7 @@ where impl<'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'a, 'tcx, E> where - E: 'a + ty_codec::TyEncoder, + E: 'a + TyEncoder, { #[inline] fn specialized_encode(&mut self, cnum: &CrateNum) -> Result<(), Self::Error> { @@ -859,7 +873,7 @@ where impl<'a, 'tcx, E> SpecializedEncoder> for CacheEncoder<'a, 'tcx, E> where - E: 'a + ty_codec::TyEncoder, + E: 'a + TyEncoder, { #[inline] fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> { @@ -870,7 +884,7 @@ where impl<'a, 'tcx, E> SpecializedEncoder> for CacheEncoder<'a, 'tcx, E> where - E: 'a + ty_codec::TyEncoder, + E: 'a + TyEncoder, { #[inline] fn specialized_encode(&mut self, @@ -883,7 +897,7 @@ where impl<'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'a, 'tcx, E> where - E: 'a + ty_codec::TyEncoder, + E: 'a + TyEncoder, { #[inline] fn specialized_encode(&mut self, id: &hir::HirId) -> Result<(), Self::Error> { @@ -901,7 +915,7 @@ where impl<'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'a, 'tcx, E> where - E: 'a + ty_codec::TyEncoder, + E: 'a + TyEncoder, { #[inline] fn specialized_encode(&mut self, id: &DefId) -> Result<(), Self::Error> { @@ -912,7 +926,7 @@ where impl<'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'a, 'tcx, E> where - E: 'a + ty_codec::TyEncoder, + E: 'a + TyEncoder, { #[inline] fn specialized_encode(&mut self, id: &LocalDefId) -> Result<(), Self::Error> { @@ -922,18 +936,18 @@ where impl<'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'a, 'tcx, E> where - E: 'a + ty_codec::TyEncoder, + E: 'a + TyEncoder, { fn specialized_encode(&mut self, _: &DefIndex) -> Result<(), Self::Error> { - bug!("Encoding DefIndex without context.") + bug!("encoding `DefIndex` without context"); } } -// NodeIds are not stable across compilation sessions, so we store them in their -// HirId representation. This allows use to map them to the current NodeId. +// `NodeId`s are not stable across compilation sessions, so we store them in their +// `HirId` representation. This allows use to map them to the current `NodeId`. impl<'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'a, 'tcx, E> where - E: 'a + ty_codec::TyEncoder, + E: 'a + TyEncoder, { #[inline] fn specialized_encode(&mut self, node_id: &NodeId) -> Result<(), Self::Error> { @@ -950,7 +964,7 @@ impl<'a, 'tcx> SpecializedEncoder for CacheEncoder<'a, 'tcx, opaque impl<'a, 'tcx, E, T> SpecializedEncoder> for CacheEncoder<'a, 'tcx, E> where - E: 'a + ty_codec::TyEncoder, + E: 'a + TyEncoder, T: Encodable, { #[inline] @@ -979,7 +993,7 @@ macro_rules! encoder_methods { impl<'a, 'tcx, E> Encoder for CacheEncoder<'a, 'tcx, E> where - E: 'a + ty_codec::TyEncoder, + E: 'a + TyEncoder, { type Error = E::Error; @@ -1023,7 +1037,7 @@ impl UseSpecializedDecodable for IntEncodedWithFixedSize {} impl SpecializedEncoder for opaque::Encoder { fn specialized_encode(&mut self, x: &IntEncodedWithFixedSize) -> Result<(), Self::Error> { let start_pos = self.position(); - for i in 0 .. IntEncodedWithFixedSize::ENCODED_SIZE { + for i in 0..IntEncodedWithFixedSize::ENCODED_SIZE { ((x.0 >> i * 8) as u8).encode(self)?; } let end_pos = self.position(); @@ -1055,24 +1069,23 @@ fn encode_query_results<'a, 'tcx, Q, E>( query_result_index: &mut EncodedQueryResultIndex, ) -> Result<(), E::Error> where - Q: super::config::QueryDescription<'tcx>, + Q: super::config::QueryDescription<'tcx, Value: Encodable>, E: 'a + TyEncoder, - Q::Value: Encodable, { let desc = &format!("encode_query_results for {}", ::std::any::type_name::()); - time_ext(tcx.sess.time_extended(), Some(tcx.sess), desc, || { - let map = Q::query_cache(tcx).borrow(); - assert!(map.active.is_empty()); - for (key, entry) in map.results.iter() { + time_ext(tcx.sess.time_extended(), desc, || { + let shards = Q::query_cache(tcx).lock_shards(); + assert!(shards.iter().all(|shard| shard.active.is_empty())); + for (key, entry) in shards.iter().flat_map(|shard| shard.results.iter()) { if Q::cache_on_disk(tcx, key.clone(), Some(&entry.value)) { let dep_node = SerializedDepNodeIndex::new(entry.index.index()); - // Record position of the cache entry + // Record position of the cache entry. query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.position()))); - // Encode the type check tables with the SerializedDepNodeIndex + // Encode the type check tables with the `SerializedDepNodeIndex` // as tag. encoder.encode_tagged(dep_node, &entry.value)?; } diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index ce9f67db59232..7f05e553bc976 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -9,14 +9,14 @@ use crate::ty::query::Query; use crate::ty::query::config::{QueryConfig, QueryDescription}; use crate::ty::query::job::{QueryJob, QueryResult, QueryInfo}; -use crate::util::common::{profq_msg, ProfileQueriesMsg, QueryMsg}; - use errors::DiagnosticBuilder; use errors::Level; use errors::Diagnostic; use errors::FatalError; +use errors::Handler; use rustc_data_structures::fx::{FxHashMap}; use rustc_data_structures::sync::{Lrc, Lock}; +use rustc_data_structures::sharded::Sharded; use rustc_data_structures::thin_vec::ThinVec; #[cfg(not(parallel_compiler))] use rustc_data_structures::cold_path; @@ -60,44 +60,17 @@ impl<'tcx, M: QueryConfig<'tcx>> Default for QueryCache<'tcx, M> { } } -// If enabled, send a message to the profile-queries thread -macro_rules! profq_msg { - ($tcx:expr, $msg:expr) => { - if cfg!(debug_assertions) { - if $tcx.sess.profile_queries() { - profq_msg($tcx.sess, $msg) - } - } - } -} - -// If enabled, format a key using its debug string, which can be -// expensive to compute (in terms of time). -macro_rules! profq_query_msg { - ($query:expr, $tcx:expr, $key:expr) => {{ - let msg = if cfg!(debug_assertions) { - if $tcx.sess.profile_queries_and_keys() { - Some(format!("{:?}", $key)) - } else { None } - } else { None }; - QueryMsg { - query: $query, - msg, - } - }} -} - /// A type representing the responsibility to execute the job in the `job` field. /// This will poison the relevant query if dropped. pub(super) struct JobOwner<'a, 'tcx, Q: QueryDescription<'tcx>> { - cache: &'a Lock>, + cache: &'a Sharded>, key: Q::Key, job: Lrc>, } impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { /// Either gets a `JobOwner` corresponding the query, allowing us to - /// start executing the query, or it returns with the result of the query. + /// start executing the query, or returns with the result of the query. /// If the query is executing elsewhere, this will wait for it. /// If the query panicked, this will silently panic. /// @@ -107,10 +80,9 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { pub(super) fn try_get(tcx: TyCtxt<'tcx>, span: Span, key: &Q::Key) -> TryGetJob<'a, 'tcx, Q> { let cache = Q::query_cache(tcx); loop { - let mut lock = cache.borrow_mut(); + let mut lock = cache.get_shard_by_value(key).lock(); if let Some(value) = lock.results.get(key) { - profq_msg!(tcx, ProfileQueriesMsg::CacheHit); - tcx.sess.profiler(|p| p.record_query_hit(Q::NAME)); + tcx.prof.query_cache_hit(Q::NAME); let result = (value.value.clone(), value.index); #[cfg(debug_assertions)] { @@ -126,7 +98,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { // in another thread has completed. Record how long we wait in the // self-profiler. #[cfg(parallel_compiler)] - tcx.sess.profiler(|p| p.query_blocked_start(Q::NAME)); + tcx.prof.query_blocked_start(Q::NAME); job.clone() }, @@ -168,7 +140,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { #[cfg(parallel_compiler)] { let result = job.r#await(tcx, span); - tcx.sess.profiler(|p| p.query_blocked_end(Q::NAME)); + tcx.prof.query_blocked_end(Q::NAME); if let Err(cycle) = result { return TryGetJob::Cycle(Q::handle_cycle_error(tcx, cycle)); @@ -191,7 +163,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { let value = QueryValue::new(result.clone(), dep_node_index); { - let mut lock = cache.borrow_mut(); + let mut lock = cache.get_shard_by_value(&key).lock(); lock.active.remove(&key); lock.results.insert(key, value); } @@ -214,29 +186,30 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> Drop for JobOwner<'a, 'tcx, Q> { #[inline(never)] #[cold] fn drop(&mut self) { - // Poison the query so jobs waiting on it panic - self.cache.borrow_mut().active.insert(self.key.clone(), QueryResult::Poisoned); + // Poison the query so jobs waiting on it panic. + let shard = self.cache.get_shard_by_value(&self.key); + shard.lock().active.insert(self.key.clone(), QueryResult::Poisoned); // Also signal the completion of the job, so waiters - // will continue execution + // will continue execution. self.job.signal_complete(); } } #[derive(Clone)] pub struct CycleError<'tcx> { - /// The query and related span which uses the cycle + /// The query and related span that uses the cycle. pub(super) usage: Option<(Span, Query<'tcx>)>, pub(super) cycle: Vec>, } -/// The result of `try_get_lock` +/// The result of `try_get_lock`. pub(super) enum TryGetJob<'a, 'tcx, D: QueryDescription<'tcx>> { /// The query is not yet started. Contains a guard to the cache eventually used to start it. NotYetStarted(JobOwner<'a, 'tcx, D>), /// The query was already completed. - /// Returns the result of the query and its dep node index - /// if it succeeded or a cycle error if it failed + /// Returns the result of the query and its dep-node index + /// if it succeeded or a cycle error if it failed. JobCompleted((D::Value, DepNodeIndex)), /// Trying to execute the query resulted in a cycle. @@ -244,7 +217,7 @@ pub(super) enum TryGetJob<'a, 'tcx, D: QueryDescription<'tcx>> { } impl<'tcx> TyCtxt<'tcx> { - /// Executes a job by changing the ImplicitCtxt to point to the + /// Executes a job by changing the `ImplicitCtxt` to point to the /// new query job while it executes. It returns the diagnostics /// captured during execution and the actual result. #[inline(always)] @@ -257,22 +230,22 @@ impl<'tcx> TyCtxt<'tcx> { where F: FnOnce(TyCtxt<'tcx>) -> R, { - // The TyCtxt stored in TLS has the same global interner lifetime + // The `TyCtxt` stored in TLS has the same global interner lifetime // as `self`, so we use `with_related_context` to relate the 'tcx lifetimes - // when accessing the ImplicitCtxt + // when accessing the `ImplicitCtxt`. tls::with_related_context(self, move |current_icx| { - // Update the ImplicitCtxt to point to our new query job + // Update the `ImplicitCtxt` to point to our new query job. let new_icx = tls::ImplicitCtxt { - tcx: self.global_tcx(), + tcx: self, query: Some(job), diagnostics, layout_depth: current_icx.layout_depth, task_deps: current_icx.task_deps, }; - // Use the ImplicitCtxt while we execute the query + // Use the `ImplicitCtxt` while we execute the query. tls::enter_context(&new_icx, |_| { - compute(self.global_tcx()) + compute(self) }) }) } @@ -319,23 +292,25 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn try_print_query_stack() { + pub fn try_print_query_stack(handler: &Handler) { eprintln!("query stack during panic:"); + // Be careful reyling on global state here: this code is called from + // a panic hook, which means that the global `Handler` may be in a weird + // state if it was responsible for triggering the panic. tls::with_context_opt(|icx| { if let Some(icx) = icx { let mut current_query = icx.query.clone(); let mut i = 0; while let Some(query) = current_query { - let mut db = DiagnosticBuilder::new(icx.tcx.sess.diagnostic(), - Level::FailureNote, + let mut diag = Diagnostic::new(Level::FailureNote, &format!("#{} [{}] {}", i, query.info.query.name(), query.info.query.describe(icx.tcx))); - db.set_span(icx.tcx.sess.source_map().def_span(query.info.span)); - icx.tcx.sess.diagnostic().force_print_db(db); + diag.span = icx.tcx.sess.source_map().def_span(query.info.span).into(); + handler.force_print_diagnostic(diag); current_query = query.parent.clone(); i += 1; @@ -353,13 +328,6 @@ impl<'tcx> TyCtxt<'tcx> { key, span); - profq_msg!(self, - ProfileQueriesMsg::QueryBegin( - span.data(), - profq_query_msg!(Q::NAME.as_str(), self, key), - ) - ); - let job = match JobOwner::try_get(self, span, &key) { TryGetJob::NotYetStarted(job) => job, TryGetJob::Cycle(result) => return result, @@ -370,26 +338,25 @@ impl<'tcx> TyCtxt<'tcx> { }; // Fast path for when incr. comp. is off. `to_dep_node` is - // expensive for some DepKinds. + // expensive for some `DepKind`s. if !self.dep_graph.is_fully_enabled() { let null_dep_node = DepNode::new_no_params(crate::dep_graph::DepKind::Null); return self.force_query_with_job::(key, job, null_dep_node).0; } if Q::ANON { - profq_msg!(self, ProfileQueriesMsg::ProviderBegin); - self.sess.profiler(|p| p.start_query(Q::NAME)); + + let prof_timer = self.prof.query_provider(Q::NAME); let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { self.start_query(job.job.clone(), diagnostics, |tcx| { tcx.dep_graph.with_anon_task(Q::dep_kind(), || { - Q::compute(tcx.global_tcx(), key) + Q::compute(tcx, key) }) }) }); - self.sess.profiler(|p| p.end_query(Q::NAME)); - profq_msg!(self, ProfileQueriesMsg::ProviderEnd); + drop(prof_timer); self.dep_graph.read_index(dep_node_index); @@ -408,7 +375,7 @@ impl<'tcx> TyCtxt<'tcx> { if !Q::EVAL_ALWAYS { // The diagnostics for this query will be // promoted to the current session during - // try_mark_green(), so we can ignore them here. + // `try_mark_green()`, so we can ignore them here. let loaded = self.start_query(job.job.clone(), None, |tcx| { let marked = tcx.dep_graph.try_mark_green_and_read(tcx, &dep_node); marked.map(|(prev_dep_node_index, dep_node_index)| { @@ -439,22 +406,21 @@ impl<'tcx> TyCtxt<'tcx> { dep_node: &DepNode, ) -> Q::Value { // Note this function can be called concurrently from the same query - // We must ensure that this is handled correctly + // We must ensure that this is handled correctly. debug_assert!(self.dep_graph.is_green(dep_node)); - // First we try to load the result from the on-disk cache - let result = if Q::cache_on_disk(self.global_tcx(), key.clone(), None) && + // First we try to load the result from the on-disk cache. + let result = if Q::cache_on_disk(self, key.clone(), None) && self.sess.opts.debugging_opts.incremental_queries { - self.sess.profiler(|p| p.incremental_load_result_start(Q::NAME)); - let result = Q::try_load_from_disk(self.global_tcx(), prev_dep_node_index); - self.sess.profiler(|p| p.incremental_load_result_end(Q::NAME)); + let _prof_timer = self.prof.incr_cache_loading(Q::NAME); + let result = Q::try_load_from_disk(self, prev_dep_node_index); // We always expect to find a cached result for things that - // can be forced from DepNode. + // can be forced from `DepNode`. debug_assert!(!dep_node.kind.can_reconstruct_query_key() || result.is_some(), - "Missing on-disk cache entry for {:?}", + "missing on-disk cache entry for {:?}", dep_node); result } else { @@ -463,36 +429,26 @@ impl<'tcx> TyCtxt<'tcx> { }; let result = if let Some(result) = result { - profq_msg!(self, ProfileQueriesMsg::CacheHit); - self.sess.profiler(|p| p.record_query_hit(Q::NAME)); - result } else { // We could not load a result from the on-disk cache, so // recompute. + let _prof_timer = self.prof.query_provider(Q::NAME); - self.sess.profiler(|p| p.start_query(Q::NAME)); - - // The dep-graph for this computation is already in - // place + // The dep-graph for this computation is already in-place. let result = self.dep_graph.with_ignore(|| { Q::compute(self, key) }); - self.sess.profiler(|p| p.end_query(Q::NAME)); result }; - // If -Zincremental-verify-ich is specified, re-hash results from + // If `-Zincremental-verify-ich` is specified, re-hash results from // the cache and make sure that they have the expected fingerprint. if unlikely!(self.sess.opts.debugging_opts.incremental_verify_ich) { self.incremental_verify_ich::(&result, dep_node, dep_node_index); } - if unlikely!(self.sess.opts.debugging_opts.query_dep_graph) { - self.dep_graph.mark_loaded_from_cache(dep_node_index, true); - } - result } @@ -506,10 +462,12 @@ impl<'tcx> TyCtxt<'tcx> { ) { use crate::ich::Fingerprint; - assert!(Some(self.dep_graph.fingerprint_of(dep_node_index)) == + assert!( + Some(self.dep_graph.fingerprint_of(dep_node_index)) == self.dep_graph.prev_fingerprint_of(dep_node), - "Fingerprint for green query instance not loaded \ - from cache: {:?}", dep_node); + "fingerprint for green query instance not loaded from cache: {:?}", + dep_node, + ); debug!("BEGIN verify_ich({:?})", dep_node); let mut hcx = self.create_stable_hashing_context(); @@ -519,8 +477,11 @@ impl<'tcx> TyCtxt<'tcx> { let old_hash = self.dep_graph.fingerprint_of(dep_node_index); - assert!(new_hash == old_hash, "Found unstable fingerprints \ - for {:?}", dep_node); + assert!( + new_hash == old_hash, + "found unstable fingerprints for {:?}", + dep_node, + ); } #[inline(always)] @@ -532,17 +493,16 @@ impl<'tcx> TyCtxt<'tcx> { ) -> (Q::Value, DepNodeIndex) { // If the following assertion triggers, it can have two reasons: // 1. Something is wrong with DepNode creation, either here or - // in DepGraph::try_mark_green() - // 2. Two distinct query keys get mapped to the same DepNode - // (see for example #48923) + // in `DepGraph::try_mark_green()`. + // 2. Two distinct query keys get mapped to the same `DepNode` + // (see for example #48923). assert!(!self.dep_graph.dep_node_exists(&dep_node), - "Forcing query with already existing DepNode.\n\ + "forcing query with already existing `DepNode`\n\ - query-key: {:?}\n\ - dep-node: {:?}", key, dep_node); - profq_msg!(self, ProfileQueriesMsg::ProviderBegin); - self.sess.profiler(|p| p.start_query(Q::NAME)); + let prof_timer = self.prof.query_provider(Q::NAME); let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { self.start_query(job.job.clone(), diagnostics, |tcx| { @@ -562,12 +522,7 @@ impl<'tcx> TyCtxt<'tcx> { }) }); - self.sess.profiler(|p| p.end_query(Q::NAME)); - profq_msg!(self, ProfileQueriesMsg::ProviderEnd); - - if unlikely!(self.sess.opts.debugging_opts.query_dep_graph) { - self.dep_graph.mark_loaded_from_cache(dep_node_index, false); - } + drop(prof_timer); if unlikely!(!diagnostics.is_empty()) { if dep_node.kind != crate::dep_graph::DepKind::Null { @@ -582,7 +537,7 @@ impl<'tcx> TyCtxt<'tcx> { } /// Ensure that either this query has all green inputs or been executed. - /// Executing query::ensure(D) is considered a read of the dep-node D. + /// Executing `query::ensure(D)` is considered a read of the dep-node `D`. /// /// This function is particularly useful when executing passes for their /// side-effects -- e.g., in order to report errors for erroneous programs. @@ -609,19 +564,12 @@ impl<'tcx> TyCtxt<'tcx> { let _ = self.get_query::(DUMMY_SP, key); } else { - profq_msg!(self, ProfileQueriesMsg::CacheHit); - self.sess.profiler(|p| p.record_query_hit(Q::NAME)); + self.prof.query_cache_hit(Q::NAME); } } #[allow(dead_code)] fn force_query>(self, key: Q::Key, span: Span, dep_node: DepNode) { - profq_msg!( - self, - ProfileQueriesMsg::QueryBegin(span.data(), - profq_query_msg!(Q::NAME.as_str(), self, key)) - ); - // We may be concurrently trying both execute and force a query. // Ensure that only one of them runs the query. let job = match JobOwner::try_get(self, span, &key) { @@ -638,7 +586,7 @@ impl<'tcx> TyCtxt<'tcx> { macro_rules! handle_cycle_error { ([][$tcx: expr, $error:expr]) => {{ $tcx.report_cycle($error).emit(); - Value::from_cycle_error($tcx.global_tcx()) + Value::from_cycle_error($tcx) }}; ([fatal_cycle$(, $modifiers:ident)*][$tcx:expr, $error:expr]) => {{ $tcx.report_cycle($error).emit(); @@ -647,7 +595,7 @@ macro_rules! handle_cycle_error { }}; ([cycle_delay_bug$(, $modifiers:ident)*][$tcx:expr, $error:expr]) => {{ $tcx.report_cycle($error).delay_as_bug(); - Value::from_cycle_error($tcx.global_tcx()) + Value::from_cycle_error($tcx) }}; ([$other:ident$(, $modifiers:ident)*][$($args:tt)*]) => { handle_cycle_error!([$($modifiers),*][$($args)*]) @@ -708,10 +656,9 @@ macro_rules! define_queries_inner { use std::mem; #[cfg(parallel_compiler)] use ty::query::job::QueryResult; - use rustc_data_structures::sync::Lock; + use rustc_data_structures::sharded::Sharded; use crate::{ rustc_data_structures::stable_hasher::HashStable, - rustc_data_structures::stable_hasher::StableHasherResult, rustc_data_structures::stable_hasher::StableHasher, ich::StableHashingContext }; @@ -740,18 +687,17 @@ macro_rules! define_queries_inner { pub fn collect_active_jobs(&self) -> Vec>> { let mut jobs = Vec::new(); - // We use try_lock here since we are only called from the + // We use try_lock_shards here since we are only called from the // deadlock handler, and this shouldn't be locked. $( - jobs.extend( - self.$name.try_lock().unwrap().active.values().filter_map(|v| - if let QueryResult::Started(ref job) = *v { - Some(job.clone()) - } else { - None - } - ) - ); + let shards = self.$name.try_lock_shards().unwrap(); + jobs.extend(shards.iter().flat_map(|shard| shard.active.values().filter_map(|v| + if let QueryResult::Started(ref job) = *v { + Some(job.clone()) + } else { + None + } + ))); )* jobs @@ -773,26 +719,27 @@ macro_rules! define_queries_inner { fn stats<'tcx, Q: QueryConfig<'tcx>>( name: &'static str, - map: &QueryCache<'tcx, Q> + map: &Sharded>, ) -> QueryStats { + let map = map.lock_shards(); QueryStats { name, #[cfg(debug_assertions)] - cache_hits: map.cache_hits, + cache_hits: map.iter().map(|shard| shard.cache_hits).sum(), #[cfg(not(debug_assertions))] cache_hits: 0, key_size: mem::size_of::(), key_type: type_name::(), value_size: mem::size_of::(), value_type: type_name::(), - entry_count: map.results.len(), + entry_count: map.iter().map(|shard| shard.results.len()).sum(), } } $( queries.push(stats::>( stringify!($name), - &*self.$name.lock() + &self.$name, )); )* @@ -897,13 +844,13 @@ macro_rules! define_queries_inner { } } - // FIXME(eddyb) Get more valid Span's on queries. + // FIXME(eddyb) Get more valid `Span`s on queries. pub fn default_span(&self, tcx: TyCtxt<$tcx>, span: Span) -> Span { if !span.is_dummy() { return span; } - // The def_span query is used to calculate default_span, - // so exit to avoid infinite recursion + // The `def_span` query is used to calculate `default_span`, + // so exit to avoid infinite recursion. if let Query::def_span(..) = *self { return span } @@ -920,9 +867,7 @@ macro_rules! define_queries_inner { } impl<'a, $tcx> HashStable> for Query<$tcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { $(Query::$name(key) => key.hash_stable(hcx, hasher),)* @@ -967,7 +912,7 @@ macro_rules! define_queries_inner { } #[inline(always)] - fn query_cache<'a>(tcx: TyCtxt<$tcx>) -> &'a Lock> { + fn query_cache<'a>(tcx: TyCtxt<$tcx>) -> &'a Sharded> { &tcx.queries.$name } @@ -994,7 +939,7 @@ macro_rules! define_queries_inner { // would be missing appropriate entries in `providers`. .unwrap_or(&tcx.queries.fallback_extern_providers) .$name; - provider(tcx.global_tcx(), key) + provider(tcx, key) }) } @@ -1099,7 +1044,7 @@ macro_rules! define_queries_struct { providers: IndexVec>, fallback_extern_providers: Box>, - $($(#[$attr])* $name: Lock>>,)* + $($(#[$attr])* $name: Sharded>>,)* } }; } @@ -1114,7 +1059,7 @@ macro_rules! define_provider_struct { impl<$tcx> Default for Providers<$tcx> { fn default() -> Self { $(fn $name<$tcx>(_: TyCtxt<$tcx>, key: $K) -> $R { - bug!("tcx.{}({:?}) unsupported by its crate", + bug!("`tcx.{}({:?})` unsupported by its crate", stringify!($name), key); })* Providers { $($name),* } @@ -1126,26 +1071,26 @@ macro_rules! define_provider_struct { /// The red/green evaluation system will try to mark a specific DepNode in the /// dependency graph as green by recursively trying to mark the dependencies of -/// that DepNode as green. While doing so, it will sometimes encounter a DepNode +/// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode` /// where we don't know if it is red or green and we therefore actually have /// to recompute its value in order to find out. Since the only piece of -/// information that we have at that point is the DepNode we are trying to +/// information that we have at that point is the `DepNode` we are trying to /// re-evaluate, we need some way to re-run a query from just that. This is what /// `force_from_dep_node()` implements. /// -/// In the general case, a DepNode consists of a DepKind and an opaque +/// In the general case, a `DepNode` consists of a `DepKind` and an opaque /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint /// is usually constructed by computing a stable hash of the query-key that the -/// DepNode corresponds to. Consequently, it is not in general possible to go +/// `DepNode` corresponds to. Consequently, it is not in general possible to go /// back from hash to query-key (since hash functions are not reversible). For /// this reason `force_from_dep_node()` is expected to fail from time to time -/// because we just cannot find out, from the DepNode alone, what the +/// because we just cannot find out, from the `DepNode` alone, what the /// corresponding query-key is and therefore cannot re-run the query. /// /// The system deals with this case letting `try_mark_green` fail which forces /// the root query to be re-evaluated. /// -/// Now, if force_from_dep_node() would always fail, it would be pretty useless. +/// Now, if `force_from_dep_node()` would always fail, it would be pretty useless. /// Fortunately, we can use some contextual information that will allow us to /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a @@ -1169,9 +1114,9 @@ macro_rules! define_provider_struct { pub fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: &DepNode) -> bool { use crate::dep_graph::RecoverKey; - // We must avoid ever having to call force_from_dep_node() for a - // DepNode::codegen_unit: - // Since we cannot reconstruct the query key of a DepNode::codegen_unit, we + // We must avoid ever having to call `force_from_dep_node()` for a + // `DepNode::codegen_unit`: + // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we // would always end up having to evaluate the first caller of the // `codegen_unit` query that *is* reconstructible. This might very well be // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just @@ -1189,56 +1134,37 @@ pub fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: &DepNode) -> bool { return false } - macro_rules! def_id { - () => { - if let Some(def_id) = dep_node.extract_def_id(tcx) { - def_id - } else { - // return from the whole function - return false - } - } - }; - - macro_rules! krate { - () => { (def_id!()).krate } - }; - - macro_rules! force_ex { - ($tcx:expr, $query:ident, $key:expr) => { - { - $tcx.force_query::>( - $key, - DUMMY_SP, - *dep_node - ); - } - } - }; - - macro_rules! force { - ($query:ident, $key:expr) => { force_ex!(tcx, $query, $key) } - }; - rustc_dep_node_force!([dep_node, tcx] // These are inputs that are expected to be pre-allocated and that - // should therefore always be red or green already + // should therefore always be red or green already. DepKind::AllLocalTraitImpls | DepKind::Krate | DepKind::CrateMetadata | DepKind::HirBody | DepKind::Hir | - // This are anonymous nodes + // These are anonymous nodes. DepKind::TraitSelect | // We don't have enough information to reconstruct the query key of - // these + // these. DepKind::CompileCodegenUnit => { - bug!("force_from_dep_node() - Encountered {:?}", dep_node) + bug!("force_from_dep_node: encountered {:?}", dep_node) } - DepKind::Analysis => { force!(analysis, krate!()); } + DepKind::Analysis => { + let def_id = if let Some(def_id) = dep_node.extract_def_id(tcx) { + def_id + } else { + // Return from the whole function. + return false + }; + tcx.force_query::>( + def_id.krate, + DUMMY_SP, + *dep_node + ); + } ); true diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 945e3e158eafb..41f34703622e7 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -5,10 +5,10 @@ //! subtyping, type equality, etc. use crate::hir::def_id::DefId; -use crate::ty::subst::{Kind, UnpackedKind, SubstsRef}; +use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use crate::ty::error::{ExpectedFound, TypeError}; -use crate::mir::interpret::{ConstValue, Scalar, GlobalId}; +use crate::mir::interpret::{ConstValue, get_slice_bytes}; use std::rc::Rc; use std::iter; use rustc_target::spec::abi; @@ -349,7 +349,7 @@ pub fn super_relate_tys>( ) -> RelateResult<'tcx, Ty<'tcx>> { let tcx = relation.tcx(); debug!("super_relate_tys: a={:?} b={:?}", a, b); - match (&a.sty, &b.sty) { + match (&a.kind, &b.kind) { (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { @@ -442,7 +442,7 @@ pub fn super_relate_tys>( // the (anonymous) type of the same closure expression. So // all of their regions should be equated. let substs = relation.relate(&a_substs, &b_substs)?; - Ok(tcx.mk_closure(a_id, substs)) + Ok(tcx.mk_closure(a_id, &substs)) } (&ty::RawPtr(ref a_mt), &ty::RawPtr(ref b_mt)) => @@ -551,26 +551,8 @@ pub fn super_relate_consts>( let tcx = relation.tcx(); let eagerly_eval = |x: &'tcx ty::Const<'tcx>| { - if let ConstValue::Unevaluated(def_id, substs) = x.val { - // FIXME(eddyb) get the right param_env. - let param_env = ty::ParamEnv::empty(); - if !substs.has_local_value() { - let instance = ty::Instance::resolve( - tcx.global_tcx(), - param_env, - def_id, - substs, - ); - if let Some(instance) = instance { - let cid = GlobalId { - instance, - promoted: None, - }; - if let Ok(ct) = tcx.const_eval(param_env.and(cid)) { - return ct.val; - } - } - } + if !x.val.has_local_value() { + return x.eval(tcx, relation.param_env()).val; } x.val }; @@ -579,44 +561,59 @@ pub fn super_relate_consts>( // implement both `PartialEq` and `Eq`, corresponding to // `structural_match` types. // FIXME(const_generics): check for `structural_match` synthetic attribute. - match (eagerly_eval(a), eagerly_eval(b)) { + let new_const_val = match (eagerly_eval(a), eagerly_eval(b)) { (ConstValue::Infer(_), _) | (_, ConstValue::Infer(_)) => { // The caller should handle these cases! bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b) } (ConstValue::Param(a_p), ConstValue::Param(b_p)) if a_p.index == b_p.index => { - Ok(a) + return Ok(a); } (ConstValue::Placeholder(p1), ConstValue::Placeholder(p2)) if p1 == p2 => { - Ok(a) + return Ok(a); } - (a_val @ ConstValue::Scalar(Scalar::Raw { .. }), b_val @ _) - if a.ty == b.ty && a_val == b_val => - { - Ok(tcx.mk_const(ty::Const { - val: a_val, - ty: a.ty, - })) + (ConstValue::Scalar(a_val), ConstValue::Scalar(b_val)) if a.ty == b.ty => { + if a_val == b_val { + Ok(ConstValue::Scalar(a_val)) + } else if let ty::FnPtr(_) = a.ty.kind { + let alloc_map = tcx.alloc_map.lock(); + let a_instance = alloc_map.unwrap_fn(a_val.to_ptr().unwrap().alloc_id); + let b_instance = alloc_map.unwrap_fn(b_val.to_ptr().unwrap().alloc_id); + if a_instance == b_instance { + Ok(ConstValue::Scalar(a_val)) + } else { + Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) + } + } else { + Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) + } } - // FIXME(const_generics): we should either handle `Scalar::Ptr` or add a comment - // saying that we're not handling it intentionally. + (a_val @ ConstValue::Slice { .. }, b_val @ ConstValue::Slice { .. }) => { + let a_bytes = get_slice_bytes(&tcx, a_val); + let b_bytes = get_slice_bytes(&tcx, b_val); + if a_bytes == b_bytes { + Ok(a_val) + } else { + Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) + } + } - // FIXME(const_generics): handle `ConstValue::ByRef` and `ConstValue::Slice`. + // FIXME(const_generics): handle `ConstValue::ByRef`. // FIXME(const_generics): this is wrong, as it is a projection (ConstValue::Unevaluated(a_def_id, a_substs), ConstValue::Unevaluated(b_def_id, b_substs)) if a_def_id == b_def_id => { - let substs = - relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?; - Ok(tcx.mk_const(ty::Const { - val: ConstValue::Unevaluated(a_def_id, &substs), - ty: a.ty, - })) - } - - _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))), - } + let substs = + relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?; + Ok(ConstValue::Unevaluated(a_def_id, &substs)) + } + _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))), + }; + new_const_val.map(|val| tcx.mk_const(ty::Const { + val, + ty: a.ty, + })) } impl<'tcx> Relate<'tcx> for &'tcx ty::List> { @@ -729,29 +726,29 @@ impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for Box { } } -impl<'tcx> Relate<'tcx> for Kind<'tcx> { +impl<'tcx> Relate<'tcx> for GenericArg<'tcx> { fn relate>( relation: &mut R, - a: &Kind<'tcx>, - b: &Kind<'tcx>, - ) -> RelateResult<'tcx, Kind<'tcx>> { + a: &GenericArg<'tcx>, + b: &GenericArg<'tcx>, + ) -> RelateResult<'tcx, GenericArg<'tcx>> { match (a.unpack(), b.unpack()) { - (UnpackedKind::Lifetime(a_lt), UnpackedKind::Lifetime(b_lt)) => { + (GenericArgKind::Lifetime(a_lt), GenericArgKind::Lifetime(b_lt)) => { Ok(relation.relate(&a_lt, &b_lt)?.into()) } - (UnpackedKind::Type(a_ty), UnpackedKind::Type(b_ty)) => { + (GenericArgKind::Type(a_ty), GenericArgKind::Type(b_ty)) => { Ok(relation.relate(&a_ty, &b_ty)?.into()) } - (UnpackedKind::Const(a_ct), UnpackedKind::Const(b_ct)) => { + (GenericArgKind::Const(a_ct), GenericArgKind::Const(b_ct)) => { Ok(relation.relate(&a_ct, &b_ct)?.into()) } - (UnpackedKind::Lifetime(unpacked), x) => { + (GenericArgKind::Lifetime(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } - (UnpackedKind::Type(unpacked), x) => { + (GenericArgKind::Type(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } - (UnpackedKind::Const(unpacked), x) => { + (GenericArgKind::Const(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 649a5244728ba..8945e1a1debdb 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -9,7 +9,7 @@ use crate::mir::interpret::ConstValue; use crate::ty::{self, Lift, Ty, TyCtxt, InferConst}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::print::{FmtPrinter, Printer}; -use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use rustc_index::vec::{IndexVec, Idx}; use smallvec::SmallVec; use crate::mir::interpret; @@ -748,6 +748,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { Sorts(ref x) => return tcx.lift(x).map(Sorts), ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch), ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch), + IntrinsicCast => IntrinsicCast, }) } } @@ -760,6 +761,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> { Some(ty::InstanceDef::Item(def_id)), ty::InstanceDef::VtableShim(def_id) => Some(ty::InstanceDef::VtableShim(def_id)), + ty::InstanceDef::ReifyShim(def_id) => + Some(ty::InstanceDef::ReifyShim(def_id)), ty::InstanceDef::Intrinsic(def_id) => Some(ty::InstanceDef::Intrinsic(def_id)), ty::InstanceDef::FnPtrShim(def_id, ref ty) => @@ -965,6 +968,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { def: match self.def { Item(did) => Item(did.fold_with(folder)), VtableShim(did) => VtableShim(did.fold_with(folder)), + ReifyShim(did) => ReifyShim(did.fold_with(folder)), Intrinsic(did) => Intrinsic(did.fold_with(folder)), FnPtrShim(did, ty) => FnPtrShim( did.fold_with(folder), @@ -993,7 +997,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { use crate::ty::InstanceDef::*; self.substs.visit_with(visitor) || match self.def { - Item(did) | VtableShim(did) | Intrinsic(did) | Virtual(did, _) => { + Item(did) | VtableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => { did.visit_with(visitor) }, FnPtrShim(did, ty) | CloneShim(did, ty) => { @@ -1022,7 +1026,7 @@ impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> { impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { - let sty = match self.sty { + let kind = match self.kind { ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)), ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)), ty::Slice(typ) => ty::Slice(typ.fold_with(folder)), @@ -1063,13 +1067,13 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::Bound(..) | ty::Placeholder(..) | ty::Never | - ty::Foreign(..) => return self + ty::Foreign(..) => return self, }; - if self.sty == sty { + if self.kind == kind { self } else { - folder.tcx().mk_ty(sty) + folder.tcx().mk_ty(kind) } } @@ -1078,7 +1082,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { } fn super_visit_with>(&self, visitor: &mut V) -> bool { - match self.sty { + match self.kind { ty::RawPtr(ref tm) => tm.visit_with(visitor), ty::Array(typ, sz) => typ.visit_with(visitor) || sz.visit_with(visitor), ty::Slice(typ) => typ.visit_with(visitor), @@ -1222,8 +1226,21 @@ BraceStructTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { fn super_fold_with>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|p| p.fold_with(folder)).collect::>(); - folder.tcx().intern_predicates(&v) + // This code is hot enough that it's worth specializing for a list of + // length 0. (No other length is common enough to be worth singling + // out). + if self.len() == 0 { + self + } else { + // Don't bother interning if nothing changed, which is the common + // case. + let v = self.iter().map(|p| p.fold_with(folder)).collect::>(); + if v[..] == self[..] { + self + } else { + folder.tcx().intern_predicates(&v) + } + } } fn super_visit_with>(&self, visitor: &mut V) -> bool { @@ -1338,6 +1355,7 @@ EnumTypeFoldableImpl! { (ty::error::TypeError::Sorts)(x), (ty::error::TypeError::ExistentialMismatch)(x), (ty::error::TypeError::ConstMismatch)(x), + (ty::error::TypeError::IntrinsicCast), } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 064c374de2b4c..4af73fa389a7d 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1,6 +1,6 @@ //! This module contains `TyKind` and its major components. -#![cfg_attr(not(bootstrap), allow(rustc::usage_of_ty_tykind))] +#![allow(rustc::usage_of_ty_tykind)] use crate::hir; use crate::hir::def_id::DefId; @@ -8,9 +8,9 @@ use crate::infer::canonical::Canonical; use crate::mir::interpret::ConstValue; use crate::middle::region; use polonius_engine::Atom; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use rustc_macros::HashStable; -use crate::ty::subst::{InternalSubsts, Subst, SubstsRef, Kind, UnpackedKind}; +use crate::ty::subst::{InternalSubsts, Subst, SubstsRef, GenericArg, GenericArgKind}; use crate::ty::{self, AdtDef, Discr, DefIdTree, TypeFlags, Ty, TyCtxt, TypeFoldable}; use crate::ty::{List, TyS, ParamEnvAnd, ParamEnv}; use crate::ty::layout::VariantIdx; @@ -86,6 +86,7 @@ impl BoundRegion { /// AST structure in `libsyntax/ast.rs` as well. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable, Debug)] +#[rustc_diagnostic_item = "TyKind"] pub enum TyKind<'tcx> { /// The primitive boolean type. Written as `bool`. Bool, @@ -157,11 +158,11 @@ pub enum TyKind<'tcx> { /// The anonymous type of a closure. Used to represent the type of /// `|a| a`. - Closure(DefId, ClosureSubsts<'tcx>), + Closure(DefId, SubstsRef<'tcx>), /// The anonymous type of a generator. Used to represent the type of /// `|a| yield a`. - Generator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability), + Generator(DefId, SubstsRef<'tcx>, hir::GeneratorMovability), /// A type representin the types stored inside a generator. /// This should only appear in GeneratorInteriors. @@ -171,6 +172,7 @@ pub enum TyKind<'tcx> { Never, /// A tuple type. For example, `(i32, bool)`. + /// Use `TyS::tuple_fields` to iterate over the field types. Tuple(SubstsRef<'tcx>), /// The projection of an associated type. For example, @@ -302,8 +304,8 @@ static_assert_size!(TyKind<'_>, 24); /// type parameters is similar, but the role of CK and CS are /// different. CK represents the "yield type" and CS represents the /// "return type" of the generator. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, - Debug, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, + RustcEncodable, RustcDecodable, HashStable)] pub struct ClosureSubsts<'tcx> { /// Lifetime and type parameters from the enclosing function, /// concatenated with the types of the upvars. @@ -318,7 +320,7 @@ pub struct ClosureSubsts<'tcx> { struct SplitClosureSubsts<'tcx> { closure_kind_ty: Ty<'tcx>, closure_sig_ty: Ty<'tcx>, - upvar_kinds: &'tcx [Kind<'tcx>], + upvar_kinds: &'tcx [GenericArg<'tcx>], } impl<'tcx> ClosureSubsts<'tcx> { @@ -343,7 +345,7 @@ impl<'tcx> ClosureSubsts<'tcx> { ) -> impl Iterator> + 'tcx { let SplitClosureSubsts { upvar_kinds, .. } = self.split(def_id, tcx); upvar_kinds.iter().map(|t| { - if let UnpackedKind::Type(ty) = t.unpack() { + if let GenericArgKind::Type(ty) = t.unpack() { ty } else { bug!("upvar should be type") @@ -354,7 +356,7 @@ impl<'tcx> ClosureSubsts<'tcx> { /// Returns the closure kind for this closure; may return a type /// variable during inference. To get the closure kind during /// inference, use `infcx.closure_kind(def_id, substs)`. - pub fn closure_kind_ty(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> { + pub fn kind_ty(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> { self.split(def_id, tcx).closure_kind_ty } @@ -362,7 +364,7 @@ impl<'tcx> ClosureSubsts<'tcx> { /// closure; may contain type variables during inference. To get /// the closure signature during inference, use /// `infcx.fn_sig(def_id)`. - pub fn closure_sig_ty(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> { + pub fn sig_ty(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> { self.split(def_id, tcx).closure_sig_ty } @@ -371,7 +373,7 @@ impl<'tcx> ClosureSubsts<'tcx> { /// there are no type variables. /// /// If you have an inference context, use `infcx.closure_kind()`. - pub fn closure_kind(self, def_id: DefId, tcx: TyCtxt<'tcx>) -> ty::ClosureKind { + pub fn kind(self, def_id: DefId, tcx: TyCtxt<'tcx>) -> ty::ClosureKind { self.split(def_id, tcx).closure_kind_ty.to_opt_closure_kind().unwrap() } @@ -380,11 +382,11 @@ impl<'tcx> ClosureSubsts<'tcx> { /// there are no type variables. /// /// If you have an inference context, use `infcx.closure_sig()`. - pub fn closure_sig(self, def_id: DefId, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { - let ty = self.closure_sig_ty(def_id, tcx); - match ty.sty { + pub fn sig(&self, def_id: DefId, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { + let ty = self.sig_ty(def_id, tcx); + match ty.kind { ty::FnPtr(sig) => sig, - _ => bug!("closure_sig_ty is not a fn-ptr: {:?}", ty), + _ => bug!("closure_sig_ty is not a fn-ptr: {:?}", ty.kind), } } } @@ -400,7 +402,7 @@ struct SplitGeneratorSubsts<'tcx> { yield_ty: Ty<'tcx>, return_ty: Ty<'tcx>, witness: Ty<'tcx>, - upvar_kinds: &'tcx [Kind<'tcx>], + upvar_kinds: &'tcx [GenericArg<'tcx>], } impl<'tcx> GeneratorSubsts<'tcx> { @@ -432,7 +434,7 @@ impl<'tcx> GeneratorSubsts<'tcx> { ) -> impl Iterator> + 'tcx { let SplitGeneratorSubsts { upvar_kinds, .. } = self.split(def_id, tcx); upvar_kinds.iter().map(|t| { - if let UnpackedKind::Type(ty) = t.unpack() { + if let GenericArgKind::Type(ty) = t.unpack() { ty } else { bug!("upvar should be type") @@ -509,7 +511,7 @@ impl<'tcx> GeneratorSubsts<'tcx> { /// variant indices. #[inline] pub fn discriminants( - &'tcx self, + self, def_id: DefId, tcx: TyCtxt<'tcx>, ) -> impl Iterator)> + Captures<'tcx> { @@ -521,7 +523,7 @@ impl<'tcx> GeneratorSubsts<'tcx> { /// Calls `f` with a reference to the name of the enumerator for the given /// variant `v`. #[inline] - pub fn variant_name(&self, v: VariantIdx) -> Cow<'static, str> { + pub fn variant_name(self, v: VariantIdx) -> Cow<'static, str> { match v.as_usize() { Self::UNRESUMED => Cow::from(Self::UNRESUMED_NAME), Self::RETURNED => Cow::from(Self::RETURNED_NAME), @@ -566,8 +568,8 @@ impl<'tcx> GeneratorSubsts<'tcx> { #[derive(Debug, Copy, Clone)] pub enum UpvarSubsts<'tcx> { - Closure(ClosureSubsts<'tcx>), - Generator(GeneratorSubsts<'tcx>), + Closure(SubstsRef<'tcx>), + Generator(SubstsRef<'tcx>), } impl<'tcx> UpvarSubsts<'tcx> { @@ -575,14 +577,14 @@ impl<'tcx> UpvarSubsts<'tcx> { pub fn upvar_tys( self, def_id: DefId, - tcx: TyCtxt<'_>, + tcx: TyCtxt<'tcx>, ) -> impl Iterator> + 'tcx { let upvar_kinds = match self { - UpvarSubsts::Closure(substs) => substs.split(def_id, tcx).upvar_kinds, - UpvarSubsts::Generator(substs) => substs.split(def_id, tcx).upvar_kinds, + UpvarSubsts::Closure(substs) => substs.as_closure().split(def_id, tcx).upvar_kinds, + UpvarSubsts::Generator(substs) => substs.as_generator().split(def_id, tcx).upvar_kinds, }; upvar_kinds.iter().map(|t| { - if let UnpackedKind::Type(ty) = t.unpack() { + if let GenericArgKind::Type(ty) = t.unpack() { ty } else { bug!("upvar should be type") @@ -642,7 +644,7 @@ impl<'tcx> Binder> { impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx List> {} impl<'tcx> List> { - /// Returns the "principal def id" of this set of existential predicates. + /// Returns the "principal `DefId`" of this set of existential predicates. /// /// A Rust trait object type consists (in addition to a lifetime bound) /// of a set of trait bounds, which are separated into any number @@ -1050,7 +1052,7 @@ impl<'tcx> PolyGenSig<'tcx> { } } -/// Signature of a function type, which I have arbitrarily +/// Signature of a function type, which we have arbitrarily /// decided to use to refer to the input/output types. /// /// - `inputs`: is the list of arguments and their modes. @@ -1074,7 +1076,8 @@ impl<'tcx> FnSig<'tcx> { self.inputs_and_output[self.inputs_and_output.len() - 1] } - // Create a minimal `FnSig` to be used when encountering a `TyKind::Error` in a fallible method + // Creates a minimal `FnSig` to be used when encountering a `TyKind::Error` in a fallible + // method. fn fake() -> FnSig<'tcx> { FnSig { inputs_and_output: List::empty(), @@ -1116,7 +1119,6 @@ impl<'tcx> PolyFnSig<'tcx> { pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder>>; - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable)] pub struct ParamTy { @@ -1140,13 +1142,6 @@ impl<'tcx> ParamTy { pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { tcx.mk_ty_param(self.index, self.name) } - - pub fn is_self(&self) -> bool { - // FIXME(#50125): Ignoring `Self` with `index != 0` might lead to weird behavior elsewhere, - // but this should only be possible when using `-Z continue-parse-after-error` like - // `compile-fail/issue-36638.rs`. - self.name.as_symbol() == kw::SelfUpper && self.index == 0 - } } #[derive(Copy, Clone, Hash, RustcEncodable, RustcDecodable, @@ -1170,7 +1165,7 @@ impl<'tcx> ParamConst { } } -newtype_index! { +rustc_index::newtype_index! { /// A [De Bruijn index][dbi] is a standard means of representing /// regions (and perhaps later types) in a higher-ranked setting. In /// particular, imagine a type like this: @@ -1354,7 +1349,7 @@ pub struct FloatVid { pub index: u32, } -newtype_index! { +rustc_index::newtype_index! { pub struct RegionVid { DEBUG_FORMAT = custom, } @@ -1381,7 +1376,7 @@ pub enum InferTy { FreshFloatTy(u32), } -newtype_index! { +rustc_index::newtype_index! { pub struct BoundVar { .. } } @@ -1683,7 +1678,7 @@ impl RegionKind { impl<'tcx> TyS<'tcx> { #[inline] pub fn is_unit(&self) -> bool { - match self.sty { + match self.kind { Tuple(ref tys) => tys.is_empty(), _ => false, } @@ -1691,7 +1686,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_never(&self) -> bool { - match self.sty { + match self.kind { Never => true, _ => false, } @@ -1706,7 +1701,7 @@ impl<'tcx> TyS<'tcx> { pub fn conservative_is_privately_uninhabited(&self, tcx: TyCtxt<'tcx>) -> bool { // FIXME(varkor): we can make this less conversative by substituting concrete // type arguments. - match self.sty { + match self.kind { ty::Never => true, ty::Adt(def, _) if def.is_union() => { // For now, `union`s are never considered uninhabited. @@ -1723,8 +1718,8 @@ impl<'tcx> TyS<'tcx> { }) }) } - ty::Tuple(tys) => tys.iter().any(|ty| { - ty.expect_ty().conservative_is_privately_uninhabited(tcx) + ty::Tuple(..) => self.tuple_fields().any(|ty| { + ty.conservative_is_privately_uninhabited(tcx) }), ty::Array(ty, len) => { match len.try_eval_usize(tcx, ParamEnv::empty()) { @@ -1746,7 +1741,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_primitive(&self) -> bool { - match self.sty { + match self.kind { Bool | Char | Int(_) | Uint(_) | Float(_) => true, _ => false, } @@ -1754,7 +1749,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_ty_var(&self) -> bool { - match self.sty { + match self.kind { Infer(TyVar(_)) => true, _ => false, } @@ -1762,7 +1757,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_ty_infer(&self) -> bool { - match self.sty { + match self.kind { Infer(_) => true, _ => false, } @@ -1770,7 +1765,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_phantom_data(&self) -> bool { - if let Adt(def, _) = self.sty { + if let Adt(def, _) = self.kind { def.is_phantom_data() } else { false @@ -1778,28 +1773,24 @@ impl<'tcx> TyS<'tcx> { } #[inline] - pub fn is_bool(&self) -> bool { self.sty == Bool } + pub fn is_bool(&self) -> bool { self.kind == Bool } + /// Returns `true` if this type is a `str`. #[inline] - pub fn is_param(&self, index: u32) -> bool { - match self.sty { - ty::Param(ref data) => data.index == index, - _ => false, - } - } + pub fn is_str(&self) -> bool { self.kind == Str } #[inline] - pub fn is_self(&self) -> bool { - match self.sty { - Param(ref p) => p.is_self(), + pub fn is_param(&self, index: u32) -> bool { + match self.kind { + ty::Param(ref data) => data.index == index, _ => false, } } #[inline] pub fn is_slice(&self) -> bool { - match self.sty { - RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => match ty.sty { + match self.kind { + RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => match ty.kind { Slice(_) | Str => true, _ => false, }, @@ -1809,14 +1800,14 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_simd(&self) -> bool { - match self.sty { + match self.kind { Adt(def, _) => def.repr.simd(), _ => false, } } pub fn sequence_element_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match self.sty { + match self.kind { Array(ty, _) | Slice(ty) => ty, Str => tcx.mk_mach_uint(ast::UintTy::U8), _ => bug!("sequence_element_type called on non-sequence value: {}", self), @@ -1824,7 +1815,7 @@ impl<'tcx> TyS<'tcx> { } pub fn simd_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match self.sty { + match self.kind { Adt(def, substs) => { def.non_enum_variant().fields[0].ty(tcx, substs) } @@ -1833,7 +1824,7 @@ impl<'tcx> TyS<'tcx> { } pub fn simd_size(&self, _cx: TyCtxt<'_>) -> usize { - match self.sty { + match self.kind { Adt(def, _) => def.non_enum_variant().fields.len(), _ => bug!("simd_size called on invalid type") } @@ -1841,7 +1832,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_region_ptr(&self) -> bool { - match self.sty { + match self.kind { Ref(..) => true, _ => false, } @@ -1849,7 +1840,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_mutable_ptr(&self) -> bool { - match self.sty { + match self.kind { RawPtr(TypeAndMut { mutbl: hir::Mutability::MutMutable, .. }) | Ref(_, _, hir::Mutability::MutMutable) => true, _ => false @@ -1858,7 +1849,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_unsafe_ptr(&self) -> bool { - match self.sty { + match self.kind { RawPtr(_) => return true, _ => return false, } @@ -1873,7 +1864,7 @@ impl<'tcx> TyS<'tcx> { /// Returns `true` if this type is an `Arc`. #[inline] pub fn is_arc(&self) -> bool { - match self.sty { + match self.kind { Adt(def, _) => def.is_arc(), _ => false, } @@ -1882,7 +1873,7 @@ impl<'tcx> TyS<'tcx> { /// Returns `true` if this type is an `Rc`. #[inline] pub fn is_rc(&self) -> bool { - match self.sty { + match self.kind { Adt(def, _) => def.is_rc(), _ => false, } @@ -1890,7 +1881,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_box(&self) -> bool { - match self.sty { + match self.kind { Adt(def, _) => def.is_box(), _ => false, } @@ -1898,7 +1889,7 @@ impl<'tcx> TyS<'tcx> { /// panics if called on any type other than `Box` pub fn boxed_ty(&self) -> Ty<'tcx> { - match self.sty { + match self.kind { Adt(def, substs) if def.is_box() => substs.type_at(0), _ => bug!("`boxed_ty` is called on non-box type {:?}", self), } @@ -1909,7 +1900,7 @@ impl<'tcx> TyS<'tcx> { /// contents are abstract to rustc.) #[inline] pub fn is_scalar(&self) -> bool { - match self.sty { + match self.kind { Bool | Char | Int(_) | Float(_) | Uint(_) | Infer(IntVar(_)) | Infer(FloatVar(_)) | FnDef(..) | FnPtr(_) | RawPtr(_) => true, @@ -1920,7 +1911,7 @@ impl<'tcx> TyS<'tcx> { /// Returns `true` if this type is a floating point type. #[inline] pub fn is_floating_point(&self) -> bool { - match self.sty { + match self.kind { Float(_) | Infer(FloatVar(_)) => true, _ => false, @@ -1929,7 +1920,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_trait(&self) -> bool { - match self.sty { + match self.kind { Dynamic(..) => true, _ => false, } @@ -1937,7 +1928,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_enum(&self) -> bool { - match self.sty { + match self.kind { Adt(adt_def, _) => { adt_def.is_enum() } @@ -1947,7 +1938,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_closure(&self) -> bool { - match self.sty { + match self.kind { Closure(..) => true, _ => false, } @@ -1955,7 +1946,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_generator(&self) -> bool { - match self.sty { + match self.kind { Generator(..) => true, _ => false, } @@ -1963,7 +1954,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_integral(&self) -> bool { - match self.sty { + match self.kind { Infer(IntVar(_)) | Int(_) | Uint(_) => true, _ => false } @@ -1971,7 +1962,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_fresh_ty(&self) -> bool { - match self.sty { + match self.kind { Infer(FreshTy(_)) => true, _ => false, } @@ -1979,7 +1970,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_fresh(&self) -> bool { - match self.sty { + match self.kind { Infer(FreshTy(_)) => true, Infer(FreshIntTy(_)) => true, Infer(FreshFloatTy(_)) => true, @@ -1989,7 +1980,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_char(&self) -> bool { - match self.sty { + match self.kind { Char => true, _ => false, } @@ -2002,7 +1993,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_signed(&self) -> bool { - match self.sty { + match self.kind { Int(_) => true, _ => false, } @@ -2010,7 +2001,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_ptr_sized_integral(&self) -> bool { - match self.sty { + match self.kind { Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize) => true, _ => false, } @@ -2018,7 +2009,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_machine(&self) -> bool { - match self.sty { + match self.kind { Int(..) | Uint(..) | Float(..) => true, _ => false, } @@ -2026,7 +2017,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn has_concrete_skeleton(&self) -> bool { - match self.sty { + match self.kind { Param(_) | Infer(_) | Error => false, _ => true, } @@ -2037,7 +2028,7 @@ impl<'tcx> TyS<'tcx> { /// The parameter `explicit` indicates if this is an *explicit* dereference. /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly. pub fn builtin_deref(&self, explicit: bool) -> Option> { - match self.sty { + match self.kind { Adt(def, _) if def.is_box() => { Some(TypeAndMut { ty: self.boxed_ty(), @@ -2052,14 +2043,14 @@ impl<'tcx> TyS<'tcx> { /// Returns the type of `ty[i]`. pub fn builtin_index(&self) -> Option> { - match self.sty { + match self.kind { Array(ty, _) | Slice(ty) => Some(ty), _ => None, } } pub fn fn_sig(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { - match self.sty { + match self.kind { FnDef(def_id, substs) => { tcx.fn_sig(def_id).subst(tcx, substs) } @@ -2067,13 +2058,16 @@ impl<'tcx> TyS<'tcx> { Error => { // ignore errors (#54954) ty::Binder::dummy(FnSig::fake()) } + Closure(..) => bug!( + "to get the signature of a closure, use `closure_sig()` not `fn_sig()`", + ), _ => bug!("Ty::fn_sig() called on non-fn type: {:?}", self) } } #[inline] pub fn is_fn(&self) -> bool { - match self.sty { + match self.kind { FnDef(..) | FnPtr(_) => true, _ => false, } @@ -2081,7 +2075,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_fn_ptr(&self) -> bool { - match self.sty { + match self.kind { FnPtr(_) => true, _ => false, } @@ -2089,7 +2083,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_impl_trait(&self) -> bool { - match self.sty { + match self.kind { Opaque(..) => true, _ => false, } @@ -2097,19 +2091,29 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn ty_adt_def(&self) -> Option<&'tcx AdtDef> { - match self.sty { + match self.kind { Adt(adt, _) => Some(adt), _ => None, } } + /// Iterates over tuple fields. + /// Panics when called on anything but a tuple. + pub fn tuple_fields(&self) -> impl DoubleEndedIterator> { + match self.kind { + Tuple(substs) => substs.iter().map(|field| field.expect_ty()), + _ => bug!("tuple_fields called on non-tuple"), + } + } + /// If the type contains variants, returns the valid range of variant indices. /// FIXME This requires the optimized MIR in the case of generators. #[inline] pub fn variant_range(&self, tcx: TyCtxt<'tcx>) -> Option> { - match self.sty { + match self.kind { TyKind::Adt(adt, _) => Some(adt.variant_range()), - TyKind::Generator(def_id, substs, _) => Some(substs.variant_range(def_id, tcx)), + TyKind::Generator(def_id, substs, _) => + Some(substs.as_generator().variant_range(def_id, tcx)), _ => None, } } @@ -2123,10 +2127,10 @@ impl<'tcx> TyS<'tcx> { tcx: TyCtxt<'tcx>, variant_index: VariantIdx, ) -> Option> { - match self.sty { + match self.kind { TyKind::Adt(adt, _) => Some(adt.discriminant_for_variant(tcx, variant_index)), TyKind::Generator(def_id, substs, _) => - Some(substs.discriminant_for_variant(def_id, tcx, variant_index)), + Some(substs.as_generator().discriminant_for_variant(def_id, tcx, variant_index)), _ => None, } } @@ -2135,7 +2139,7 @@ impl<'tcx> TyS<'tcx> { /// types reachable from this type via `walk_tys`). This ignores late-bound /// regions binders. pub fn push_regions(&self, out: &mut SmallVec<[ty::Region<'tcx>; 4]>) { - match self.sty { + match self.kind { Ref(region, _, _) => { out.push(region); } @@ -2148,8 +2152,8 @@ impl<'tcx> TyS<'tcx> { Adt(_, substs) | Opaque(_, substs) => { out.extend(substs.regions()) } - Closure(_, ClosureSubsts { ref substs }) | - Generator(_, GeneratorSubsts { ref substs }, _) => { + Closure(_, ref substs ) | + Generator(_, ref substs, _) => { out.extend(substs.regions()) } Projection(ref data) | UnnormalizedProjection(ref data) => { @@ -2191,7 +2195,7 @@ impl<'tcx> TyS<'tcx> { /// inferred. Once upvar inference (in `src/librustc_typeck/check/upvar.rs`) /// is complete, that type variable will be unified. pub fn to_opt_closure_kind(&self) -> Option { - match self.sty { + match self.kind { Int(int_ty) => match int_ty { ast::IntTy::I8 => Some(ty::ClosureKind::Fn), ast::IntTy::I16 => Some(ty::ClosureKind::FnMut), @@ -2199,7 +2203,9 @@ impl<'tcx> TyS<'tcx> { _ => bug!("cannot convert type `{:?}` to a closure kind", self), }, - Infer(_) => None, + // "Bound" types appear in canonical queries when the + // closure type is not yet known + Bound(..) | Infer(_) => None, Error => Some(ty::ClosureKind::Fn), @@ -2212,7 +2218,7 @@ impl<'tcx> TyS<'tcx> { /// Returning true means the type is known to be sized. Returning /// `false` means nothing -- could be sized, might not be. pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool { - match self.sty { + match self.kind { ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) | ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Float(_) | ty::FnDef(..) | ty::FnPtr(_) | ty::RawPtr(..) | @@ -2299,25 +2305,35 @@ impl<'tcx> Const<'tcx> { ty: Ty<'tcx>, ) -> Option { assert_eq!(self.ty, ty); - // if `ty` does not depend on generic parameters, use an empty param_env let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size; + // if `ty` does not depend on generic parameters, use an empty param_env + self.eval(tcx, param_env).val.try_to_bits(size) + } + + #[inline] + pub fn eval( + &self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ) -> &Const<'tcx> { + // FIXME(const_generics): this doesn't work right now, + // because it tries to relate an `Infer` to a `Param`. match self.val { - // FIXME(const_generics): this doesn't work right now, - // because it tries to relate an `Infer` to a `Param`. ConstValue::Unevaluated(did, substs) => { // if `substs` has no unresolved components, use and empty param_env let (param_env, substs) = param_env.with_reveal_all().and(substs).into_parts(); // try to resolve e.g. associated constants to their definition on an impl - let instance = ty::Instance::resolve(tcx, param_env, did, substs)?; + let instance = match ty::Instance::resolve(tcx, param_env, did, substs) { + Some(instance) => instance, + None => return self, + }; let gid = GlobalId { instance, promoted: None, }; - let evaluated = tcx.const_eval(param_env.and(gid)).ok()?; - evaluated.val.try_to_bits(size) + tcx.const_eval(param_env.and(gid)).unwrap_or(self) }, - // otherwise just extract a `ConstValue`'s bits if possible - _ => self.val.try_to_bits(size), + _ => self, } } diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index ea829da783e9b..4081c02a33ca4 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -5,6 +5,7 @@ use crate::infer::canonical::Canonical; use crate::ty::{self, Lift, List, Ty, TyCtxt, InferConst, ParamConst}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::mir::interpret::ConstValue; +use crate::ty::sty::{ClosureSubsts, GeneratorSubsts}; use rustc_serialize::{self, Encodable, Encoder, Decodable, Decoder}; use syntax_pos::{Span, DUMMY_SP}; @@ -20,11 +21,11 @@ use std::num::NonZeroUsize; /// An entity in the Rust type system, which can be one of /// several kinds (types, lifetimes, and consts). -/// To reduce memory usage, a `Kind` is a interned pointer, +/// To reduce memory usage, a `GenericArg` is a interned pointer, /// with the lowest 2 bits being reserved for a tag to /// indicate the type (`Ty`, `Region`, or `Const`) it points to. #[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct Kind<'tcx> { +pub struct GenericArg<'tcx> { ptr: NonZeroUsize, marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, &'tcx ty::Const<'tcx>)> } @@ -35,33 +36,33 @@ const REGION_TAG: usize = 0b01; const CONST_TAG: usize = 0b10; #[derive(Debug, RustcEncodable, RustcDecodable, PartialEq, Eq, PartialOrd, Ord, HashStable)] -pub enum UnpackedKind<'tcx> { +pub enum GenericArgKind<'tcx> { Lifetime(ty::Region<'tcx>), Type(Ty<'tcx>), Const(&'tcx ty::Const<'tcx>), } -impl<'tcx> UnpackedKind<'tcx> { - fn pack(self) -> Kind<'tcx> { +impl<'tcx> GenericArgKind<'tcx> { + fn pack(self) -> GenericArg<'tcx> { let (tag, ptr) = match self { - UnpackedKind::Lifetime(lt) => { + GenericArgKind::Lifetime(lt) => { // Ensure we can use the tag bits. assert_eq!(mem::align_of_val(lt) & TAG_MASK, 0); (REGION_TAG, lt as *const _ as usize) } - UnpackedKind::Type(ty) => { + GenericArgKind::Type(ty) => { // Ensure we can use the tag bits. assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0); (TYPE_TAG, ty as *const _ as usize) } - UnpackedKind::Const(ct) => { + GenericArgKind::Const(ct) => { // Ensure we can use the tag bits. assert_eq!(mem::align_of_val(ct) & TAG_MASK, 0); (CONST_TAG, ct as *const _ as usize) } }; - Kind { + GenericArg { ptr: unsafe { NonZeroUsize::new_unchecked(ptr | tag) }, @@ -70,119 +71,137 @@ impl<'tcx> UnpackedKind<'tcx> { } } -impl fmt::Debug for Kind<'tcx> { +impl fmt::Debug for GenericArg<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.unpack() { - UnpackedKind::Lifetime(lt) => lt.fmt(f), - UnpackedKind::Type(ty) => ty.fmt(f), - UnpackedKind::Const(ct) => ct.fmt(f), + GenericArgKind::Lifetime(lt) => lt.fmt(f), + GenericArgKind::Type(ty) => ty.fmt(f), + GenericArgKind::Const(ct) => ct.fmt(f), } } } -impl<'tcx> Ord for Kind<'tcx> { - fn cmp(&self, other: &Kind<'_>) -> Ordering { +impl<'tcx> Ord for GenericArg<'tcx> { + fn cmp(&self, other: &GenericArg<'_>) -> Ordering { self.unpack().cmp(&other.unpack()) } } -impl<'tcx> PartialOrd for Kind<'tcx> { - fn partial_cmp(&self, other: &Kind<'_>) -> Option { +impl<'tcx> PartialOrd for GenericArg<'tcx> { + fn partial_cmp(&self, other: &GenericArg<'_>) -> Option { Some(self.cmp(&other)) } } -impl<'tcx> From> for Kind<'tcx> { - fn from(r: ty::Region<'tcx>) -> Kind<'tcx> { - UnpackedKind::Lifetime(r).pack() +impl<'tcx> From> for GenericArg<'tcx> { + fn from(r: ty::Region<'tcx>) -> GenericArg<'tcx> { + GenericArgKind::Lifetime(r).pack() } } -impl<'tcx> From> for Kind<'tcx> { - fn from(ty: Ty<'tcx>) -> Kind<'tcx> { - UnpackedKind::Type(ty).pack() +impl<'tcx> From> for GenericArg<'tcx> { + fn from(ty: Ty<'tcx>) -> GenericArg<'tcx> { + GenericArgKind::Type(ty).pack() } } -impl<'tcx> From<&'tcx ty::Const<'tcx>> for Kind<'tcx> { - fn from(c: &'tcx ty::Const<'tcx>) -> Kind<'tcx> { - UnpackedKind::Const(c).pack() +impl<'tcx> From<&'tcx ty::Const<'tcx>> for GenericArg<'tcx> { + fn from(c: &'tcx ty::Const<'tcx>) -> GenericArg<'tcx> { + GenericArgKind::Const(c).pack() } } -impl<'tcx> Kind<'tcx> { +impl<'tcx> GenericArg<'tcx> { #[inline] - pub fn unpack(self) -> UnpackedKind<'tcx> { + pub fn unpack(self) -> GenericArgKind<'tcx> { let ptr = self.ptr.get(); unsafe { match ptr & TAG_MASK { - REGION_TAG => UnpackedKind::Lifetime(&*((ptr & !TAG_MASK) as *const _)), - TYPE_TAG => UnpackedKind::Type(&*((ptr & !TAG_MASK) as *const _)), - CONST_TAG => UnpackedKind::Const(&*((ptr & !TAG_MASK) as *const _)), + REGION_TAG => GenericArgKind::Lifetime(&*((ptr & !TAG_MASK) as *const _)), + TYPE_TAG => GenericArgKind::Type(&*((ptr & !TAG_MASK) as *const _)), + CONST_TAG => GenericArgKind::Const(&*((ptr & !TAG_MASK) as *const _)), _ => intrinsics::unreachable() } } } - /// Unpack the `Kind` as a type when it is known certainly to be a type. + /// Unpack the `GenericArg` as a type when it is known certainly to be a type. /// This is true in cases where `Substs` is used in places where the kinds are known /// to be limited (e.g. in tuples, where the only parameters are type parameters). pub fn expect_ty(self) -> Ty<'tcx> { match self.unpack() { - UnpackedKind::Type(ty) => ty, + GenericArgKind::Type(ty) => ty, _ => bug!("expected a type, but found another kind"), } } } -impl<'a, 'tcx> Lift<'tcx> for Kind<'a> { - type Lifted = Kind<'tcx>; +impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> { + type Lifted = GenericArg<'tcx>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { match self.unpack() { - UnpackedKind::Lifetime(lt) => tcx.lift(<).map(|lt| lt.into()), - UnpackedKind::Type(ty) => tcx.lift(&ty).map(|ty| ty.into()), - UnpackedKind::Const(ct) => tcx.lift(&ct).map(|ct| ct.into()), + GenericArgKind::Lifetime(lt) => tcx.lift(<).map(|lt| lt.into()), + GenericArgKind::Type(ty) => tcx.lift(&ty).map(|ty| ty.into()), + GenericArgKind::Const(ct) => tcx.lift(&ct).map(|ct| ct.into()), } } } -impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { match self.unpack() { - UnpackedKind::Lifetime(lt) => lt.fold_with(folder).into(), - UnpackedKind::Type(ty) => ty.fold_with(folder).into(), - UnpackedKind::Const(ct) => ct.fold_with(folder).into(), + GenericArgKind::Lifetime(lt) => lt.fold_with(folder).into(), + GenericArgKind::Type(ty) => ty.fold_with(folder).into(), + GenericArgKind::Const(ct) => ct.fold_with(folder).into(), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { match self.unpack() { - UnpackedKind::Lifetime(lt) => lt.visit_with(visitor), - UnpackedKind::Type(ty) => ty.visit_with(visitor), - UnpackedKind::Const(ct) => ct.visit_with(visitor), + GenericArgKind::Lifetime(lt) => lt.visit_with(visitor), + GenericArgKind::Type(ty) => ty.visit_with(visitor), + GenericArgKind::Const(ct) => ct.visit_with(visitor), } } } -impl<'tcx> Encodable for Kind<'tcx> { +impl<'tcx> Encodable for GenericArg<'tcx> { fn encode(&self, e: &mut E) -> Result<(), E::Error> { self.unpack().encode(e) } } -impl<'tcx> Decodable for Kind<'tcx> { - fn decode(d: &mut D) -> Result, D::Error> { - Ok(UnpackedKind::decode(d)?.pack()) +impl<'tcx> Decodable for GenericArg<'tcx> { + fn decode(d: &mut D) -> Result, D::Error> { + Ok(GenericArgKind::decode(d)?.pack()) } } /// A substitution mapping generic parameters to new values. -pub type InternalSubsts<'tcx> = List>; +pub type InternalSubsts<'tcx> = List>; pub type SubstsRef<'tcx> = &'tcx InternalSubsts<'tcx>; impl<'a, 'tcx> InternalSubsts<'tcx> { + /// Interpret these substitutions as the substitutions of a closure type. + /// Closure substitutions have a particular structure controlled by the + /// compiler that encodes information like the signature and closure kind; + /// see `ty::ClosureSubsts` struct for more comments. + pub fn as_closure(&'a self) -> ClosureSubsts<'a> { + ClosureSubsts { + substs: self, + } + } + + /// Interpret these substitutions as the substitutions of a generator type. + /// Closure substitutions have a particular structure controlled by the + /// compiler that encodes information like the signature and generator kind; + /// see `ty::GeneratorSubsts` struct for more comments. + pub fn as_generator(&'tcx self) -> GeneratorSubsts<'tcx> { + GeneratorSubsts { substs: self } + } + /// Creates a `InternalSubsts` that maps each generic parameter to itself. pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { Self::for_item(tcx, def_id, |param, _| { @@ -232,7 +251,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { /// substitute defaults of generic parameters. pub fn for_item(tcx: TyCtxt<'tcx>, def_id: DefId, mut mk_kind: F) -> SubstsRef<'tcx> where - F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx>, + F: FnMut(&ty::GenericParamDef, &[GenericArg<'tcx>]) -> GenericArg<'tcx>, { let defs = tcx.generics_of(def_id); let count = defs.count(); @@ -243,7 +262,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { pub fn extend_to(&self, tcx: TyCtxt<'tcx>, def_id: DefId, mut mk_kind: F) -> SubstsRef<'tcx> where - F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx>, + F: FnMut(&ty::GenericParamDef, &[GenericArg<'tcx>]) -> GenericArg<'tcx>, { Self::for_item(tcx, def_id, |param, substs| { self.get(param.index as usize) @@ -253,12 +272,12 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { } fn fill_item( - substs: &mut SmallVec<[Kind<'tcx>; 8]>, + substs: &mut SmallVec<[GenericArg<'tcx>; 8]>, tcx: TyCtxt<'tcx>, defs: &ty::Generics, mk_kind: &mut F, ) where - F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx>, + F: FnMut(&ty::GenericParamDef, &[GenericArg<'tcx>]) -> GenericArg<'tcx>, { if let Some(def_id) = defs.parent { let parent_defs = tcx.generics_of(def_id); @@ -267,10 +286,10 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { Self::fill_single(substs, defs, mk_kind) } - fn fill_single(substs: &mut SmallVec<[Kind<'tcx>; 8]>, + fn fill_single(substs: &mut SmallVec<[GenericArg<'tcx>; 8]>, defs: &ty::Generics, mk_kind: &mut F) - where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx> + where F: FnMut(&ty::GenericParamDef, &[GenericArg<'tcx>]) -> GenericArg<'tcx> { substs.reserve(defs.params.len()); for param in &defs.params { @@ -287,7 +306,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { #[inline] pub fn types(&'a self) -> impl DoubleEndedIterator> + 'a { self.iter().filter_map(|k| { - if let UnpackedKind::Type(ty) = k.unpack() { + if let GenericArgKind::Type(ty) = k.unpack() { Some(ty) } else { None @@ -298,7 +317,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { #[inline] pub fn regions(&'a self) -> impl DoubleEndedIterator> + 'a { self.iter().filter_map(|k| { - if let UnpackedKind::Lifetime(lt) = k.unpack() { + if let GenericArgKind::Lifetime(lt) = k.unpack() { Some(lt) } else { None @@ -309,7 +328,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { #[inline] pub fn consts(&'a self) -> impl DoubleEndedIterator> + 'a { self.iter().filter_map(|k| { - if let UnpackedKind::Const(ct) = k.unpack() { + if let GenericArgKind::Const(ct) = k.unpack() { Some(ct) } else { None @@ -320,10 +339,10 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { #[inline] pub fn non_erasable_generics( &'a self - ) -> impl DoubleEndedIterator> + 'a { + ) -> impl DoubleEndedIterator> + 'a { self.iter().filter_map(|k| { match k.unpack() { - UnpackedKind::Lifetime(_) => None, + GenericArgKind::Lifetime(_) => None, generic => Some(generic), } }) @@ -331,7 +350,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { #[inline] pub fn type_at(&self, i: usize) -> Ty<'tcx> { - if let UnpackedKind::Type(ty) = self[i].unpack() { + if let GenericArgKind::Type(ty) = self[i].unpack() { ty } else { bug!("expected type for param #{} in {:?}", i, self); @@ -340,7 +359,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { #[inline] pub fn region_at(&self, i: usize) -> ty::Region<'tcx> { - if let UnpackedKind::Lifetime(lt) = self[i].unpack() { + if let GenericArgKind::Lifetime(lt) = self[i].unpack() { lt } else { bug!("expected region for param #{} in {:?}", i, self); @@ -349,7 +368,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { #[inline] pub fn const_at(&self, i: usize) -> &'tcx ty::Const<'tcx> { - if let UnpackedKind::Const(ct) = self[i].unpack() { + if let GenericArgKind::Const(ct) = self[i].unpack() { ct } else { bug!("expected const for param #{} in {:?}", i, self); @@ -357,7 +376,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { } #[inline] - pub fn type_for_def(&self, def: &ty::GenericParamDef) -> Kind<'tcx> { + pub fn type_for_def(&self, def: &ty::GenericParamDef) -> GenericArg<'tcx> { self.type_at(def.index as usize).into() } @@ -383,14 +402,41 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { - let params: SmallVec<[_; 8]> = self.iter().map(|k| k.fold_with(folder)).collect(); - - // If folding doesn't change the substs, it's faster to avoid - // calling `mk_substs` and instead reuse the existing substs. - if params[..] == self[..] { - self - } else { - folder.tcx().intern_substs(¶ms) + // This code is hot enough that it's worth specializing for the most + // common length lists, to avoid the overhead of `SmallVec` creation. + // The match arms are in order of frequency. The 1, 2, and 0 cases are + // typically hit in 90--99.99% of cases. When folding doesn't change + // the substs, it's faster to reuse the existing substs rather than + // calling `intern_substs`. + match self.len() { + 1 => { + let param0 = self[0].fold_with(folder); + if param0 == self[0] { + self + } else { + folder.tcx().intern_substs(&[param0]) + } + } + 2 => { + let param0 = self[0].fold_with(folder); + let param1 = self[1].fold_with(folder); + if param0 == self[0] && param1 == self[1] { + self + } else { + folder.tcx().intern_substs(&[param0, param1]) + } + } + 0 => { + self + } + _ => { + let params: SmallVec<[_; 8]> = self.iter().map(|k| k.fold_with(folder)).collect(); + if params[..] == self[..] { + self + } else { + folder.tcx().intern_substs(¶ms) + } + } } } @@ -409,15 +455,25 @@ impl<'tcx> rustc_serialize::UseSpecializedDecodable for SubstsRef<'tcx> {} // there is more information available (for better errors). pub trait Subst<'tcx>: Sized { - fn subst(&self, tcx: TyCtxt<'tcx>, substs: &[Kind<'tcx>]) -> Self { + fn subst(&self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self { self.subst_spanned(tcx, substs, None) } - fn subst_spanned(&self, tcx: TyCtxt<'tcx>, substs: &[Kind<'tcx>], span: Option) -> Self; + fn subst_spanned( + &self, + tcx: TyCtxt<'tcx>, + substs: &[GenericArg<'tcx>], + span: Option, + ) -> Self; } impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for T { - fn subst_spanned(&self, tcx: TyCtxt<'tcx>, substs: &[Kind<'tcx>], span: Option) -> T { + fn subst_spanned( + &self, + tcx: TyCtxt<'tcx>, + substs: &[GenericArg<'tcx>], + span: Option, + ) -> T { let mut folder = SubstFolder { tcx, substs, span, @@ -433,7 +489,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for T { struct SubstFolder<'a, 'tcx> { tcx: TyCtxt<'tcx>, - substs: &'a [Kind<'tcx>], + substs: &'a [GenericArg<'tcx>], /// The location for which the substitution is performed, if available. span: Option, @@ -468,7 +524,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { ty::ReEarlyBound(data) => { let rk = self.substs.get(data.index as usize).map(|k| k.unpack()); match rk { - Some(UnpackedKind::Lifetime(lt)) => { + Some(GenericArgKind::Lifetime(lt)) => { self.shift_region_through_binders(lt) } _ => { @@ -501,7 +557,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { } self.ty_stack_depth += 1; - let t1 = match t.sty { + let t1 = match t.kind { ty::Param(p) => { self.ty_for_param(p, t) } @@ -537,7 +593,7 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { // Look up the type in the substitutions. It really should be in there. let opt_ty = self.substs.get(p.index as usize).map(|k| k.unpack()); let ty = match opt_ty { - Some(UnpackedKind::Type(ty)) => ty, + Some(GenericArgKind::Type(ty)) => ty, Some(kind) => { let span = self.span.unwrap_or(DUMMY_SP); span_bug!( @@ -578,7 +634,7 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { // Look up the const in the substitutions. It really should be in there. let opt_ct = self.substs.get(p.index as usize).map(|k| k.unpack()); let ct = match opt_ct { - Some(UnpackedKind::Const(ct)) => ct, + Some(GenericArgKind::Const(ct)) => ct, Some(kind) => { let span = self.span.unwrap_or(DUMMY_SP); span_bug!( diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 2bb9c258f8b67..49ec908231548 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -8,8 +8,7 @@ use crate::ty::fold::TypeFoldable; use crate::ty::{Ty, TyCtxt}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, - StableHasherResult}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::HashStable; /// A trait's definition with type information. @@ -194,9 +193,7 @@ pub(super) fn trait_impls_of_provider( } impl<'a> HashStable> for TraitImpls { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let TraitImpls { ref blanket_impls, ref non_blanket_impls, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index c3ecc04b12e01..5ddf15317a31c 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -8,7 +8,7 @@ use crate::mir::interpret::{sign_extend, truncate}; use crate::ich::NodeIdHashingMode; use crate::traits::{self, ObligationCause}; use crate::ty::{self, DefIdTree, Ty, TyCtxt, GenericParamDefKind, TypeFoldable}; -use crate::ty::subst::{Subst, InternalSubsts, SubstsRef, UnpackedKind}; +use crate::ty::subst::{Subst, InternalSubsts, SubstsRef, GenericArgKind}; use crate::ty::query::TyCtxtAt; use crate::ty::TyKind::*; use crate::ty::layout::{Integer, IntegerExt}; @@ -33,7 +33,7 @@ pub struct Discr<'tcx> { impl<'tcx> fmt::Display for Discr<'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.ty.sty { + match self.ty.kind { ty::Int(ity) => { let size = ty::tls::with(|tcx| { Integer::from_attr(&tcx, SignedInt(ity)).size() @@ -54,7 +54,7 @@ impl<'tcx> Discr<'tcx> { self.checked_add(tcx, 1).0 } pub fn checked_add(self, tcx: TyCtxt<'tcx>, n: u128) -> (Self, bool) { - let (int, signed) = match self.ty.sty { + let (int, signed) = match self.ty.kind { Int(ity) => (Integer::from_attr(&tcx, SignedInt(ity)), true), Uint(uty) => (Integer::from_attr(&tcx, UnsignedInt(uty)), false), _ => bug!("non integer discriminant"), @@ -179,7 +179,7 @@ impl<'tcx> ty::ParamEnv<'tcx> { ) -> Result<(), CopyImplementationError<'tcx>> { // FIXME: (@jroesch) float this code up tcx.infer_ctxt().enter(|infcx| { - let (adt, substs) = match self_type.sty { + let (adt, substs) = match self_type.kind { // These types used to have a builtin impl. // Now libcore provides that impl. ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Float(_) | @@ -246,10 +246,10 @@ impl<'tcx> TyCtxt<'tcx> { impl<'tcx> TyCtxt<'tcx> { pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { - if let ty::Adt(def, substs) = ty.sty { + if let ty::Adt(def, substs) = ty.kind { for field in def.all_fields() { let field_ty = field.ty(self, substs); - if let Error = field_ty.sty { + if let Error = field_ty.kind { return true; } } @@ -298,7 +298,7 @@ impl<'tcx> TyCtxt<'tcx> { -> Ty<'tcx> { loop { - match ty.sty { + match ty.kind { ty::Adt(def, substs) => { if !def.is_struct() { break; @@ -370,7 +370,7 @@ impl<'tcx> TyCtxt<'tcx> { { let (mut a, mut b) = (source, target); loop { - match (&a.sty, &b.sty) { + match (&a.kind, &b.kind) { (&Adt(a_def, a_substs), &Adt(b_def, b_substs)) if a_def == b_def && a_def.is_struct() => { if let Some(f) = a_def.non_enum_variant().fields.last() { @@ -510,7 +510,7 @@ impl<'tcx> TyCtxt<'tcx> { /// destructor of `def` itself. For the destructors of the /// contents, you need `adt_dtorck_constraint`. pub fn destructor_constraints(self, def: &'tcx ty::AdtDef) - -> Vec> + -> Vec> { let dtor = match def.destructor(self) { None => { @@ -544,12 +544,12 @@ impl<'tcx> TyCtxt<'tcx> { // , and then look up which of the impl substs refer to // parameters marked as pure. - let impl_substs = match self.type_of(impl_def_id).sty { + let impl_substs = match self.type_of(impl_def_id).kind { ty::Adt(def_, substs) if def_ == def => substs, _ => bug!() }; - let item_substs = match self.type_of(def.did).sty { + let item_substs = match self.type_of(def.did).kind { ty::Adt(def_, substs) if def_ == def => substs, _ => bug!() }; @@ -557,23 +557,23 @@ impl<'tcx> TyCtxt<'tcx> { let result = item_substs.iter().zip(impl_substs.iter()) .filter(|&(_, &k)| { match k.unpack() { - UnpackedKind::Lifetime(&ty::RegionKind::ReEarlyBound(ref ebr)) => { + GenericArgKind::Lifetime(&ty::RegionKind::ReEarlyBound(ref ebr)) => { !impl_generics.region_param(ebr, self).pure_wrt_drop } - UnpackedKind::Type(&ty::TyS { - sty: ty::Param(ref pt), .. + GenericArgKind::Type(&ty::TyS { + kind: ty::Param(ref pt), .. }) => { !impl_generics.type_param(pt, self).pure_wrt_drop } - UnpackedKind::Const(&ty::Const { + GenericArgKind::Const(&ty::Const { val: ConstValue::Param(ref pc), .. }) => { !impl_generics.const_param(pc, self).pure_wrt_drop } - UnpackedKind::Lifetime(_) | - UnpackedKind::Type(_) | - UnpackedKind::Const(_) => { + GenericArgKind::Lifetime(_) | + GenericArgKind::Type(_) | + GenericArgKind::Const(_) => { // Not a type, const or region param: this should be reported // as an error. false @@ -642,12 +642,12 @@ impl<'tcx> TyCtxt<'tcx> { /// wrapped in a binder. pub fn closure_env_ty(self, closure_def_id: DefId, - closure_substs: ty::ClosureSubsts<'tcx>) + closure_substs: SubstsRef<'tcx>) -> Option>> { let closure_ty = self.mk_closure(closure_def_id, closure_substs); let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); - let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self); + let closure_kind_ty = closure_substs.as_closure().kind_ty(closure_def_id, self); let closure_kind = closure_kind_ty.to_opt_closure_kind()?; let env_ty = match closure_kind { ty::ClosureKind::Fn => self.mk_imm_ref(self.mk_region(env_region), closure_ty), @@ -709,8 +709,10 @@ impl<'tcx> TyCtxt<'tcx> { substs: SubstsRef<'tcx>, ) -> Option> { if self.found_recursion { - None - } else if self.seen_opaque_tys.insert(def_id) { + return None; + } + let substs = substs.fold_with(self); + if self.seen_opaque_tys.insert(def_id) { let generic_ty = self.tcx.type_of(def_id); let concrete_ty = generic_ty.subst(self.tcx, substs); let expanded_ty = self.fold_ty(concrete_ty); @@ -731,7 +733,7 @@ impl<'tcx> TyCtxt<'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Opaque(def_id, substs) = t.sty { + if let ty::Opaque(def_id, substs) = t.kind { self.expand_opaque_ty(def_id, substs).unwrap_or(t) } else { t.super_fold_with(self) @@ -809,7 +811,7 @@ impl<'tcx> ty::TyS<'tcx> { } pub fn same_type(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match (&a.sty, &b.sty) { + match (&a.kind, &b.kind) { (&Adt(did_a, substs_a), &Adt(did_b, substs_b)) => { if did_a != did_b { return false; @@ -844,16 +846,16 @@ impl<'tcx> ty::TyS<'tcx> { representable_cache: &mut FxHashMap, Representability>, ty: Ty<'tcx>, ) -> Representability { - match ty.sty { - Tuple(ref ts) => { + match ty.kind { + Tuple(..) => { // Find non representable - fold_repr(ts.iter().map(|ty| { + fold_repr(ty.tuple_fields().map(|ty| { is_type_structurally_recursive( tcx, sp, seen, representable_cache, - ty.expect_ty(), + ty, ) })) } @@ -887,7 +889,7 @@ impl<'tcx> ty::TyS<'tcx> { } fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: &'tcx ty::AdtDef) -> bool { - match ty.sty { + match ty.kind { Adt(ty_def, _) => { ty_def == def } @@ -925,7 +927,7 @@ impl<'tcx> ty::TyS<'tcx> { representable_cache: &mut FxHashMap, Representability>, ty: Ty<'tcx>, ) -> Representability { - match ty.sty { + match ty.kind { Adt(def, _) => { { // Iterate through stack of previously seen types. @@ -994,37 +996,46 @@ impl<'tcx> ty::TyS<'tcx> { debug!("is_type_representable: {:?} is {:?}", self, r); r } + + /// Peel off all reference types in this type until there are none left. + /// + /// This method is idempotent, i.e. `ty.peel_refs().peel_refs() == ty.peel_refs()`. + /// + /// # Examples + /// + /// - `u8` -> `u8` + /// - `&'a mut u8` -> `u8` + /// - `&'a &'b u8` -> `u8` + /// - `&'a *const &'b u8 -> *const &'b u8` + pub fn peel_refs(&'tcx self) -> Ty<'tcx> { + let mut ty = self; + while let Ref(_, inner_ty, _) = ty.kind { + ty = inner_ty; + } + ty + } } fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - let (param_env, ty) = query.into_parts(); - let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem); - tcx.infer_ctxt() - .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( - &infcx, - param_env, - ty, - trait_def_id, - DUMMY_SP, - )) + is_item_raw(tcx, query, lang_items::CopyTraitLangItem) } fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - let (param_env, ty) = query.into_parts(); - let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem); - tcx.infer_ctxt() - .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( - &infcx, - param_env, - ty, - trait_def_id, - DUMMY_SP, - )) + is_item_raw(tcx, query, lang_items::SizedTraitLangItem) + } fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + is_item_raw(tcx, query, lang_items::FreezeTraitLangItem) +} + +fn is_item_raw<'tcx>( + tcx: TyCtxt<'tcx>, + query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, + item: lang_items::LangItem, +) -> bool { let (param_env, ty) = query.into_parts(); - let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem); + let trait_def_id = tcx.require_lang_item(item, None); tcx.infer_ctxt() .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( &infcx, @@ -1047,7 +1058,7 @@ fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx> assert!(!ty.needs_infer()); - NeedsDrop(match ty.sty { + NeedsDrop(match ty.kind { // Fast-path for primitive types ty::Infer(ty::FreshIntTy(_)) | ty::Infer(ty::FreshFloatTy(_)) | ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Never | @@ -1088,14 +1099,16 @@ fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx> // Structural recursion. ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty), - ty::Closure(def_id, ref substs) => substs.upvar_tys(def_id, tcx).any(needs_drop), + ty::Closure(def_id, ref substs) => { + substs.as_closure().upvar_tys(def_id, tcx).any(needs_drop) + } // Pessimistically assume that all generators will require destructors // as we don't know if a destructor is a noop or not until after the MIR // state transformation pass ty::Generator(..) => true, - ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).any(needs_drop), + ty::Tuple(..) => ty.tuple_fields().any(needs_drop), // unions don't have destructors because of the child types, // only if they manually implement `Drop` (handled above). @@ -1150,7 +1163,7 @@ impl<'tcx> ExplicitSelf<'tcx> { { use self::ExplicitSelf::*; - match self_arg_ty.sty { + match self_arg_ty.kind { _ if is_self_ty(self_arg_ty) => ByValue, ty::Ref(region, ty, mutbl) if is_self_ty(ty) => { ByReference(region, mutbl) diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index c74511cf0fdda..f5b1902e3cc8c 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -69,7 +69,7 @@ pub fn walk_shallow(ty: Ty<'_>) -> smallvec::IntoIter> { // natural order one would expect (basically, the order of the // types as they are written). fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { - match parent_ty.sty { + match parent_ty.kind { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Infer(_) | ty::Param(_) | ty::Never | ty::Error | ty::Placeholder(..) | ty::Bound(..) | ty::Foreign(..) => { @@ -110,17 +110,15 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { ty::Adt(_, substs) | ty::Opaque(_, substs) => { stack.extend(substs.types().rev()); } - ty::Closure(_, ref substs) => { - stack.extend(substs.substs.types().rev()); - } - ty::Generator(_, ref substs, _) => { - stack.extend(substs.substs.types().rev()); + ty::Closure(_, ref substs) + | ty::Generator(_, ref substs, _) => { + stack.extend(substs.types().rev()); } ty::GeneratorWitness(ts) => { stack.extend(ts.skip_binder().iter().cloned().rev()); } - ty::Tuple(ts) => { - stack.extend(ts.iter().map(|k| k.expect_ty()).rev()); + ty::Tuple(..) => { + stack.extend(parent_ty.tuple_fields().rev()); } ty::FnDef(_, substs) => { stack.extend(substs.types().rev()); diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index d32c32af29e0d..ecb075e30b14d 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -221,7 +221,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { if !subty.has_escaping_bound_vars() { let cause = self.cause(cause); let trait_ref = ty::TraitRef { - def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem), + def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None), substs: self.infcx.tcx.mk_substs_trait(subty, &[]), }; self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate())); @@ -236,7 +236,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let mut subtys = ty0.walk(); let param_env = self.param_env; while let Some(ty) = subtys.next() { - match ty.sty { + match ty.kind { ty::Bool | ty::Char | ty::Int(..) | @@ -347,7 +347,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // anyway, except via auto trait matching (which // only inspects the upvar types). subtys.skip_current_subtree(); // subtree handled by compute_projection - for upvar_ty in substs.upvar_tys(def_id, self.infcx.tcx) { + for upvar_ty in substs.as_closure().upvar_tys(def_id, self.infcx.tcx) { self.compute(upvar_ty); } } @@ -407,7 +407,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // is satisfied to ensure termination.) ty::Infer(_) => { let ty = self.infcx.shallow_resolve(ty); - if let ty::Infer(_) = ty.sty { // not yet resolved... + if let ty::Infer(_) = ty.kind { // not yet resolved... if ty == ty0 { // ...this is the type we started from! no progress. return false; } diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 7118d05204c3b..3e52a6aa50850 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -1,21 +1,13 @@ #![allow(non_camel_case_types)] -use rustc_data_structures::{fx::FxHashMap, sync::Lock}; +use rustc_data_structures::sync::Lock; -use std::cell::{RefCell, Cell}; +use std::cell::Cell; use std::fmt::Debug; -use std::hash::Hash; -use std::panic; -use std::env; use std::time::{Duration, Instant}; -use std::sync::mpsc::{Sender}; -use syntax_pos::{SpanData}; use syntax::symbol::{Symbol, sym}; use rustc_macros::HashStable; -use crate::ty::TyCtxt; -use crate::dep_graph::{DepNode}; -use lazy_static; use crate::session::Session; #[cfg(test)] @@ -31,50 +23,6 @@ pub struct ErrorReported; thread_local!(static TIME_DEPTH: Cell = Cell::new(0)); -lazy_static! { - static ref DEFAULT_HOOK: Box) + Sync + Send + 'static> = { - let hook = panic::take_hook(); - panic::set_hook(Box::new(panic_hook)); - hook - }; -} - -fn panic_hook(info: &panic::PanicInfo<'_>) { - (*DEFAULT_HOOK)(info); - - let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false); - - if backtrace { - TyCtxt::try_print_query_stack(); - } - - #[cfg(windows)] - unsafe { - if env::var("RUSTC_BREAK_ON_ICE").is_ok() { - extern "system" { - fn DebugBreak(); - } - // Trigger a debugger if we crashed during bootstrap. - DebugBreak(); - } - } -} - -pub fn install_panic_hook() { - lazy_static::initialize(&DEFAULT_HOOK); -} - -/// Parameters to the `Dump` variant of type `ProfileQueriesMsg`. -#[derive(Clone,Debug)] -pub struct ProfQDumpParams { - /// A base path for the files we will dump. - pub path:String, - /// To ensure that the compiler waits for us to finish our dumps. - pub ack:Sender<()>, - /// Toggle dumping a log file with every `ProfileQueriesMsg`. - pub dump_profq_msg_log:bool, -} - #[allow(nonstandard_style)] #[derive(Clone, Debug, PartialEq, Eq)] pub struct QueryMsg { @@ -82,53 +30,6 @@ pub struct QueryMsg { pub msg: Option, } -/// A sequence of these messages induce a trace of query-based incremental compilation. -// FIXME(matthewhammer): Determine whether we should include cycle detection here or not. -#[derive(Clone,Debug)] -pub enum ProfileQueriesMsg { - /// Begin a timed pass. - TimeBegin(String), - /// End a timed pass. - TimeEnd, - /// Begin a task (see `dep_graph::graph::with_task`). - TaskBegin(DepNode), - /// End a task. - TaskEnd, - /// Begin a new query. - /// Cannot use `Span` because queries are sent to other thread. - QueryBegin(SpanData, QueryMsg), - /// Query is satisfied by using an already-known value for the given key. - CacheHit, - /// Query requires running a provider; providers may nest, permitting queries to nest. - ProviderBegin, - /// Query is satisfied by a provider terminating with a value. - ProviderEnd, - /// Dump a record of the queries to the given path. - Dump(ProfQDumpParams), - /// Halt the profiling/monitoring background thread. - Halt -} - -/// If enabled, send a message to the profile-queries thread. -pub fn profq_msg(sess: &Session, msg: ProfileQueriesMsg) { - if let Some(s) = sess.profile_channel.borrow().as_ref() { - s.send(msg).unwrap() - } else { - // Do nothing. - } -} - -/// Set channel for profile queries channel. -pub fn profq_set_chan(sess: &Session, s: Sender) -> bool { - let mut channel = sess.profile_channel.borrow_mut(); - if channel.is_none() { - *channel = Some(s); - true - } else { - false - } -} - /// Read the current depth of `time()` calls. This is used to /// encourage indentation across threads. pub fn time_depth() -> usize { @@ -145,10 +46,10 @@ pub fn set_time_depth(depth: usize) { pub fn time(sess: &Session, what: &str, f: F) -> T where F: FnOnce() -> T, { - time_ext(sess.time_passes(), Some(sess), what, f) + time_ext(sess.time_passes(), what, f) } -pub fn time_ext(do_it: bool, sess: Option<&Session>, what: &str, f: F) -> T where +pub fn time_ext(do_it: bool, what: &str, f: F) -> T where F: FnOnce() -> T, { if !do_it { return f(); } @@ -159,19 +60,9 @@ pub fn time_ext(do_it: bool, sess: Option<&Session>, what: &str, f: F) -> r }); - if let Some(sess) = sess { - if cfg!(debug_assertions) { - profq_msg(sess, ProfileQueriesMsg::TimeBegin(what.to_string())) - } - } let start = Instant::now(); let rv = f(); let dur = start.elapsed(); - if let Some(sess) = sess { - if cfg!(debug_assertions) { - profq_msg(sess, ProfileQueriesMsg::TimeEnd) - } - } print_time_passes_entry(true, what, dur); @@ -316,39 +207,3 @@ pub fn indenter() -> Indenter { debug!(">>"); Indenter { _cannot_construct_outside_of_this_module: () } } - -pub trait MemoizationMap { - type Key: Clone; - type Value: Clone; - - /// If `key` is present in the map, return the value, - /// otherwise invoke `op` and store the value in the map. - /// - /// N.B., if the receiver is a `DepTrackingMap`, special care is - /// needed in the `op` to ensure that the correct edges are - /// added into the dep graph. See the `DepTrackingMap` impl for - /// more details! - fn memoize(&self, key: Self::Key, op: OP) -> Self::Value - where OP: FnOnce() -> Self::Value; -} - -impl MemoizationMap for RefCell> - where K: Hash+Eq+Clone, V: Clone -{ - type Key = K; - type Value = V; - - fn memoize(&self, key: K, op: OP) -> V - where OP: FnOnce() -> V - { - let result = self.borrow().get(&key).cloned(); - match result { - Some(result) => result, - None => { - let result = op(); - self.borrow_mut().insert(key, result.clone()); - result - } - } - } -} diff --git a/src/librustc/util/profiling.rs b/src/librustc/util/profiling.rs index 8624856a4f55c..bd02e7f5a14a1 100644 --- a/src/librustc/util/profiling.rs +++ b/src/librustc/util/profiling.rs @@ -1,9 +1,9 @@ -use std::borrow::Cow; use std::error::Error; use std::fs; use std::mem::{self, Discriminant}; use std::path::Path; use std::process; +use std::sync::Arc; use std::thread::ThreadId; use std::u32; @@ -62,6 +62,206 @@ fn thread_id_to_u64(tid: ThreadId) -> u64 { unsafe { mem::transmute::(tid) } } + +/// A reference to the SelfProfiler. It can be cloned and sent across thread +/// boundaries at will. +#[derive(Clone)] +pub struct SelfProfilerRef { + // This field is `None` if self-profiling is disabled for the current + // compilation session. + profiler: Option>, + + // We store the filter mask directly in the reference because that doesn't + // cost anything and allows for filtering with checking if the profiler is + // actually enabled. + event_filter_mask: EventFilter, +} + +impl SelfProfilerRef { + + pub fn new(profiler: Option>) -> SelfProfilerRef { + // If there is no SelfProfiler then the filter mask is set to NONE, + // ensuring that nothing ever tries to actually access it. + let event_filter_mask = profiler + .as_ref() + .map(|p| p.event_filter_mask) + .unwrap_or(EventFilter::NONE); + + SelfProfilerRef { + profiler, + event_filter_mask, + } + } + + // This shim makes sure that calls only get executed if the filter mask + // lets them pass. It also contains some trickery to make sure that + // code is optimized for non-profiling compilation sessions, i.e. anything + // past the filter check is never inlined so it doesn't clutter the fast + // path. + #[inline(always)] + fn exec(&self, event_filter: EventFilter, f: F) -> TimingGuard<'_> + where F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a> + { + #[inline(never)] + fn cold_call(profiler_ref: &SelfProfilerRef, f: F) -> TimingGuard<'_> + where F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a> + { + let profiler = profiler_ref.profiler.as_ref().unwrap(); + f(&**profiler) + } + + if unlikely!(self.event_filter_mask.contains(event_filter)) { + cold_call(self, f) + } else { + TimingGuard::none() + } + } + + /// Start profiling a generic activity. Profiling continues until the + /// TimingGuard returned from this call is dropped. + #[inline(always)] + pub fn generic_activity(&self, event_id: &str) -> TimingGuard<'_> { + self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| { + let event_id = profiler.profiler.alloc_string(event_id); + TimingGuard::start( + profiler, + profiler.generic_activity_event_kind, + event_id + ) + }) + } + + /// Start profiling a generic activity. Profiling continues until + /// `generic_activity_end` is called. The RAII-based `generic_activity` + /// usually is the better alternative. + #[inline(always)] + pub fn generic_activity_start(&self, event_id: &str) { + self.non_guard_generic_event( + |profiler| profiler.generic_activity_event_kind, + |profiler| profiler.profiler.alloc_string(event_id), + EventFilter::GENERIC_ACTIVITIES, + TimestampKind::Start, + ); + } + + /// End profiling a generic activity that was started with + /// `generic_activity_start`. The RAII-based `generic_activity` usually is + /// the better alternative. + #[inline(always)] + pub fn generic_activity_end(&self, event_id: &str) { + self.non_guard_generic_event( + |profiler| profiler.generic_activity_event_kind, + |profiler| profiler.profiler.alloc_string(event_id), + EventFilter::GENERIC_ACTIVITIES, + TimestampKind::End, + ); + } + + /// Start profiling a query provider. Profiling continues until the + /// TimingGuard returned from this call is dropped. + #[inline(always)] + pub fn query_provider(&self, query_name: QueryName) -> TimingGuard<'_> { + self.exec(EventFilter::QUERY_PROVIDERS, |profiler| { + let event_id = SelfProfiler::get_query_name_string_id(query_name); + TimingGuard::start(profiler, profiler.query_event_kind, event_id) + }) + } + + /// Record a query in-memory cache hit. + #[inline(always)] + pub fn query_cache_hit(&self, query_name: QueryName) { + self.non_guard_query_event( + |profiler| profiler.query_cache_hit_event_kind, + query_name, + EventFilter::QUERY_CACHE_HITS, + TimestampKind::Instant, + ); + } + + /// Start profiling a query being blocked on a concurrent execution. + /// Profiling continues until `query_blocked_end` is called. + #[inline(always)] + pub fn query_blocked_start(&self, query_name: QueryName) { + self.non_guard_query_event( + |profiler| profiler.query_blocked_event_kind, + query_name, + EventFilter::QUERY_BLOCKED, + TimestampKind::Start, + ); + } + + /// End profiling a query being blocked on a concurrent execution. + #[inline(always)] + pub fn query_blocked_end(&self, query_name: QueryName) { + self.non_guard_query_event( + |profiler| profiler.query_blocked_event_kind, + query_name, + EventFilter::QUERY_BLOCKED, + TimestampKind::End, + ); + } + + /// Start profiling how long it takes to load a query result from the + /// incremental compilation on-disk cache. Profiling continues until the + /// TimingGuard returned from this call is dropped. + #[inline(always)] + pub fn incr_cache_loading(&self, query_name: QueryName) -> TimingGuard<'_> { + self.exec(EventFilter::INCR_CACHE_LOADS, |profiler| { + let event_id = SelfProfiler::get_query_name_string_id(query_name); + TimingGuard::start( + profiler, + profiler.incremental_load_result_event_kind, + event_id + ) + }) + } + + #[inline(always)] + fn non_guard_query_event( + &self, + event_kind: fn(&SelfProfiler) -> StringId, + query_name: QueryName, + event_filter: EventFilter, + timestamp_kind: TimestampKind + ) { + drop(self.exec(event_filter, |profiler| { + let event_id = SelfProfiler::get_query_name_string_id(query_name); + let thread_id = thread_id_to_u64(std::thread::current().id()); + + profiler.profiler.record_event( + event_kind(profiler), + event_id, + thread_id, + timestamp_kind, + ); + + TimingGuard::none() + })); + } + + #[inline(always)] + fn non_guard_generic_event StringId>( + &self, + event_kind: fn(&SelfProfiler) -> StringId, + event_id: F, + event_filter: EventFilter, + timestamp_kind: TimestampKind + ) { + drop(self.exec(event_filter, |profiler| { + let thread_id = thread_id_to_u64(std::thread::current().id()); + + profiler.profiler.record_event( + event_kind(profiler), + event_id(profiler), + thread_id, + timestamp_kind, + ); + + TimingGuard::none() + })); + } +} + pub struct SelfProfiler { profiler: Profiler, event_filter_mask: EventFilter, @@ -143,103 +343,51 @@ impl SelfProfiler { let id = SelfProfiler::get_query_name_string_id(query_name); self.profiler.alloc_string_with_reserved_id(id, query_name.as_str()); } +} - #[inline] - pub fn start_activity( - &self, - label: impl Into>, - ) { - if self.event_filter_mask.contains(EventFilter::GENERIC_ACTIVITIES) { - self.record(&label.into(), self.generic_activity_event_kind, TimestampKind::Start); - } - } - - #[inline] - pub fn end_activity( - &self, - label: impl Into>, - ) { - if self.event_filter_mask.contains(EventFilter::GENERIC_ACTIVITIES) { - self.record(&label.into(), self.generic_activity_event_kind, TimestampKind::End); - } - } - - #[inline] - pub fn record_query_hit(&self, query_name: QueryName) { - if self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS) { - self.record_query(query_name, self.query_cache_hit_event_kind, TimestampKind::Instant); - } - } - - #[inline] - pub fn start_query(&self, query_name: QueryName) { - if self.event_filter_mask.contains(EventFilter::QUERY_PROVIDERS) { - self.record_query(query_name, self.query_event_kind, TimestampKind::Start); - } - } - - #[inline] - pub fn end_query(&self, query_name: QueryName) { - if self.event_filter_mask.contains(EventFilter::QUERY_PROVIDERS) { - self.record_query(query_name, self.query_event_kind, TimestampKind::End); - } - } - - #[inline] - pub fn incremental_load_result_start(&self, query_name: QueryName) { - if self.event_filter_mask.contains(EventFilter::INCR_CACHE_LOADS) { - self.record_query( - query_name, - self.incremental_load_result_event_kind, - TimestampKind::Start - ); - } - } - - #[inline] - pub fn incremental_load_result_end(&self, query_name: QueryName) { - if self.event_filter_mask.contains(EventFilter::INCR_CACHE_LOADS) { - self.record_query( - query_name, - self.incremental_load_result_event_kind, - TimestampKind::End - ); - } - } +#[must_use] +pub struct TimingGuard<'a>(Option>); - #[inline] - pub fn query_blocked_start(&self, query_name: QueryName) { - if self.event_filter_mask.contains(EventFilter::QUERY_BLOCKED) { - self.record_query(query_name, self.query_blocked_event_kind, TimestampKind::Start); - } - } +struct TimingGuardInternal<'a> { + raw_profiler: &'a Profiler, + event_id: StringId, + event_kind: StringId, + thread_id: u64, +} +impl<'a> TimingGuard<'a> { #[inline] - pub fn query_blocked_end(&self, query_name: QueryName) { - if self.event_filter_mask.contains(EventFilter::QUERY_BLOCKED) { - self.record_query(query_name, self.query_blocked_event_kind, TimestampKind::End); - } + pub fn start( + profiler: &'a SelfProfiler, + event_kind: StringId, + event_id: StringId, + ) -> TimingGuard<'a> { + let thread_id = thread_id_to_u64(std::thread::current().id()); + let raw_profiler = &profiler.profiler; + raw_profiler.record_event(event_kind, event_id, thread_id, TimestampKind::Start); + + TimingGuard(Some(TimingGuardInternal { + raw_profiler, + event_kind, + event_id, + thread_id, + })) } #[inline] - fn record(&self, event_id: &str, event_kind: StringId, timestamp_kind: TimestampKind) { - let thread_id = thread_id_to_u64(std::thread::current().id()); - - let event_id = self.profiler.alloc_string(event_id); - self.profiler.record_event(event_kind, event_id, thread_id, timestamp_kind); + pub fn none() -> TimingGuard<'a> { + TimingGuard(None) } +} +impl<'a> Drop for TimingGuardInternal<'a> { #[inline] - fn record_query( - &self, - query_name: QueryName, - event_kind: StringId, - timestamp_kind: TimestampKind, - ) { - let dep_node_name = SelfProfiler::get_query_name_string_id(query_name); - - let thread_id = thread_id_to_u64(std::thread::current().id()); - - self.profiler.record_event(event_kind, dep_node_name, thread_id, timestamp_kind); + fn drop(&mut self) { + self.raw_profiler.record_event( + self.event_kind, + self.event_id, + self.thread_id, + TimestampKind::End + ); } } diff --git a/src/librustc_apfloat/ieee.rs b/src/librustc_apfloat/ieee.rs index 9f68d770b9e87..4abb86a5251a5 100644 --- a/src/librustc_apfloat/ieee.rs +++ b/src/librustc_apfloat/ieee.rs @@ -1,13 +1,13 @@ use crate::{Category, ExpInt, IEK_INF, IEK_NAN, IEK_ZERO}; use crate::{Float, FloatConvert, ParseError, Round, Status, StatusAnd}; +use core::cmp::{self, Ordering}; +use core::convert::TryFrom; +use core::fmt::{self, Write}; +use core::marker::PhantomData; +use core::mem; +use core::ops::Neg; use smallvec::{SmallVec, smallvec}; -use std::cmp::{self, Ordering}; -use std::convert::TryFrom; -use std::fmt::{self, Write}; -use std::marker::PhantomData; -use std::mem; -use std::ops::Neg; #[must_use] pub struct IeeeFloat { @@ -1199,8 +1199,8 @@ impl Float for IeeeFloat { } // Handle a leading minus sign. - let minus = s.starts_with("-"); - if minus || s.starts_with("+") { + let minus = s.starts_with('-'); + if minus || s.starts_with('+') { s = &s[1..]; if s.is_empty() { return Err(ParseError("String has no digits")); @@ -2287,8 +2287,8 @@ impl Loss { /// Implementation details of IeeeFloat significands, such as big integer arithmetic. /// As a rule of thumb, no functions in this module should dynamically allocate. mod sig { - use std::cmp::Ordering; - use std::mem; + use core::cmp::Ordering; + use core::mem; use super::{ExpInt, Limb, LIMB_BITS, limbs_for_bits, Loss}; pub(super) fn is_all_zeros(limbs: &[Limb]) -> bool { diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 9e6d5a6f62434..5efe4fda8ccf8 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -31,15 +31,19 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![no_std] #![forbid(unsafe_code)] #![feature(nll)] -use std::cmp::Ordering; -use std::fmt; -use std::ops::{Neg, Add, Sub, Mul, Div, Rem}; -use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; -use std::str::FromStr; +#[macro_use] +extern crate alloc; + +use core::cmp::Ordering; +use core::fmt; +use core::ops::{Neg, Add, Sub, Mul, Div, Rem}; +use core::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; +use core::str::FromStr; bitflags::bitflags! { /// IEEE-754R 7: Default exception handling. @@ -551,12 +555,13 @@ pub trait Float fn ilogb(self) -> ExpInt; /// Returns: self * 2exp for integral exponents. + /// Equivalent to C standard library function `ldexp`. fn scalbn_r(self, exp: ExpInt, round: Round) -> Self; fn scalbn(self, exp: ExpInt) -> Self { self.scalbn_r(exp, Round::NearestTiesToEven) } - /// Equivalent of C standard library function. + /// Equivalent to C standard library function with the same name. /// /// While the C standard says exp is an unspecified value for infinity and nan, /// this returns INT_MAX for infinities, and INT_MIN for NaNs (see `ilogb`). @@ -587,7 +592,7 @@ macro_rules! float_common_impls { } } - impl<$t> ::std::str::FromStr for $ty<$t> where Self: Float { + impl<$t> ::core::str::FromStr for $ty<$t> where Self: Float { type Err = ParseError; fn from_str(s: &str) -> Result { Self::from_str_r(s, Round::NearestTiesToEven).map(|x| x.value) @@ -596,66 +601,66 @@ macro_rules! float_common_impls { // Rounding ties to the nearest even, by default. - impl<$t> ::std::ops::Add for $ty<$t> where Self: Float { + impl<$t> ::core::ops::Add for $ty<$t> where Self: Float { type Output = StatusAnd; fn add(self, rhs: Self) -> StatusAnd { self.add_r(rhs, Round::NearestTiesToEven) } } - impl<$t> ::std::ops::Sub for $ty<$t> where Self: Float { + impl<$t> ::core::ops::Sub for $ty<$t> where Self: Float { type Output = StatusAnd; fn sub(self, rhs: Self) -> StatusAnd { self.sub_r(rhs, Round::NearestTiesToEven) } } - impl<$t> ::std::ops::Mul for $ty<$t> where Self: Float { + impl<$t> ::core::ops::Mul for $ty<$t> where Self: Float { type Output = StatusAnd; fn mul(self, rhs: Self) -> StatusAnd { self.mul_r(rhs, Round::NearestTiesToEven) } } - impl<$t> ::std::ops::Div for $ty<$t> where Self: Float { + impl<$t> ::core::ops::Div for $ty<$t> where Self: Float { type Output = StatusAnd; fn div(self, rhs: Self) -> StatusAnd { self.div_r(rhs, Round::NearestTiesToEven) } } - impl<$t> ::std::ops::Rem for $ty<$t> where Self: Float { + impl<$t> ::core::ops::Rem for $ty<$t> where Self: Float { type Output = StatusAnd; fn rem(self, rhs: Self) -> StatusAnd { self.c_fmod(rhs) } } - impl<$t> ::std::ops::AddAssign for $ty<$t> where Self: Float { + impl<$t> ::core::ops::AddAssign for $ty<$t> where Self: Float { fn add_assign(&mut self, rhs: Self) { *self = (*self + rhs).value; } } - impl<$t> ::std::ops::SubAssign for $ty<$t> where Self: Float { + impl<$t> ::core::ops::SubAssign for $ty<$t> where Self: Float { fn sub_assign(&mut self, rhs: Self) { *self = (*self - rhs).value; } } - impl<$t> ::std::ops::MulAssign for $ty<$t> where Self: Float { + impl<$t> ::core::ops::MulAssign for $ty<$t> where Self: Float { fn mul_assign(&mut self, rhs: Self) { *self = (*self * rhs).value; } } - impl<$t> ::std::ops::DivAssign for $ty<$t> where Self: Float { + impl<$t> ::core::ops::DivAssign for $ty<$t> where Self: Float { fn div_assign(&mut self, rhs: Self) { *self = (*self / rhs).value; } } - impl<$t> ::std::ops::RemAssign for $ty<$t> where Self: Float { + impl<$t> ::core::ops::RemAssign for $ty<$t> where Self: Float { fn rem_assign(&mut self, rhs: Self) { *self = (*self % rhs).value; } diff --git a/src/librustc_apfloat/ppc.rs b/src/librustc_apfloat/ppc.rs index ddccfd6ca623b..8e2e390568e48 100644 --- a/src/librustc_apfloat/ppc.rs +++ b/src/librustc_apfloat/ppc.rs @@ -1,9 +1,9 @@ use crate::{Category, ExpInt, Float, FloatConvert, Round, ParseError, Status, StatusAnd}; use crate::ieee; -use std::cmp::Ordering; -use std::fmt; -use std::ops::Neg; +use core::cmp::Ordering; +use core::fmt; +use core::ops::Neg; #[must_use] #[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] diff --git a/src/librustc_asan/build.rs b/src/librustc_asan/build.rs index a2b4b090efb4f..645707ccc0338 100644 --- a/src/librustc_asan/build.rs +++ b/src/librustc_asan/build.rs @@ -4,6 +4,10 @@ use build_helper::sanitizer_lib_boilerplate; use cmake::Config; fn main() { + println!("cargo:rerun-if-env-changed=RUSTC_BUILD_SANITIZERS"); + if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) { + return; + } if let Some(llvm_config) = env::var_os("LLVM_CONFIG") { build_helper::restore_library_path(); diff --git a/src/librustc_ast_borrowck/Cargo.toml b/src/librustc_ast_borrowck/Cargo.toml deleted file mode 100644 index 024b2640e1e8e..0000000000000 --- a/src/librustc_ast_borrowck/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_ast_borrowck" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_ast_borrowck" -path = "lib.rs" -test = false -doctest = false - -[dependencies] -log = "0.4" -syntax = { path = "../libsyntax" } -syntax_pos = { path = "../libsyntax_pos" } -# for "clarity", rename the graphviz crate to dot; graphviz within `borrowck` -# refers to the borrowck-specific graphviz adapter traits. -dot = { path = "../libgraphviz", package = "graphviz" } -rustc = { path = "../librustc" } -errors = { path = "../librustc_errors", package = "rustc_errors" } -rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc_ast_borrowck/borrowck/README.md b/src/librustc_ast_borrowck/borrowck/README.md deleted file mode 100644 index 3f2175921d48c..0000000000000 --- a/src/librustc_ast_borrowck/borrowck/README.md +++ /dev/null @@ -1,1167 +0,0 @@ -% The Borrow Checker - -> WARNING: This README is more or less obsolete, and will be removed -> soon! The new system is described in the [rustc guide]. - -[rustc guide]: https://rust-lang.github.io/rustc-guide/borrow_check.html - -This pass has the job of enforcing memory safety. This is a subtle -topic. This docs aim to explain both the practice and the theory -behind the borrow checker. They start with a high-level overview of -how it works, and then proceed to dive into the theoretical -background. Finally, they go into detail on some of the more subtle -aspects. - -# Table of contents - -These docs are long. Search for the section you are interested in. - -- Overview -- Formal model -- Borrowing and loans -- Moves and initialization -- Drop flags and structural fragments -- Future work - -# Overview - -The borrow checker checks one function at a time. It operates in two -passes. The first pass, called `gather_loans`, walks over the function -and identifies all of the places where borrows (e.g., `&` expressions -and `ref` bindings) and moves (copies or captures of a linear value) -occur. It also tracks initialization sites. For each borrow and move, -it checks various basic safety conditions at this time (for example, -that the lifetime of the borrow doesn't exceed the lifetime of the -value being borrowed, or that there is no move out of an `&T` -referent). - -It then uses the dataflow module to propagate which of those borrows -may be in scope at each point in the procedure. A loan is considered -to come into scope at the expression that caused it and to go out of -scope when the lifetime of the resulting reference expires. - -Once the in-scope loans are known for each point in the program, the -borrow checker walks the IR again in a second pass called -`check_loans`. This pass examines each statement and makes sure that -it is safe with respect to the in-scope loans. - -# Formal model - -Throughout the docs we'll consider a simple subset of Rust in which -you can only borrow from places, defined like so: - -```text -P = x | P.f | *P -``` - -Here `x` represents some variable, `P.f` is a field reference, -and `*P` is a pointer dereference. There is no auto-deref or other -niceties. This means that if you have a type like: - -```rust -struct S { f: i32 } -``` - -and a variable `a: Box`, then the rust expression `a.f` would correspond -to an `P` of `(*a).f`. - -Here is the formal grammar for the types we'll consider: - -```text -TY = i32 | bool | S<'LT...> | Box | & 'LT MQ TY -MQ = mut | imm -``` - -Most of these types should be pretty self explanatory. Here `S` is a -struct name and we assume structs are declared like so: - -```text -SD = struct S<'LT...> { (f: TY)... } -``` - -# Borrowing and loans - -## An intuitive explanation - -### Issuing loans - -Now, imagine we had a program like this: - -```rust -struct Foo { f: i32, g: i32 } -... -'a: { - let mut x: Box = ...; - let y = &mut (*x).f; - x = ...; -} -``` - -This is of course dangerous because mutating `x` will free the old -value and hence invalidate `y`. The borrow checker aims to prevent -this sort of thing. - -#### Loans and restrictions - -The way the borrow checker works is that it analyzes each borrow -expression (in our simple model, that's stuff like `&P`, though in -real life there are a few other cases to consider). For each borrow -expression, it computes a `Loan`, which is a data structure that -records (1) the value being borrowed, (2) the mutability and scope of -the borrow, and (3) a set of restrictions. In the code, `Loan` is a -struct defined in `middle::borrowck`. Formally, we define `LOAN` as -follows: - -```text -LOAN = (P, LT, MQ, RESTRICTION*) -RESTRICTION = (P, ACTION*) -ACTION = MUTATE | CLAIM | FREEZE -``` - -Here the `LOAN` tuple defines the place `P` being borrowed; the -lifetime `LT` of that borrow; the mutability `MQ` of the borrow; and a -list of restrictions. The restrictions indicate actions which, if -taken, could invalidate the loan and lead to type safety violations. - -Each `RESTRICTION` is a pair of a restrictive place `P` (which will -either be the path that was borrowed or some prefix of the path that -was borrowed) and a set of restricted actions. There are three kinds -of actions that may be restricted for the path `P`: - -- `MUTATE` means that `P` cannot be assigned to; -- `CLAIM` means that the `P` cannot be borrowed mutably; -- `FREEZE` means that the `P` cannot be borrowed immutably; - -Finally, it is never possible to move from a place that appears in a -restriction. This implies that the "empty restriction" `(P, [])`, -which contains an empty set of actions, still has a purpose---it -prevents moves from `P`. I chose not to make `MOVE` a fourth kind of -action because that would imply that sometimes moves are permitted -from restricted values, which is not the case. - -#### Example - -To give you a better feeling for what kind of restrictions derived -from a loan, let's look at the loan `L` that would be issued as a -result of the borrow `&mut (*x).f` in the example above: - -```text -L = ((*x).f, 'a, mut, RS) where - RS = [((*x).f, [MUTATE, CLAIM, FREEZE]), - (*x, [MUTATE, CLAIM, FREEZE]), - (x, [MUTATE, CLAIM, FREEZE])] -``` - -The loan states that the expression `(*x).f` has been loaned as -mutable for the lifetime `'a`. Because the loan is mutable, that means -that the value `(*x).f` may be mutated via the newly created reference -(and *only* via that pointer). This is reflected in the -restrictions `RS` that accompany the loan. - -The first restriction `((*x).f, [MUTATE, CLAIM, FREEZE])` states that -the lender may not mutate, freeze, nor alias `(*x).f`. Mutation is -illegal because `(*x).f` is only supposed to be mutated via the new -reference, not by mutating the original path `(*x).f`. Freezing is -illegal because the path now has an `&mut` alias; so even if we the -lender were to consider `(*x).f` to be immutable, it might be mutated -via this alias. They will be enforced for the lifetime `'a` of the -loan. After the loan expires, the restrictions no longer apply. - -The second restriction on `*x` is interesting because it does not -apply to the path that was lent (`(*x).f`) but rather to a prefix of -the borrowed path. This is due to the rules of inherited mutability: -if the user were to assign to (or freeze) `*x`, they would indirectly -overwrite (or freeze) `(*x).f`, and thus invalidate the reference -that was created. In general it holds that when a path is -lent, restrictions are issued for all the owning prefixes of that -path. In this case, the path `*x` owns the path `(*x).f` and, -because `x` has ownership, the path `x` owns the path `*x`. -Therefore, borrowing `(*x).f` yields restrictions on both -`*x` and `x`. - -### Checking for illegal assignments, moves, and reborrows - -Once we have computed the loans introduced by each borrow, the borrow -checker uses a data flow propagation to compute the full set of loans -in scope at each expression and then uses that set to decide whether -that expression is legal. Remember that the scope of loan is defined -by its lifetime LT. We sometimes say that a loan which is in-scope at -a particular point is an "outstanding loan", and the set of -restrictions included in those loans as the "outstanding -restrictions". - -The kinds of expressions which in-scope loans can render illegal are: -- *assignments* (`lv = v`): illegal if there is an in-scope restriction - against mutating `lv`; -- *moves*: illegal if there is any in-scope restriction on `lv` at all; -- *mutable borrows* (`&mut lv`): illegal there is an in-scope restriction - against claiming `lv`; -- *immutable borrows* (`&lv`): illegal there is an in-scope restriction - against freezing `lv`. - -## Formal rules - -Now that we hopefully have some kind of intuitive feeling for how the -borrow checker works, let's look a bit more closely now at the precise -conditions that it uses. - -I will present the rules in a modified form of standard inference -rules, which looks as follows: - -```text -PREDICATE(X, Y, Z) // Rule-Name - Condition 1 - Condition 2 - Condition 3 -``` - -The initial line states the predicate that is to be satisfied. The -indented lines indicate the conditions that must be met for the -predicate to be satisfied. The right-justified comment states the name -of this rule: there are comments in the borrowck source referencing -these names, so that you can cross reference to find the actual code -that corresponds to the formal rule. - -### Invariants - -I want to collect, at a high-level, the invariants the borrow checker -maintains. I will give them names and refer to them throughout the -text. Together these invariants are crucial for the overall soundness -of the system. - -**Mutability requires uniqueness.** To mutate a path - -**Unique mutability.** There is only one *usable* mutable path to any -given memory at any given time. This implies that when claiming memory -with an expression like `p = &mut x`, the compiler must guarantee that -the borrowed value `x` can no longer be mutated so long as `p` is -live. (This is done via restrictions, read on.) - -**.** - - -### The `gather_loans` pass - -We start with the `gather_loans` pass, which walks the AST looking for -borrows. For each borrow, there are three bits of information: the -place `P` being borrowed and the mutability `MQ` and lifetime `LT` -of the resulting pointer. Given those, `gather_loans` applies four -validity tests: - -1. `MUTABILITY(P, MQ)`: The mutability of the reference is -compatible with the mutability of `P` (i.e., not borrowing immutable -data as mutable). - -2. `ALIASABLE(P, MQ)`: The aliasability of the reference is -compatible with the aliasability of `P`. The goal is to prevent -`&mut` borrows of aliasability data. - -3. `LIFETIME(P, LT, MQ)`: The lifetime of the borrow does not exceed -the lifetime of the value being borrowed. - -4. `RESTRICTIONS(P, LT, ACTIONS) = RS`: This pass checks and computes the -restrictions to maintain memory safety. These are the restrictions -that will go into the final loan. We'll discuss in more detail below. - -## Checking mutability - -Checking mutability is fairly straightforward. We just want to prevent -immutable data from being borrowed as mutable. Note that it is ok to borrow -mutable data as immutable, since that is simply a freeze. The judgement -`MUTABILITY(P, MQ)` means the mutability of `P` is compatible with a borrow -of mutability `MQ`. The Rust code corresponding to this predicate is the -function `check_mutability` in `middle::borrowck::gather_loans`. - -### Checking mutability of variables - -*Code pointer:* Function `check_mutability()` in `gather_loans/mod.rs`, -but also the code in `mem_categorization`. - -Let's begin with the rules for variables, which state that if a -variable is declared as mutable, it may be borrowed any which way, but -otherwise the variable must be borrowed as immutable: - -```text -MUTABILITY(X, MQ) // M-Var-Mut - DECL(X) = mut - -MUTABILITY(X, imm) // M-Var-Imm - DECL(X) = imm -``` - -### Checking mutability of owned content - -Fields and boxes inherit their mutability from -their base expressions, so both of their rules basically -delegate the check to the base expression `P`: - -```text -MUTABILITY(P.f, MQ) // M-Field - MUTABILITY(P, MQ) - -MUTABILITY(*P, MQ) // M-Deref-Unique - TYPE(P) = Box - MUTABILITY(P, MQ) -``` - -### Checking mutability of immutable pointer types - -Immutable pointer types like `&T` can only -be borrowed if MQ is immutable: - -```text -MUTABILITY(*P, imm) // M-Deref-Borrowed-Imm - TYPE(P) = &Ty -``` - -### Checking mutability of mutable pointer types - -`&mut T` can be frozen, so it is acceptable to borrow it as either imm or mut: - -```text -MUTABILITY(*P, MQ) // M-Deref-Borrowed-Mut - TYPE(P) = &mut Ty -``` - -## Checking aliasability - -The goal of the aliasability check is to ensure that we never permit `&mut` -borrows of aliasable data. The judgement `ALIASABLE(P, MQ)` means the -aliasability of `P` is compatible with a borrow of mutability `MQ`. The Rust -code corresponding to this predicate is the function `check_aliasability()` in -`middle::borrowck::gather_loans`. - -### Checking aliasability of variables - -Local variables are never aliasable as they are accessible only within -the stack frame. - -```text - ALIASABLE(X, MQ) // M-Var-Mut -``` - -### Checking aliasable of owned content - -Owned content is aliasable if it is found in an aliasable location: - -```text -ALIASABLE(P.f, MQ) // M-Field - ALIASABLE(P, MQ) - -ALIASABLE(*P, MQ) // M-Deref-Unique - ALIASABLE(P, MQ) -``` - -### Checking aliasability of immutable pointer types - -Immutable pointer types like `&T` are aliasable, and hence can only be -borrowed immutably: - -```text -ALIASABLE(*P, imm) // M-Deref-Borrowed-Imm - TYPE(P) = &Ty -``` - -### Checking aliasability of mutable pointer types - -`&mut T` can be frozen, so it is acceptable to borrow it as either imm or mut: - -```text -ALIASABLE(*P, MQ) // M-Deref-Borrowed-Mut - TYPE(P) = &mut Ty -``` - -## Checking lifetime - -These rules aim to ensure that no data is borrowed for a scope that exceeds -its lifetime. These two computations wind up being intimately related. -Formally, we define a predicate `LIFETIME(P, LT, MQ)`, which states that -"the place `P` can be safely borrowed for the lifetime `LT` with mutability -`MQ`". The Rust code corresponding to this predicate is the module -`middle::borrowck::gather_loans::lifetime`. - -### Checking lifetime of variables - -The rule for variables states that a variable can only be borrowed a -lifetime `LT` that is a subregion of the variable's scope: - -```text -LIFETIME(X, LT, MQ) // L-Local - LT <= block where X is declared -``` - -### Checking lifetime for owned content - -The lifetime of a field or box is the same as the lifetime -of its owner: - -```text -LIFETIME(P.f, LT, MQ) // L-Field - LIFETIME(P, LT, MQ) - -LIFETIME(*P, LT, MQ) // L-Deref-Send - TYPE(P) = Box - LIFETIME(P, LT, MQ) -``` - -### Checking lifetime for derefs of references - -References have a lifetime `LT'` associated with them. The -data they point at has been guaranteed to be valid for at least this -lifetime. Therefore, the borrow is valid so long as the lifetime `LT` -of the borrow is shorter than the lifetime `LT'` of the pointer -itself: - -```text -LIFETIME(*P, LT, MQ) // L-Deref-Borrowed - TYPE(P) = <' Ty OR <' mut Ty - LT <= LT' -``` - -## Computing the restrictions - -The final rules govern the computation of *restrictions*, meaning that -we compute the set of actions that will be illegal for the life of the -loan. The predicate is written `RESTRICTIONS(P, LT, ACTIONS) = -RESTRICTION*`, which can be read "in order to prevent `ACTIONS` from -occurring on `P`, the restrictions `RESTRICTION*` must be respected -for the lifetime of the loan". - -Note that there is an initial set of restrictions: these restrictions -are computed based on the kind of borrow: - -```text -&mut P => RESTRICTIONS(P, LT, MUTATE|CLAIM|FREEZE) -&P => RESTRICTIONS(P, LT, MUTATE|CLAIM) -``` - -The reasoning here is that a mutable borrow must be the only writer, -therefore it prevents other writes (`MUTATE`), mutable borrows -(`CLAIM`), and immutable borrows (`FREEZE`). An immutable borrow -permits other immutable borrows but forbids writes and mutable borrows. - -### Restrictions for loans of a local variable - -The simplest case is a borrow of a local variable `X`: - -```text -RESTRICTIONS(X, LT, ACTIONS) = (X, ACTIONS) // R-Variable -``` - -In such cases we just record the actions that are not permitted. - -### Restrictions for loans of fields - -Restricting a field is the same as restricting the owner of that -field: - -```text -RESTRICTIONS(P.f, LT, ACTIONS) = RS, (P.f, ACTIONS) // R-Field - RESTRICTIONS(P, LT, ACTIONS) = RS -``` - -The reasoning here is as follows. If the field must not be mutated, -then you must not mutate the owner of the field either, since that -would indirectly modify the field. Similarly, if the field cannot be -frozen or aliased, we cannot allow the owner to be frozen or aliased, -since doing so indirectly freezes/aliases the field. This is the -origin of inherited mutability. - -### Restrictions for loans of owned referents - -Because the mutability of owned referents is inherited, restricting an -owned referent is similar to restricting a field, in that it implies -restrictions on the pointer. However, boxes have an important -twist: if the owner `P` is mutated, that causes the owned referent -`*P` to be freed! So whenever an owned referent `*P` is borrowed, we -must prevent the box `P` from being mutated, which means -that we always add `MUTATE` and `CLAIM` to the restriction set imposed -on `P`: - -```text -RESTRICTIONS(*P, LT, ACTIONS) = RS, (*P, ACTIONS) // R-Deref-Send-Pointer - TYPE(P) = Box - RESTRICTIONS(P, LT, ACTIONS|MUTATE|CLAIM) = RS -``` - -### Restrictions for loans of immutable borrowed referents - -Immutable borrowed referents are freely aliasable, meaning that -the compiler does not prevent you from copying the pointer. This -implies that issuing restrictions is useless. We might prevent the -user from acting on `*P` itself, but there could be another path -`*P1` that refers to the exact same memory, and we would not be -restricting that path. Therefore, the rule for `&Ty` pointers -always returns an empty set of restrictions, and it only permits -restricting `MUTATE` and `CLAIM` actions: - -```text -RESTRICTIONS(*P, LT, ACTIONS) = [] // R-Deref-Imm-Borrowed - TYPE(P) = <' Ty - LT <= LT' // (1) - ACTIONS subset of [MUTATE, CLAIM] -``` - -The reason that we can restrict `MUTATE` and `CLAIM` actions even -without a restrictions list is that it is never legal to mutate nor to -borrow mutably the contents of a `&Ty` pointer. In other words, -those restrictions are already inherent in the type. - -Clause (1) in the rule for `&Ty` deserves mention. Here I -specify that the lifetime of the loan must be less than the lifetime -of the `&Ty` pointer. In simple cases, this clause is redundant, since -the `LIFETIME()` function will already enforce the required rule: - -```rust -fn foo(point: &'a Point) -> &'static i32 { - &point.x // Error -} -``` - -The above example fails to compile both because of clause (1) above -but also by the basic `LIFETIME()` check. However, in more advanced -examples involving multiple nested pointers, clause (1) is needed: - -```rust -fn foo(point: &'a &'b mut Point) -> &'b i32 { - &point.x // Error -} -``` - -The `LIFETIME` rule here would accept `'b` because, in fact, the -*memory is* guaranteed to remain valid (i.e., not be freed) for the -lifetime `'b`, since the `&mut` pointer is valid for `'b`. However, we -are returning an immutable reference, so we need the memory to be both -valid and immutable. Even though `point.x` is referenced by an `&mut` -pointer, it can still be considered immutable so long as that `&mut` -pointer is found in an aliased location. That means the memory is -guaranteed to be *immutable* for the lifetime of the `&` pointer, -which is only `'a`, not `'b`. Hence this example yields an error. - -As a final twist, consider the case of two nested *immutable* -pointers, rather than a mutable pointer within an immutable one: - -```rust -fn foo(point: &'a &'b Point) -> &'b i32 { - &point.x // OK -} -``` - -This function is legal. The reason for this is that the inner pointer -(`*point : &'b Point`) is enough to guarantee the memory is immutable -and valid for the lifetime `'b`. This is reflected in -`RESTRICTIONS()` by the fact that we do not recurse (i.e., we impose -no restrictions on `P`, which in this particular case is the pointer -`point : &'a &'b Point`). - -#### Why both `LIFETIME()` and `RESTRICTIONS()`? - -Given the previous text, it might seem that `LIFETIME` and -`RESTRICTIONS` should be folded together into one check, but there is -a reason that they are separated. They answer separate concerns. -The rules pertaining to `LIFETIME` exist to ensure that we don't -create a borrowed pointer that outlives the memory it points at. So -`LIFETIME` prevents a function like this: - -```rust -fn get_1<'a>() -> &'a i32 { - let x = 1; - &x -} -``` - -Here we would be returning a pointer into the stack. Clearly bad. - -However, the `RESTRICTIONS` rules are more concerned with how memory -is used. The example above doesn't generate an error according to -`RESTRICTIONS` because, for local variables, we don't require that the -loan lifetime be a subset of the local variable lifetime. The idea -here is that we *can* guarantee that `x` is not (e.g.) mutated for the -lifetime `'a`, even though `'a` exceeds the function body and thus -involves unknown code in the caller -- after all, `x` ceases to exist -after we return and hence the remaining code in `'a` cannot possibly -mutate it. This distinction is important for type checking functions -like this one: - -```rust -fn inc_and_get<'a>(p: &'a mut Point) -> &'a i32 { - p.x += 1; - &p.x -} -``` - -In this case, we take in a `&mut` and return a frozen borrowed pointer -with the same lifetime. So long as the lifetime of the returned value -doesn't exceed the lifetime of the `&mut` we receive as input, this is -fine, though it may seem surprising at first (it surprised me when I -first worked it through). After all, we're guaranteeing that `*p` -won't be mutated for the lifetime `'a`, even though we can't "see" the -entirety of the code during that lifetime, since some of it occurs in -our caller. But we *do* know that nobody can mutate `*p` except -through `p`. So if we don't mutate `*p` and we don't return `p`, then -we know that the right to mutate `*p` has been lost to our caller -- -in terms of capability, the caller passed in the ability to mutate -`*p`, and we never gave it back. (Note that we can't return `p` while -`*p` is borrowed since that would be a move of `p`, as `&mut` pointers -are affine.) - -### Restrictions for loans of mutable borrowed referents - -Mutable borrowed pointers are guaranteed to be the only way to mutate -their referent. This permits us to take greater license with them; for -example, the referent can be frozen simply be ensuring that we do not -use the original pointer to perform mutate. Similarly, we can allow -the referent to be claimed, so long as the original pointer is unused -while the new claimant is live. - -The rule for mutable borrowed pointers is as follows: - -```text -RESTRICTIONS(*P, LT, ACTIONS) = RS, (*P, ACTIONS) // R-Deref-Mut-Borrowed - TYPE(P) = <' mut Ty - LT <= LT' // (1) - RESTRICTIONS(P, LT, ACTIONS) = RS // (2) -``` - -Let's examine the two numbered clauses: - -Clause (1) specifies that the lifetime of the loan (`LT`) cannot -exceed the lifetime of the `&mut` pointer (`LT'`). The reason for this -is that the `&mut` pointer is guaranteed to be the only legal way to -mutate its referent -- but only for the lifetime `LT'`. After that -lifetime, the loan on the referent expires and hence the data may be -modified by its owner again. This implies that we are only able to -guarantee that the referent will not be modified or aliased for a -maximum of `LT'`. - -Here is a concrete example of a bug this rule prevents: - -```rust -// Test region-reborrow-from-shorter-mut-ref.rs: -fn copy_borrowed_ptr<'a,'b,T>(x: &'a mut &'b mut T) -> &'b mut T { - &mut **p // ERROR due to clause (1) -} -fn main() { - let mut x = 1; - let mut y = &mut x; // <-'b-----------------------------+ - // +-'a--------------------+ | - // v v | - let z = copy_borrowed_ptr(&mut y); // y is lent | - *y += 1; // Here y==z, so both should not be usable... | - *z += 1; // ...and yet they would be, but for clause 1. | -} // <------------------------------------------------------+ -``` - -Clause (2) propagates the restrictions on the referent to the pointer -itself. This is the same as with an box, though the -reasoning is mildly different. The basic goal in all cases is to -prevent the user from establishing another route to the same data. To -see what I mean, let's examine various cases of what can go wrong and -show how it is prevented. - -**Example danger 1: Moving the base pointer.** One of the simplest -ways to violate the rules is to move the base pointer to a new name -and access it via that new name, thus bypassing the restrictions on -the old name. Here is an example: - -```rust -// src/test/compile-fail/borrowck-move-mut-base-ptr.rs -fn foo(t0: &mut i32) { - let p: &i32 = &*t0; // Freezes `*t0` - let t1 = t0; //~ ERROR cannot move out of `t0` - *t1 = 22; // OK, not a write through `*t0` -} -``` - -Remember that `&mut` pointers are linear, and hence `let t1 = t0` is a -move of `t0` -- or would be, if it were legal. Instead, we get an -error, because clause (2) imposes restrictions on `P` (`t0`, here), -and any restrictions on a path make it impossible to move from that -path. - -**Example danger 2: Claiming the base pointer.** Another possible -danger is to mutably borrow the base path. This can lead to two bad -scenarios. The most obvious is that the mutable borrow itself becomes -another path to access the same data, as shown here: - -```rust -// src/test/compile-fail/borrowck-mut-borrow-of-mut-base-ptr.rs -fn foo<'a>(mut t0: &'a mut i32, - mut t1: &'a mut i32) { - let p: &i32 = &*t0; // Freezes `*t0` - let mut t2 = &mut t0; //~ ERROR cannot borrow `t0` - **t2 += 1; // Mutates `*t0` -} -``` - -In this example, `**t2` is the same memory as `*t0`. Because `t2` is -an `&mut` pointer, `**t2` is a unique path and hence it would be -possible to mutate `**t2` even though that memory was supposed to be -frozen by the creation of `p`. However, an error is reported -- the -reason is that the freeze `&*t0` will restrict claims and mutation -against `*t0` which, by clause 2, in turn prevents claims and mutation -of `t0`. Hence the claim `&mut t0` is illegal. - -Another danger with an `&mut` pointer is that we could swap the `t0` -value away to create a new path: - -```rust -// src/test/compile-fail/borrowck-swap-mut-base-ptr.rs -fn foo<'a>(mut t0: &'a mut i32, - mut t1: &'a mut i32) { - let p: &i32 = &*t0; // Freezes `*t0` - swap(&mut t0, &mut t1); //~ ERROR cannot borrow `t0` - *t1 = 22; -} -``` - -This is illegal for the same reason as above. Note that if we added -back a swap operator -- as we used to have -- we would want to be very -careful to ensure this example is still illegal. - -**Example danger 3: Freeze the base pointer.** In the case where the -referent is claimed, even freezing the base pointer can be dangerous, -as shown in the following example: - -```rust -// src/test/compile-fail/borrowck-borrow-of-mut-base-ptr.rs -fn foo<'a>(mut t0: &'a mut i32, - mut t1: &'a mut i32) { - let p: &mut i32 = &mut *t0; // Claims `*t0` - let mut t2 = &t0; //~ ERROR cannot borrow `t0` - let q: &i32 = &*t2; // Freezes `*t0` but not through `*p` - *p += 1; // violates type of `*q` -} -``` - -Here the problem is that `*t0` is claimed by `p`, and hence `p` wants -to be the controlling pointer through which mutation or freezes occur. -But `t2` would -- if it were legal -- have the type `& &mut i32`, and -hence would be a mutable pointer in an aliasable location, which is -considered frozen (since no one can write to `**t2` as it is not a -unique path). Therefore, we could reasonably create a frozen `&i32` -pointer pointing at `*t0` that coexists with the mutable pointer `p`, -which is clearly unsound. - -However, it is not always unsafe to freeze the base pointer. In -particular, if the referent is frozen, there is no harm in it: - -```rust -// src/test/ui/borrowck-borrow-of-mut-base-ptr-safe.rs -fn foo<'a>(mut t0: &'a mut i32, - mut t1: &'a mut i32) { - let p: &i32 = &*t0; // Freezes `*t0` - let mut t2 = &t0; - let q: &i32 = &*t2; // Freezes `*t0`, but that's ok... - let r: &i32 = &*t0; // ...after all, could do same thing directly. -} -``` - -In this case, creating the alias `t2` of `t0` is safe because the only -thing `t2` can be used for is to further freeze `*t0`, which is -already frozen. In particular, we cannot assign to `*t0` through the -new alias `t2`, as demonstrated in this test case: - -```rust -// src/test/ui/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs -fn foo(t0: & &mut i32) { - let t1 = t0; - let p: &i32 = &**t0; - **t1 = 22; //~ ERROR cannot assign -} -``` - -This distinction is reflected in the rules. When doing an `&mut` -borrow -- as in the first example -- the set `ACTIONS` will be -`CLAIM|MUTATE|FREEZE`, because claiming the referent implies that it -cannot be claimed, mutated, or frozen by anyone else. These -restrictions are propagated back to the base path and hence the base -path is considered unfreezable. - -In contrast, when the referent is merely frozen -- as in the second -example -- the set `ACTIONS` will be `CLAIM|MUTATE`, because freezing -the referent implies that it cannot be claimed or mutated but permits -others to freeze. Hence when these restrictions are propagated back to -the base path, it will still be considered freezable. - - - -**FIXME [RFC 1751](https://github.com/rust-lang/rfcs/issues/1751) -Restrictions against mutating the base pointer.** -When an `&mut` pointer is frozen or claimed, we currently pass along the -restriction against MUTATE to the base pointer. I do not believe this -restriction is needed. It dates from the days when we had a way to -mutate that preserved the value being mutated (i.e., swap). Nowadays -the only form of mutation is assignment, which destroys the pointer -being mutated -- therefore, a mutation cannot create a new path to the -same data. Rather, it removes an existing path. This implies that not -only can we permit mutation, we can have mutation kill restrictions in -the dataflow sense. - -**WARNING:** We do not currently have `const` borrows in the -language. If they are added back in, we must ensure that they are -consistent with all of these examples. The crucial question will be -what sorts of actions are permitted with a `&const &mut` pointer. I -would suggest that an `&mut` referent found in an `&const` location be -prohibited from both freezes and claims. This would avoid the need to -prevent `const` borrows of the base pointer when the referent is -borrowed. - -[ Previous revisions of this document discussed `&const` in more detail. -See the revision history. ] - -# Moves and initialization - -The borrow checker is also in charge of ensuring that: - -- all memory which is accessed is initialized -- immutable local variables are assigned at most once. - -These are two separate dataflow analyses built on the same -framework. Let's look at checking that memory is initialized first; -the checking of immutable local variable assignments works in a very -similar way. - -To track the initialization of memory, we actually track all the -points in the program that *create uninitialized memory*, meaning -moves and the declaration of uninitialized variables. For each of -these points, we create a bit in the dataflow set. Assignments to a -variable `x` or path `a.b.c` kill the move/uninitialization bits for -those paths and any subpaths (e.g., `x`, `x.y`, `a.b.c`, `*a.b.c`). -Bits are unioned when two control-flow paths join. Thus, the -presence of a bit indicates that the move may have occurred without an -intervening assignment to the same memory. At each use of a variable, -we examine the bits in scope, and check that none of them are -moves/uninitializations of the variable that is being used. - -Let's look at a simple example: - -```rust -fn foo(a: Box) { - let b: Box; // Gen bit 0. - - if cond { // Bits: 0 - use(&*a); - b = a; // Gen bit 1, kill bit 0. - use(&*b); - } else { - // Bits: 0 - } - // Bits: 0,1 - use(&*a); // Error. - use(&*b); // Error. -} - -fn use(a: &i32) { } -``` - -In this example, the variable `b` is created uninitialized. In one -branch of an `if`, we then move the variable `a` into `b`. Once we -exit the `if`, therefore, it is an error to use `a` or `b` since both -are only conditionally initialized. I have annotated the dataflow -state using comments. There are two dataflow bits, with bit 0 -corresponding to the creation of `b` without an initializer, and bit 1 -corresponding to the move of `a`. The assignment `b = a` both -generates bit 1, because it is a move of `a`, and kills bit 0, because -`b` is now initialized. On the else branch, though, `b` is never -initialized, and so bit 0 remains untouched. When the two flows of -control join, we union the bits from both sides, resulting in both -bits 0 and 1 being set. Thus any attempt to use `a` uncovers the bit 1 -from the "then" branch, showing that `a` may be moved, and any attempt -to use `b` uncovers bit 0, from the "else" branch, showing that `b` -may not be initialized. - -## Initialization of immutable variables - -Initialization of immutable variables works in a very similar way, -except that: - -1. we generate bits for each assignment to a variable; -2. the bits are never killed except when the variable goes out of scope. - -Thus the presence of an assignment bit indicates that the assignment -may have occurred. Note that assignments are only killed when the -variable goes out of scope, as it is not relevant whether or not there -has been a move in the meantime. Using these bits, we can declare that -an assignment to an immutable variable is legal iff there is no other -assignment bit to that same variable in scope. - -## Why is the design made this way? - -It may seem surprising that we assign dataflow bits to *each move* -rather than *each path being moved*. This is somewhat less efficient, -since on each use, we must iterate through all moves and check whether -any of them correspond to the path in question. Similar concerns apply -to the analysis for double assignments to immutable variables. The -main reason to do it this way is that it allows us to print better -error messages, because when a use occurs, we can print out the -precise move that may be in scope, rather than simply having to say -"the variable may not be initialized". - -## Data structures used in the move analysis - -The move analysis maintains several data structures that enable it to -cross-reference moves and assignments to determine when they may be -moving/assigning the same memory. These are all collected into the -`MoveData` and `FlowedMoveData` structs. The former represents the set -of move paths, moves, and assignments, and the latter adds in the -results of a dataflow computation. - -### Move paths - -The `MovePath` tree tracks every path that is moved or assigned to. -These paths have the same form as the `LoanPath` data structure, which -in turn is the "real world version of the places `P` that we -introduced earlier. The difference between a `MovePath` and a `LoanPath` -is that move paths are: - -1. Canonicalized, so that we have exactly one copy of each, and - we can refer to move paths by index; -2. Cross-referenced with other paths into a tree, so that given a move - path we can efficiently find all parent move paths and all - extensions (e.g., given the `a.b` move path, we can easily find the - move path `a` and also the move paths `a.b.c`) -3. Cross-referenced with moves and assignments, so that we can - easily find all moves and assignments to a given path. - -The mechanism that we use is to create a `MovePath` record for each -move path. These are arranged in an array and are referenced using -`MovePathIndex` values, which are newtype'd indices. The `MovePath` -structs are arranged into a tree, representing using the standard -Knuth representation where each node has a child 'pointer' and a "next -sibling" 'pointer'. In addition, each `MovePath` has a parent -'pointer'. In this case, the 'pointers' are just `MovePathIndex` -values. - -In this way, if we want to find all base paths of a given move path, -we can just iterate up the parent pointers (see `each_base_path()` in -the `move_data` module). If we want to find all extensions, we can -iterate through the subtree (see `each_extending_path()`). - -### Moves and assignments - -There are structs to represent moves (`Move`) and assignments -(`Assignment`), and these are also placed into arrays and referenced -by index. All moves of a particular path are arranged into a linked -lists, beginning with `MovePath.first_move` and continuing through -`Move.next_move`. - -We distinguish between "var" assignments, which are assignments to a -variable like `x = foo`, and "path" assignments (`x.f = foo`). This -is because we need to assign dataflows to the former, but not the -latter, so as to check for double initialization of immutable -variables. - -### Gathering and checking moves - -Like loans, we distinguish two phases. The first, gathering, is where -we uncover all the moves and assignments. As with loans, we do some -basic sanity checking in this phase, so we'll report errors if you -attempt to move out of a borrowed pointer etc. Then we do the dataflow -(see `FlowedMoveData::new`). Finally, in the `check_loans.rs` code, we -walk back over, identify all uses, assignments, and captures, and -check that they are legal given the set of dataflow bits we have -computed for that program point. - -# Drop flags and structural fragments - -In addition to the job of enforcing memory safety, the borrow checker -code is also responsible for identifying the *structural fragments* of -data in the function, to support out-of-band dynamic drop flags -allocated on the stack. (For background, see [RFC PR #320].) - -[RFC PR #320]: https://github.com/rust-lang/rfcs/pull/320 - -Semantically, each piece of data that has a destructor may need a -boolean flag to indicate whether or not its destructor has been run -yet. However, in many cases there is no need to actually maintain such -a flag: It can be apparent from the code itself that a given path is -always initialized (or always deinitialized) when control reaches the -end of its owner's scope, and thus we can unconditionally emit (or -not) the destructor invocation for that path. - -A simple example of this is the following: - -```rust -struct D { p: i32 } -impl D { fn new(x: i32) -> D { ... } -impl Drop for D { ... } - -fn foo(a: D, b: D, t: || -> bool) { - let c: D; - let d: D; - if t() { c = b; } -} -``` - -At the end of the body of `foo`, the compiler knows that `a` is -initialized, introducing a drop obligation (deallocating the boxed -integer) for the end of `a`'s scope that is run unconditionally. -Likewise the compiler knows that `d` is not initialized, and thus it -leave out the drop code for `d`. - -The compiler cannot statically know the drop-state of `b` nor `c` at -the end of their scope, since that depends on the value of -`t`. Therefore, we need to insert boolean flags to track whether we -need to drop `b` and `c`. - -However, the matter is not as simple as just mapping local variables -to their corresponding drop flags when necessary. In particular, in -addition to being able to move data out of local variables, Rust -allows one to move values in and out of structured data. - -Consider the following: - -```rust -struct S { x: D, y: D, z: D } - -fn foo(a: S, mut b: S, t: || -> bool) { - let mut c: S; - let d: S; - let e: S = a.clone(); - if t() { - c = b; - b.x = e.y; - } - if t() { c.y = D::new(4); } -} -``` - -As before, the drop obligations of `a` and `d` can be statically -determined, and again the state of `b` and `c` depend on dynamic -state. But additionally, the dynamic drop obligations introduced by -`b` and `c` are not just per-local boolean flags. For example, if the -first call to `t` returns `false` and the second call `true`, then at -the end of their scope, `b` will be completely initialized, but only -`c.y` in `c` will be initialized. If both calls to `t` return `true`, -then at the end of their scope, `c` will be completely initialized, -but only `b.x` will be initialized in `b`, and only `e.x` and `e.z` -will be initialized in `e`. - -Note that we need to cover the `z` field in each case in some way, -since it may (or may not) need to be dropped, even though `z` is never -directly mentioned in the body of the `foo` function. We call a path -like `b.z` a *fragment sibling* of `b.x`, since the field `z` comes -from the same structure `S` that declared the field `x` in `b.x`. - -In general we need to maintain boolean flags that match the -`S`-structure of both `b` and `c`. In addition, we need to consult -such a flag when doing an assignment (such as `c.y = D::new(4);` -above), in order to know whether or not there is a previous value that -needs to be dropped before we do the assignment. - -So for any given function, we need to determine what flags are needed -to track its drop obligations. Our strategy for determining the set of -flags is to represent the fragmentation of the structure explicitly: -by starting initially from the paths that are explicitly mentioned in -moves and assignments (such as `b.x` and `c.y` above), and then -traversing the structure of the path's type to identify leftover -*unmoved fragments*: assigning into `c.y` means that `c.x` and `c.z` -are leftover unmoved fragments. Each fragment represents a drop -obligation that may need to be tracked. Paths that are only moved or -assigned in their entirety (like `a` and `d`) are treated as a single -drop obligation. - -The fragment construction process works by piggy-backing on the -existing `move_data` module. We already have callbacks that visit each -direct move and assignment; these form the basis for the sets of -moved_leaf_paths and assigned_leaf_paths. From these leaves, we can -walk up their parent chain to identify all of their parent paths. -We need to identify the parents because of cases like the following: - -```rust -struct Pair{ x: X, y: Y } -fn foo(dd_d_d: Pair, D>, D>) { - other_function(dd_d_d.x.y); -} -``` - -In this code, the move of the path `dd_d.x.y` leaves behind not only -the fragment drop-obligation `dd_d.x.x` but also `dd_d.y` as well. - -Once we have identified the directly-referenced leaves and their -parents, we compute the left-over fragments, in the function -`fragments::add_fragment_siblings`. As of this writing this works by -looking at each directly-moved or assigned path P, and blindly -gathering all sibling fields of P (as well as siblings for the parents -of P, etc). After accumulating all such siblings, we filter out the -entries added as siblings of P that turned out to be -directly-referenced paths (or parents of directly referenced paths) -themselves, thus leaving the never-referenced "left-overs" as the only -thing left from the gathering step. - -## Array structural fragments - -A special case of the structural fragments discussed above are -the elements of an array that has been passed by value, such as -the following: - -```rust -fn foo(a: [D; 10], i: i32) -> D { - a[i] -} -``` - -The above code moves a single element out of the input array `a`. -The remainder of the array still needs to be dropped; i.e., it -is a structural fragment. Note that after performing such a move, -it is not legal to read from the array `a`. There are a number of -ways to deal with this, but the important thing to note is that -the semantics needs to distinguish in some manner between a -fragment that is the *entire* array versus a fragment that represents -all-but-one element of the array. A place where that distinction -would arise is the following: - -```rust -fn foo(a: [D; 10], b: [D; 10], i: i32, t: bool) -> D { - if t { - a[i] - } else { - b[i] - } - - // When control exits, we will need either to drop all of `a` - // and all-but-one of `b`, or to drop all of `b` and all-but-one - // of `a`. -} -``` - -There are a number of ways that the codegen backend could choose to -compile this (e.g. a `[bool; 10]` array for each such moved array; -or an `Option` for each moved array). From the viewpoint of the -borrow-checker, the important thing is to record what kind of fragment -is implied by the relevant moves. - -# Future work - -While writing up these docs, I encountered some rules I believe to be -stricter than necessary: - -- I think restricting the `&mut` P against moves and `ALIAS` is sufficient, - `MUTATE` and `CLAIM` are overkill. `MUTATE` was necessary when swap was - a built-in operator, but as it is not, it is implied by `CLAIM`, - and `CLAIM` is implied by `ALIAS`. The only net effect of this is an - extra error message in some cases, though. -- I have not described how closures interact. Current code is unsound. - I am working on describing and implementing the fix. -- If we wish, we can easily extend the move checking to allow finer-grained - tracking of what is initialized and what is not, enabling code like - this: - - a = x.f.g; // x.f.g is now uninitialized - // here, x and x.f are not usable, but x.f.h *is* - x.f.g = b; // x.f.g is not initialized - // now x, x.f, x.f.g, x.f.h are all usable - - What needs to change here, most likely, is that the `moves` module - should record not only what paths are moved, but what expressions - are actual *uses*. For example, the reference to `x` in `x.f.g = b` - is not a true *use* in the sense that it requires `x` to be fully - initialized. This is in fact why the above code produces an error - today: the reference to `x` in `x.f.g = b` is considered illegal - because `x` is not fully initialized. - -There are also some possible refactorings: - -- It might be nice to replace all loan paths with the MovePath mechanism, - since they allow lightweight comparison using an integer. diff --git a/src/librustc_ast_borrowck/borrowck/check_loans.rs b/src/librustc_ast_borrowck/borrowck/check_loans.rs deleted file mode 100644 index 3d824ee6ce1e8..0000000000000 --- a/src/librustc_ast_borrowck/borrowck/check_loans.rs +++ /dev/null @@ -1,680 +0,0 @@ -// ---------------------------------------------------------------------- -// Checking loans -// -// Phase 2 of check: we walk down the tree and check that: -// 1. assignments are always made to mutable locations; -// 2. loans made in overlapping scopes do not conflict -// 3. assignments do not affect things loaned out as immutable -// 4. moves do not affect things loaned out in any way - -use crate::borrowck::*; -use crate::borrowck::InteriorKind::{InteriorElement, InteriorField}; -use rustc::middle::expr_use_visitor as euv; -use rustc::middle::expr_use_visitor::MutateMode; -use rustc::middle::mem_categorization as mc; -use rustc::middle::mem_categorization::Categorization; -use rustc::middle::region; -use rustc::ty::{self, TyCtxt, RegionKind}; -use syntax_pos::Span; -use rustc::hir; -use rustc::hir::Node; -use log::debug; - -use std::rc::Rc; - -// FIXME (#16118): These functions are intended to allow the borrow checker to -// be less precise in its handling of Box while still allowing moves out of a -// Box. They should be removed when Unique is removed from LoanPath. - -fn owned_ptr_base_path<'a, 'tcx>(loan_path: &'a LoanPath<'tcx>) -> &'a LoanPath<'tcx> { - //! Returns the base of the leftmost dereference of an Unique in - //! `loan_path`. If there is no dereference of an Unique in `loan_path`, - //! then it just returns `loan_path` itself. - - return match helper(loan_path) { - Some(new_loan_path) => new_loan_path, - None => loan_path, - }; - - fn helper<'a, 'tcx>(loan_path: &'a LoanPath<'tcx>) -> Option<&'a LoanPath<'tcx>> { - match loan_path.kind { - LpVar(_) | LpUpvar(_) => None, - LpExtend(ref lp_base, _, LpDeref(mc::Unique)) => { - match helper(&lp_base) { - v @ Some(_) => v, - None => Some(&lp_base) - } - } - LpDowncast(ref lp_base, _) | - LpExtend(ref lp_base, ..) => helper(&lp_base) - } - } -} - -fn owned_ptr_base_path_rc<'tcx>(loan_path: &Rc>) -> Rc> { - //! The equivalent of `owned_ptr_base_path` for an &Rc rather than - //! a &LoanPath. - - return match helper(loan_path) { - Some(new_loan_path) => new_loan_path, - None => loan_path.clone() - }; - - fn helper<'tcx>(loan_path: &Rc>) -> Option>> { - match loan_path.kind { - LpVar(_) | LpUpvar(_) => None, - LpExtend(ref lp_base, _, LpDeref(mc::Unique)) => { - match helper(lp_base) { - v @ Some(_) => v, - None => Some(lp_base.clone()) - } - } - LpDowncast(ref lp_base, _) | - LpExtend(ref lp_base, ..) => helper(lp_base) - } - } -} - -struct CheckLoanCtxt<'a, 'tcx> { - bccx: &'a BorrowckCtxt<'a, 'tcx>, - dfcx_loans: &'a LoanDataFlow<'tcx>, - move_data: &'a move_data::FlowedMoveData<'tcx>, - all_loans: &'a [Loan<'tcx>], - movable_generator: bool, -} - -impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { - fn consume(&mut self, - consume_id: hir::HirId, - _: Span, - cmt: &mc::cmt_<'tcx>, - mode: euv::ConsumeMode) { - debug!("consume(consume_id={}, cmt={:?})", consume_id, cmt); - - self.consume_common(consume_id.local_id, cmt, mode); - } - - fn matched_pat(&mut self, - _matched_pat: &hir::Pat, - _cmt: &mc::cmt_<'_>, - _mode: euv::MatchMode) { } - - fn consume_pat(&mut self, - consume_pat: &hir::Pat, - cmt: &mc::cmt_<'tcx>, - mode: euv::ConsumeMode) { - debug!("consume_pat(consume_pat={:?}, cmt={:?})", consume_pat, cmt); - - self.consume_common(consume_pat.hir_id.local_id, cmt, mode); - } - - fn borrow(&mut self, - borrow_id: hir::HirId, - borrow_span: Span, - cmt: &mc::cmt_<'tcx>, - loan_region: ty::Region<'tcx>, - bk: ty::BorrowKind, - loan_cause: euv::LoanCause) - { - debug!("borrow(borrow_id={}, cmt={:?}, loan_region={:?}, \ - bk={:?}, loan_cause={:?})", - borrow_id, cmt, loan_region, - bk, loan_cause); - - if let Some(lp) = opt_loan_path(cmt) { - self.check_if_path_is_moved(borrow_id.local_id, &lp); - } - - self.check_for_conflicting_loans(borrow_id.local_id); - - self.check_for_loans_across_yields(cmt, loan_region, borrow_span); - } - - fn mutate(&mut self, - assignment_id: hir::HirId, - _: Span, - assignee_cmt: &mc::cmt_<'tcx>, - mode: euv::MutateMode) - { - debug!("mutate(assignment_id={}, assignee_cmt={:?})", - assignment_id, assignee_cmt); - - if let Some(lp) = opt_loan_path(assignee_cmt) { - match mode { - MutateMode::Init | MutateMode::JustWrite => { - // In a case like `path = 1`, then path does not - // have to be *FULLY* initialized, but we still - // must be careful lest it contains derefs of - // pointers. - self.check_if_assigned_path_is_moved(assignee_cmt.hir_id.local_id, &lp); - } - MutateMode::WriteAndRead => { - // In a case like `path += 1`, then path must be - // fully initialized, since we will read it before - // we write it. - self.check_if_path_is_moved(assignee_cmt.hir_id.local_id, - &lp); - } - } - } - self.check_assignment(assignment_id.local_id, assignee_cmt); - } - - fn decl_without_init(&mut self, _id: hir::HirId, _span: Span) { } -} - -pub fn check_loans<'a, 'tcx>( - bccx: &BorrowckCtxt<'a, 'tcx>, - dfcx_loans: &LoanDataFlow<'tcx>, - move_data: &move_data::FlowedMoveData<'tcx>, - all_loans: &[Loan<'tcx>], - body: &hir::Body, -) { - debug!("check_loans(body id={})", body.value.hir_id); - - let def_id = bccx.tcx.hir().body_owner_def_id(body.id()); - - let hir_id = bccx.tcx.hir().as_local_hir_id(def_id).unwrap(); - let movable_generator = !match bccx.tcx.hir().get(hir_id) { - Node::Expr(&hir::Expr { - node: hir::ExprKind::Closure(.., Some(hir::GeneratorMovability::Static)), - .. - }) => true, - _ => false, - }; - - let param_env = bccx.tcx.param_env(def_id); - let mut clcx = CheckLoanCtxt { - bccx, - dfcx_loans, - move_data, - all_loans, - movable_generator, - }; - let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id); - euv::ExprUseVisitor::new(&mut clcx, - bccx.tcx, - def_id, - param_env, - &bccx.region_scope_tree, - bccx.tables, - Some(rvalue_promotable_map)) - .consume_body(body); -} - -fn compatible_borrow_kinds(borrow_kind1: ty::BorrowKind, - borrow_kind2: ty::BorrowKind) - -> bool { - borrow_kind1 == ty::ImmBorrow && borrow_kind2 == ty::ImmBorrow -} - -impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { - pub fn tcx(&self) -> TyCtxt<'tcx> { self.bccx.tcx } - - pub fn each_issued_loan(&self, node: hir::ItemLocalId, mut op: F) -> bool where - F: FnMut(&Loan<'tcx>) -> bool, - { - //! Iterates over each loan that has been issued - //! on entrance to `node`, regardless of whether it is - //! actually *in scope* at that point. Sometimes loans - //! are issued for future scopes and thus they may have been - //! *issued* but not yet be in effect. - - self.dfcx_loans.each_bit_on_entry(node, |loan_index| { - let loan = &self.all_loans[loan_index]; - op(loan) - }) - } - - pub fn each_in_scope_loan(&self, scope: region::Scope, mut op: F) -> bool where - F: FnMut(&Loan<'tcx>) -> bool, - { - //! Like `each_issued_loan()`, but only considers loans that are - //! currently in scope. - - self.each_issued_loan(scope.item_local_id(), |loan| { - if self.bccx.region_scope_tree.is_subscope_of(scope, loan.kill_scope) { - op(loan) - } else { - true - } - }) - } - - fn each_in_scope_loan_affecting_path(&self, - scope: region::Scope, - loan_path: &LoanPath<'tcx>, - mut op: F) - -> bool where - F: FnMut(&Loan<'tcx>) -> bool, - { - //! Iterates through all of the in-scope loans affecting `loan_path`, - //! calling `op`, and ceasing iteration if `false` is returned. - - // First, we check for a loan restricting the path P being used. This - // accounts for borrows of P but also borrows of subpaths, like P.a.b. - // Consider the following example: - // - // let x = &mut a.b.c; // Restricts a, a.b, and a.b.c - // let y = a; // Conflicts with restriction - - let loan_path = owned_ptr_base_path(loan_path); - let cont = self.each_in_scope_loan(scope, |loan| { - let mut ret = true; - for restr_path in &loan.restricted_paths { - if **restr_path == *loan_path { - if !op(loan) { - ret = false; - break; - } - } - } - ret - }); - - if !cont { - return false; - } - - // Next, we must check for *loans* (not restrictions) on the path P or - // any base path. This rejects examples like the following: - // - // let x = &mut a.b; - // let y = a.b.c; - // - // Limiting this search to *loans* and not *restrictions* means that - // examples like the following continue to work: - // - // let x = &mut a.b; - // let y = a.c; - - let mut loan_path = loan_path; - loop { - match loan_path.kind { - LpVar(_) | LpUpvar(_) => { - break; - } - LpDowncast(ref lp_base, _) | - LpExtend(ref lp_base, ..) => { - loan_path = &lp_base; - } - } - - let cont = self.each_in_scope_loan(scope, |loan| { - if *loan.loan_path == *loan_path { - op(loan) - } else { - true - } - }); - - if !cont { - return false; - } - } - - return true; - } - - pub fn loans_generated_by(&self, node: hir::ItemLocalId) -> Vec { - //! Returns a vector of the loans that are generated as - //! we enter `node`. - - let mut result = Vec::new(); - self.dfcx_loans.each_gen_bit(node, |loan_index| { - result.push(loan_index); - true - }); - return result; - } - - pub fn check_for_loans_across_yields(&self, - cmt: &mc::cmt_<'tcx>, - loan_region: ty::Region<'tcx>, - borrow_span: Span) { - pub fn borrow_of_local_data(cmt: &mc::cmt_<'_>) -> bool { - match cmt.cat { - // Borrows of static items is allowed - Categorization::StaticItem => false, - // Reborrow of already borrowed data is ignored - // Any errors will be caught on the initial borrow - Categorization::Deref(..) => false, - - // By-ref upvars has Derefs so they will get ignored. - // Generators counts as FnOnce so this leaves only - // by-move upvars, which is local data for generators - Categorization::Upvar(..) => true, - - Categorization::ThreadLocal(region) | - Categorization::Rvalue(region) => { - // Rvalues promoted to 'static are no longer local - if let RegionKind::ReStatic = *region { - false - } else { - true - } - } - - // Borrow of local data must be checked - Categorization::Local(..) => true, - - // For interior references and downcasts, find out if the base is local - Categorization::Downcast(ref cmt_base, _) | - Categorization::Interior(ref cmt_base, _) => borrow_of_local_data(&cmt_base), - } - } - - if !self.movable_generator { - return; - } - - if !borrow_of_local_data(cmt) { - return; - } - - let scope = match *loan_region { - // A concrete region in which we will look for a yield expression - RegionKind::ReScope(scope) => scope, - - // There cannot be yields inside an empty region - RegionKind::ReEmpty => return, - - // Local data cannot have these lifetimes - RegionKind::ReEarlyBound(..) | - RegionKind::ReLateBound(..) | - RegionKind::ReFree(..) | - RegionKind::ReStatic => { - self.bccx - .tcx - .sess.delay_span_bug(borrow_span, - &format!("unexpected region for local data {:?}", - loan_region)); - return - } - - // These cannot exist in borrowck - RegionKind::ReVar(..) | - RegionKind::RePlaceholder(..) | - RegionKind::ReClosureBound(..) | - RegionKind::ReErased => span_bug!(borrow_span, - "unexpected region in borrowck {:?}", - loan_region), - }; - - let body_id = self.bccx.body.value.hir_id.local_id; - - if self.bccx.region_scope_tree.containing_body(scope) != Some(body_id) { - // We are borrowing local data longer than its storage. - // This should result in other borrowck errors. - self.bccx.tcx.sess.delay_span_bug(borrow_span, - "borrowing local data longer than its storage"); - return; - } - - if let Some(_) = self.bccx.region_scope_tree - .yield_in_scope_for_expr(scope, cmt.hir_id, self.bccx.body) - { - self.bccx.signal_error(); - } - } - - pub fn check_for_conflicting_loans(&self, node: hir::ItemLocalId) { - //! Checks to see whether any of the loans that are issued - //! on entrance to `node` conflict with loans that have already been - //! issued when we enter `node` (for example, we do not - //! permit two `&mut` borrows of the same variable). - //! - //! (Note that some loans can be *issued* without necessarily - //! taking effect yet.) - - debug!("check_for_conflicting_loans(node={:?})", node); - - let new_loan_indices = self.loans_generated_by(node); - debug!("new_loan_indices = {:?}", new_loan_indices); - - for &new_loan_index in &new_loan_indices { - self.each_issued_loan(node, |issued_loan| { - let new_loan = &self.all_loans[new_loan_index]; - // Only report an error for the first issued loan that conflicts - // to avoid O(n^2) errors. - self.report_error_if_loans_conflict(issued_loan, new_loan) - }); - } - - for (i, &x) in new_loan_indices.iter().enumerate() { - let old_loan = &self.all_loans[x]; - for &y in &new_loan_indices[(i+1) ..] { - let new_loan = &self.all_loans[y]; - self.report_error_if_loans_conflict(old_loan, new_loan); - } - } - } - - pub fn report_error_if_loans_conflict( - &self, - old_loan: &Loan<'tcx>, - new_loan: &Loan<'tcx>, - ) -> bool { - //! Checks whether `old_loan` and `new_loan` can safely be issued - //! simultaneously. - - debug!("report_error_if_loans_conflict(old_loan={:?}, new_loan={:?})", - old_loan, - new_loan); - - // Should only be called for loans that are in scope at the same time. - assert!(self.bccx.region_scope_tree.scopes_intersect(old_loan.kill_scope, - new_loan.kill_scope)); - - self.report_error_if_loan_conflicts_with_restriction( - old_loan, new_loan) - && self.report_error_if_loan_conflicts_with_restriction( - new_loan, old_loan) - } - - pub fn report_error_if_loan_conflicts_with_restriction( - &self, - loan1: &Loan<'tcx>, - loan2: &Loan<'tcx>, - ) -> bool { - //! Checks whether the restrictions introduced by `loan1` would - //! prohibit `loan2`. - debug!("report_error_if_loan_conflicts_with_restriction(\ - loan1={:?}, loan2={:?})", - loan1, - loan2); - - if compatible_borrow_kinds(loan1.kind, loan2.kind) { - return true; - } - - let loan2_base_path = owned_ptr_base_path_rc(&loan2.loan_path); - for restr_path in &loan1.restricted_paths { - if *restr_path != loan2_base_path { continue; } - - self.bccx.signal_error(); - return false; - } - - true - } - - fn consume_common( - &self, - id: hir::ItemLocalId, - cmt: &mc::cmt_<'tcx>, - mode: euv::ConsumeMode, - ) { - if let Some(lp) = opt_loan_path(cmt) { - match mode { - euv::Copy => { - self.check_for_copy_of_frozen_path(id, &lp); - } - euv::Move(_) => { - // Sometimes moves aren't from a move path; - // this either means that the original move - // was from something illegal to move, - // or was moved from referent of an unsafe - // pointer or something like that. - if self.move_data.is_move_path(id, &lp) { - self.check_for_move_of_borrowed_path(id, &lp); - } - } - } - self.check_if_path_is_moved(id, &lp); - } - } - - fn check_for_copy_of_frozen_path(&self, - id: hir::ItemLocalId, - copy_path: &LoanPath<'tcx>) { - self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow); - } - - fn check_for_move_of_borrowed_path(&self, - id: hir::ItemLocalId, - move_path: &LoanPath<'tcx>) { - // We want to detect if there are any loans at all, so we search for - // any loans incompatible with MutBorrrow, since all other kinds of - // loans are incompatible with that. - self.analyze_restrictions_on_use(id, move_path, ty::MutBorrow); - } - - fn analyze_restrictions_on_use(&self, - expr_id: hir::ItemLocalId, - use_path: &LoanPath<'tcx>, - borrow_kind: ty::BorrowKind) { - debug!("analyze_restrictions_on_use(expr_id={:?}, use_path={:?})", - expr_id, use_path); - - let scope = region::Scope { - id: expr_id, - data: region::ScopeData::Node - }; - self.each_in_scope_loan_affecting_path( - scope, use_path, |loan| { - if !compatible_borrow_kinds(loan.kind, borrow_kind) { - self.bccx.signal_error(); - false - } else { - true - } - }); - } - - /// Reports an error if `expr` (which should be a path) - /// is using a moved/uninitialized value - fn check_if_path_is_moved(&self, - id: hir::ItemLocalId, - lp: &Rc>) { - debug!("check_if_path_is_moved(id={:?}, lp={:?})", id, lp); - - // FIXME: if you find yourself tempted to cut and paste - // the body below and then specializing the error reporting, - // consider refactoring this instead! - - let base_lp = owned_ptr_base_path_rc(lp); - self.move_data.each_move_of(id, &base_lp, |_, _| { - self.bccx.signal_error(); - false - }); - } - - /// Reports an error if assigning to `lp` will use a - /// moved/uninitialized value. Mainly this is concerned with - /// detecting derefs of uninitialized pointers. - /// - /// For example: - /// - /// ``` - /// let a: i32; - /// a = 10; // ok, even though a is uninitialized - /// ``` - /// - /// ``` - /// struct Point { x: u32, y: u32 } - /// let mut p: Point; - /// p.x = 22; // ok, even though `p` is uninitialized - /// ``` - /// - /// ```compile_fail,E0381 - /// # struct Point { x: u32, y: u32 } - /// let mut p: Box; - /// (*p).x = 22; // not ok, p is uninitialized, can't deref - /// ``` - fn check_if_assigned_path_is_moved(&self, - id: hir::ItemLocalId, - lp: &Rc>) - { - match lp.kind { - LpVar(_) | LpUpvar(_) => { - // assigning to `x` does not require that `x` is initialized - } - LpDowncast(ref lp_base, _) => { - // assigning to `(P->Variant).f` is ok if assigning to `P` is ok - self.check_if_assigned_path_is_moved(id, lp_base); - } - LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => { - match lp_base.to_type().sty { - ty::Adt(def, _) if def.has_dtor(self.tcx()) => { - // In the case where the owner implements drop, then - // the path must be initialized to prevent a case of - // partial reinitialization - // - // FIXME: could refactor via hypothetical - // generalized check_if_path_is_moved - let loan_path = owned_ptr_base_path_rc(lp_base); - self.move_data.each_move_of(id, &loan_path, |_, _| { - self.bccx - .signal_error(); - false - }); - return; - }, - _ => {}, - } - - // assigning to `P.f` is ok if assigning to `P` is ok - self.check_if_assigned_path_is_moved(id, lp_base); - } - LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) | - LpExtend(ref lp_base, _, LpDeref(_)) => { - // assigning to `P[i]` requires `P` is initialized - // assigning to `(*P)` requires `P` is initialized - self.check_if_path_is_moved(id, lp_base); - } - } - } - - fn check_assignment(&self, - assignment_id: hir::ItemLocalId, - assignee_cmt: &mc::cmt_<'tcx>) { - debug!("check_assignment(assignee_cmt={:?})", assignee_cmt); - - // Check that we don't invalidate any outstanding loans - if let Some(loan_path) = opt_loan_path(assignee_cmt) { - let scope = region::Scope { - id: assignment_id, - data: region::ScopeData::Node - }; - self.each_in_scope_loan_affecting_path(scope, &loan_path, |_| { - self.bccx.signal_error(); - false - }); - } - - // Check for reassignments to (immutable) local variables. This - // needs to be done here instead of in check_loans because we - // depend on move data. - if let Categorization::Local(_) = assignee_cmt.cat { - let lp = opt_loan_path(assignee_cmt).unwrap(); - self.move_data.each_assignment_of(assignment_id, &lp, |_| { - if !assignee_cmt.mutbl.is_mutable() { - self.bccx.signal_error(); - } - false - }); - return - } - } -} diff --git a/src/librustc_ast_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_ast_borrowck/borrowck/gather_loans/gather_moves.rs deleted file mode 100644 index 617161109b573..0000000000000 --- a/src/librustc_ast_borrowck/borrowck/gather_loans/gather_moves.rs +++ /dev/null @@ -1,135 +0,0 @@ -//! Computes moves. - -use crate::borrowck::*; -use crate::borrowck::move_data::*; -use rustc::middle::mem_categorization as mc; -use rustc::middle::mem_categorization::Categorization; -use rustc::middle::mem_categorization::InteriorOffsetKind as Kind; -use rustc::ty::{self, Ty}; - -use std::rc::Rc; -use syntax_pos::Span; -use log::debug; - -struct GatherMoveInfo<'c, 'tcx> { - id: hir::ItemLocalId, - cmt: &'c mc::cmt_<'tcx>, -} - -pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - move_data: &MoveData<'tcx>, - var_id: hir::HirId, - var_ty: Ty<'tcx>) { - let loan_path = Rc::new(LoanPath::new(LpVar(var_id), var_ty)); - move_data.add_move(bccx.tcx, loan_path, var_id.local_id); -} - -pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - move_data: &MoveData<'tcx>, - move_expr_id: hir::ItemLocalId, - cmt: &mc::cmt_<'tcx>) { - let move_info = GatherMoveInfo { - id: move_expr_id, - cmt, - }; - gather_move(bccx, move_data, move_info); -} - -pub fn gather_move_from_pat<'a, 'c, 'tcx>( - bccx: &BorrowckCtxt<'a, 'tcx>, - move_data: &MoveData<'tcx>, - move_pat: &hir::Pat, - cmt: &'c mc::cmt_<'tcx>, -) { - let move_info = GatherMoveInfo { - id: move_pat.hir_id.local_id, - cmt, - }; - - debug!("gather_move_from_pat: move_pat={:?}", move_pat); - - gather_move(bccx, move_data, move_info); -} - -fn gather_move<'a, 'c, 'tcx>( - bccx: &BorrowckCtxt<'a, 'tcx>, - move_data: &MoveData<'tcx>, - move_info: GatherMoveInfo<'c, 'tcx>, -) { - debug!("gather_move(move_id={:?}, cmt={:?})", - move_info.id, move_info.cmt); - - let potentially_illegal_move = check_and_get_illegal_move_origin(bccx, move_info.cmt); - if let Some(_) = potentially_illegal_move { - bccx.signal_error(); - return; - } - - match opt_loan_path(&move_info.cmt) { - Some(loan_path) => { - move_data.add_move(bccx.tcx, loan_path, - move_info.id); - } - None => { - // move from rvalue or raw pointer, hence ok - } - } -} - -pub fn gather_assignment<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - move_data: &MoveData<'tcx>, - assignment_id: hir::ItemLocalId, - assignment_span: Span, - assignee_loan_path: Rc>) { - move_data.add_assignment(bccx.tcx, - assignee_loan_path, - assignment_id, - assignment_span); -} - -// (keep in sync with move_error::report_cannot_move_out_of ) -fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - cmt: &mc::cmt_<'tcx>) - -> Option> { - match cmt.cat { - Categorization::Deref(_, mc::BorrowedPtr(..)) | - Categorization::Deref(_, mc::UnsafePtr(..)) | - Categorization::ThreadLocal(..) | - Categorization::StaticItem => { - Some(cmt.clone()) - } - - Categorization::Rvalue(..) | - Categorization::Local(..) | - Categorization::Upvar(..) => { - None - } - - Categorization::Downcast(ref b, _) | - Categorization::Interior(ref b, mc::InteriorField(_)) | - Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern)) => { - match b.ty.sty { - ty::Adt(def, _) => { - if def.has_dtor(bccx.tcx) { - Some(cmt.clone()) - } else { - check_and_get_illegal_move_origin(bccx, b) - } - } - ty::Slice(..) => Some(cmt.clone()), - _ => { - check_and_get_illegal_move_origin(bccx, b) - } - } - } - - Categorization::Interior(_, mc::InteriorElement(Kind::Index)) => { - // Forbid move of arr[i] for arr: [T; 3]; see RFC 533. - Some(cmt.clone()) - } - - Categorization::Deref(ref b, mc::Unique) => { - check_and_get_illegal_move_origin(bccx, b) - } - } -} diff --git a/src/librustc_ast_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_ast_borrowck/borrowck/gather_loans/lifetime.rs deleted file mode 100644 index ff7dd66793d18..0000000000000 --- a/src/librustc_ast_borrowck/borrowck/gather_loans/lifetime.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! This module implements the check that the lifetime of a borrow -//! does not exceed the lifetime of the value being borrowed. - -use crate::borrowck::*; -use rustc::hir::HirId; -use rustc::middle::mem_categorization as mc; -use rustc::middle::mem_categorization::Categorization; -use rustc::middle::region; -use rustc::ty; - -use log::debug; - -type R = Result<(),()>; - -pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - item_scope: region::Scope, - cmt: &'a mc::cmt_<'tcx>, - loan_region: ty::Region<'tcx>) - -> Result<(),()> { - //! Reports error if `loan_region` is larger than S - //! where S is `item_scope` if `cmt` is an upvar, - //! and is scope of `cmt` otherwise. - debug!("guarantee_lifetime(cmt={:?}, loan_region={:?})", - cmt, loan_region); - let ctxt = GuaranteeLifetimeContext { bccx, item_scope, loan_region }; - ctxt.check(cmt, None) -} - -/////////////////////////////////////////////////////////////////////////// -// Private - -struct GuaranteeLifetimeContext<'a, 'tcx> { - bccx: &'a BorrowckCtxt<'a, 'tcx>, - - // the scope of the function body for the enclosing item - item_scope: region::Scope, - - loan_region: ty::Region<'tcx>, -} - -impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { - fn check(&self, cmt: &mc::cmt_<'tcx>, discr_scope: Option) -> R { - //! Main routine. Walks down `cmt` until we find the - //! "guarantor". Reports an error if `self.loan_region` is - //! larger than scope of `cmt`. - debug!("guarantee_lifetime.check(cmt={:?}, loan_region={:?})", - cmt, - self.loan_region); - - match cmt.cat { - Categorization::Rvalue(..) | - Categorization::ThreadLocal(..) | - Categorization::Local(..) | // L-Local - Categorization::Upvar(..) | - Categorization::Deref(_, mc::BorrowedPtr(..)) | // L-Deref-Borrowed - Categorization::Deref(_, mc::UnsafePtr(..)) => { - self.check_scope(self.scope(cmt)) - } - - Categorization::StaticItem => { - Ok(()) - } - - Categorization::Downcast(ref base, _) | - Categorization::Deref(ref base, mc::Unique) | // L-Deref-Send - Categorization::Interior(ref base, _) => { // L-Field - self.check(base, discr_scope) - } - } - } - - fn check_scope(&self, max_scope: ty::Region<'tcx>) -> R { - //! Reports an error if `loan_region` is larger than `max_scope` - - if !self.bccx.is_subregion_of(self.loan_region, max_scope) { - Err(self.bccx.signal_error()) - } else { - Ok(()) - } - } - - fn scope(&self, cmt: &mc::cmt_<'tcx>) -> ty::Region<'tcx> { - //! Returns the maximal region scope for the which the - //! place `cmt` is guaranteed to be valid without any - //! rooting etc, and presuming `cmt` is not mutated. - - match cmt.cat { - Categorization::ThreadLocal(temp_scope) | - Categorization::Rvalue(temp_scope) => { - temp_scope - } - Categorization::Upvar(..) => { - self.bccx.tcx.mk_region(ty::ReScope(self.item_scope)) - } - Categorization::Local(hir_id) => { - self.bccx.tcx.mk_region(ty::ReScope( - self.bccx.region_scope_tree.var_scope(hir_id.local_id))) - } - Categorization::StaticItem | - Categorization::Deref(_, mc::UnsafePtr(..)) => { - self.bccx.tcx.lifetimes.re_static - } - Categorization::Deref(_, mc::BorrowedPtr(_, r)) => { - r - } - Categorization::Downcast(ref cmt, _) | - Categorization::Deref(ref cmt, mc::Unique) | - Categorization::Interior(ref cmt, _) => { - self.scope(cmt) - } - } - } -} diff --git a/src/librustc_ast_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_ast_borrowck/borrowck/gather_loans/mod.rs deleted file mode 100644 index 16fef705ec953..0000000000000 --- a/src/librustc_ast_borrowck/borrowck/gather_loans/mod.rs +++ /dev/null @@ -1,433 +0,0 @@ -// ---------------------------------------------------------------------- -// Gathering loans -// -// The borrow check proceeds in two phases. In phase one, we gather the full -// set of loans that are required at any point. These are sorted according to -// their associated scopes. In phase two, checking loans, we will then make -// sure that all of these loans are honored. - -use crate::borrowck::*; -use crate::borrowck::move_data::MoveData; -use rustc::middle::expr_use_visitor as euv; -use rustc::middle::mem_categorization as mc; -use rustc::middle::mem_categorization::Categorization; -use rustc::middle::region; -use rustc::ty::{self, TyCtxt}; - -use syntax_pos::Span; -use rustc::hir; -use log::debug; - -use restrictions::RestrictionResult; - -mod lifetime; -mod restrictions; -mod gather_moves; - -pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - body: hir::BodyId) - -> (Vec>, move_data::MoveData<'tcx>) { - let def_id = bccx.tcx.hir().body_owner_def_id(body); - let param_env = bccx.tcx.param_env(def_id); - let mut glcx = GatherLoanCtxt { - bccx, - all_loans: Vec::new(), - item_ub: region::Scope { - id: bccx.tcx.hir().body(body).value.hir_id.local_id, - data: region::ScopeData::Node - }, - move_data: MoveData::default(), - }; - - let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id); - euv::ExprUseVisitor::new(&mut glcx, - bccx.tcx, - def_id, - param_env, - &bccx.region_scope_tree, - bccx.tables, - Some(rvalue_promotable_map)) - .consume_body(bccx.body); - - let GatherLoanCtxt { all_loans, move_data, .. } = glcx; - (all_loans, move_data) -} - -struct GatherLoanCtxt<'a, 'tcx> { - bccx: &'a BorrowckCtxt<'a, 'tcx>, - move_data: move_data::MoveData<'tcx>, - all_loans: Vec>, - /// `item_ub` is used as an upper-bound on the lifetime whenever we - /// ask for the scope of an expression categorized as an upvar. - item_ub: region::Scope, -} - -impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { - fn consume(&mut self, - consume_id: hir::HirId, - _consume_span: Span, - cmt: &mc::cmt_<'tcx>, - mode: euv::ConsumeMode) { - debug!("consume(consume_id={}, cmt={:?}, mode={:?})", - consume_id, cmt, mode); - - match mode { - euv::Move(_) => { - gather_moves::gather_move_from_expr( - self.bccx, &self.move_data, - consume_id.local_id, cmt); - } - euv::Copy => { } - } - } - - fn matched_pat(&mut self, - matched_pat: &hir::Pat, - cmt: &mc::cmt_<'tcx>, - mode: euv::MatchMode) { - debug!("matched_pat(matched_pat={:?}, cmt={:?}, mode={:?})", - matched_pat, - cmt, - mode); - } - - fn consume_pat(&mut self, - consume_pat: &hir::Pat, - cmt: &mc::cmt_<'tcx>, - mode: euv::ConsumeMode) { - debug!("consume_pat(consume_pat={:?}, cmt={:?}, mode={:?})", - consume_pat, - cmt, - mode); - - match mode { - euv::Copy => { return; } - euv::Move(_) => { } - } - - gather_moves::gather_move_from_pat( - self.bccx, &self.move_data, - consume_pat, cmt); - } - - fn borrow(&mut self, - borrow_id: hir::HirId, - _: Span, - cmt: &mc::cmt_<'tcx>, - loan_region: ty::Region<'tcx>, - bk: ty::BorrowKind, - loan_cause: euv::LoanCause) - { - debug!("borrow(borrow_id={}, cmt={:?}, loan_region={:?}, \ - bk={:?}, loan_cause={:?})", - borrow_id, cmt, loan_region, - bk, loan_cause); - - self.guarantee_valid(borrow_id.local_id, - cmt, - bk, - loan_region); - } - - fn mutate(&mut self, - assignment_id: hir::HirId, - assignment_span: Span, - assignee_cmt: &mc::cmt_<'tcx>, - _: euv::MutateMode) - { - self.guarantee_assignment_valid(assignment_id, - assignment_span, - assignee_cmt); - } - - fn decl_without_init(&mut self, id: hir::HirId, _span: Span) { - let ty = self.bccx - .tables - .node_type(id); - gather_moves::gather_decl(self.bccx, &self.move_data, id, ty); - } - - fn nested_body(&mut self, body_id: hir::BodyId) { - debug!("nested_body(body_id={:?})", body_id); - // rust-lang/rust#58776: MIR and AST borrow check disagree on where - // certain closure errors are reported. As such migrate borrowck has to - // operate at the level of items, rather than bodies. Check if the - // contained closure had any errors and set `signalled_any_error` if it - // has. - let bccx = self.bccx; - if bccx.tcx.migrate_borrowck() { - if let SignalledError::NoErrorsSeen = bccx.signalled_any_error.get() { - let closure_def_id = bccx.tcx.hir().body_owner_def_id(body_id); - debug!("checking closure: {:?}", closure_def_id); - - bccx.signalled_any_error.set(bccx.tcx.borrowck(closure_def_id).signalled_any_error); - } - } - } -} - -/// Implements the A-* rules in README.md. -fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - cmt: &mc::cmt_<'tcx>, - req_kind: ty::BorrowKind) - -> Result<(),()> { - - let aliasability = cmt.freely_aliasable(); - debug!("check_aliasability aliasability={:?} req_kind={:?}", - aliasability, req_kind); - - match (aliasability, req_kind) { - (mc::Aliasability::NonAliasable, _) => { - /* Uniquely accessible path -- OK for `&` and `&mut` */ - Ok(()) - } - (mc::Aliasability::FreelyAliasable(mc::AliasableStatic), ty::ImmBorrow) => { - // Borrow of an immutable static item. - Ok(()) - } - (mc::Aliasability::FreelyAliasable(mc::AliasableStaticMut), _) => { - // Even touching a static mut is considered unsafe. We assume the - // user knows what they're doing in these cases. - Ok(()) - } - (mc::Aliasability::FreelyAliasable(_), ty::UniqueImmBorrow) | - (mc::Aliasability::FreelyAliasable(_), ty::MutBorrow) => { - bccx.signal_error(); - Err(()) - } - (..) => { - Ok(()) - } - } -} - -/// Implements the M-* rules in README.md. -fn check_mutability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - cmt: &mc::cmt_<'tcx>, - req_kind: ty::BorrowKind) - -> Result<(),()> { - debug!("check_mutability(cmt={:?} req_kind={:?}", cmt, req_kind); - match req_kind { - ty::UniqueImmBorrow | ty::ImmBorrow => { - match cmt.mutbl { - // I am intentionally leaving this here to help - // refactoring if, in the future, we should add new - // kinds of mutability. - mc::McImmutable | mc::McDeclared | mc::McInherited => { - // both imm and mut data can be lent as imm; - // for mutable data, this is a freeze - Ok(()) - } - } - } - - ty::MutBorrow => { - // Only mutable data can be lent as mutable. - if !cmt.mutbl.is_mutable() { - Err(bccx.signal_error()) - } else { - Ok(()) - } - } - } -} - -impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { - pub fn tcx(&self) -> TyCtxt<'tcx> { self.bccx.tcx } - - /// Guarantees that `cmt` is assignable, or reports an error. - fn guarantee_assignment_valid(&mut self, - assignment_id: hir::HirId, - assignment_span: Span, - cmt: &mc::cmt_<'tcx>) { - - let opt_lp = opt_loan_path(cmt); - debug!("guarantee_assignment_valid(assignment_id={}, cmt={:?}) opt_lp={:?}", - assignment_id, cmt, opt_lp); - - if let Categorization::Local(..) = cmt.cat { - // Only re-assignments to locals require it to be - // mutable - this is checked in check_loans. - } else { - // Check that we don't allow assignments to non-mutable data. - if check_mutability(self.bccx, cmt, ty::MutBorrow).is_err() { - return; // reported an error, no sense in reporting more. - } - } - - // Check that we don't allow assignments to aliasable data - if check_aliasability(self.bccx, cmt, ty::MutBorrow).is_err() { - return; // reported an error, no sense in reporting more. - } - - match opt_lp { - Some(lp) => { - gather_moves::gather_assignment(self.bccx, &self.move_data, - assignment_id.local_id, - assignment_span, - lp); - } - None => { - // This can occur with e.g., `*foo() = 5`. In such - // cases, there is no need to check for conflicts - // with moves etc, just ignore. - } - } - } - - /// Guarantees that `addr_of(cmt)` will be valid for the duration of `static_scope_r`, or - /// reports an error. This may entail taking out loans, which will be added to the - /// `req_loan_map`. - fn guarantee_valid(&mut self, - borrow_id: hir::ItemLocalId, - cmt: &mc::cmt_<'tcx>, - req_kind: ty::BorrowKind, - loan_region: ty::Region<'tcx>) { - debug!("guarantee_valid(borrow_id={:?}, cmt={:?}, \ - req_mutbl={:?}, loan_region={:?})", - borrow_id, - cmt, - req_kind, - loan_region); - - // a loan for the empty region can never be dereferenced, so - // it is always safe - if *loan_region == ty::ReEmpty { - return; - } - - // Check that the lifetime of the borrow does not exceed - // the lifetime of the data being borrowed. - if lifetime::guarantee_lifetime(self.bccx, self.item_ub, cmt, loan_region).is_err() { - return; // reported an error, no sense in reporting more. - } - - // Check that we don't allow mutable borrows of non-mutable data. - if check_mutability(self.bccx, cmt, req_kind).is_err() { - return; // reported an error, no sense in reporting more. - } - - // Check that we don't allow mutable borrows of aliasable data. - if check_aliasability(self.bccx, cmt, req_kind).is_err() { - return; // reported an error, no sense in reporting more. - } - - // Compute the restrictions that are required to enforce the - // loan is safe. - let restr = restrictions::compute_restrictions(self.bccx, &cmt, loan_region); - - debug!("guarantee_valid(): restrictions={:?}", restr); - - // Create the loan record (if needed). - let loan = match restr { - RestrictionResult::Safe => { - // No restrictions---no loan record necessary - return; - } - - RestrictionResult::SafeIf(loan_path, restricted_paths) => { - let loan_scope = match *loan_region { - ty::ReScope(scope) => scope, - - ty::ReEarlyBound(ref br) => { - self.bccx.region_scope_tree.early_free_scope(self.tcx(), br) - } - - ty::ReFree(ref fr) => { - self.bccx.region_scope_tree.free_scope(self.tcx(), fr) - } - - ty::ReStatic => self.item_ub, - - ty::ReEmpty | - ty::ReClosureBound(..) | - ty::ReLateBound(..) | - ty::ReVar(..) | - ty::RePlaceholder(..) | - ty::ReErased => { - span_bug!( - cmt.span, - "invalid borrow lifetime: {:?}", - loan_region); - } - }; - debug!("loan_scope = {:?}", loan_scope); - - let borrow_scope = region::Scope { - id: borrow_id, - data: region::ScopeData::Node - }; - let gen_scope = self.compute_gen_scope(borrow_scope, loan_scope); - debug!("gen_scope = {:?}", gen_scope); - - let kill_scope = self.compute_kill_scope(loan_scope, &loan_path); - debug!("kill_scope = {:?}", kill_scope); - - Loan { - index: self.all_loans.len(), - loan_path, - kind: req_kind, - gen_scope, - kill_scope, - restricted_paths, - } - } - }; - - debug!("guarantee_valid(borrow_id={:?}), loan={:?}", - borrow_id, loan); - - // let loan_path = loan.loan_path; - // let loan_gen_scope = loan.gen_scope; - // let loan_kill_scope = loan.kill_scope; - self.all_loans.push(loan); - } - - pub fn compute_gen_scope(&self, - borrow_scope: region::Scope, - loan_scope: region::Scope) - -> region::Scope { - //! Determine when to introduce the loan. Typically the loan - //! is introduced at the point of the borrow, but in some cases, - //! notably method arguments, the loan may be introduced only - //! later, once it comes into scope. - - if self.bccx.region_scope_tree.is_subscope_of(borrow_scope, loan_scope) { - borrow_scope - } else { - loan_scope - } - } - - pub fn compute_kill_scope(&self, loan_scope: region::Scope, lp: &LoanPath<'tcx>) - -> region::Scope { - //! Determine when the loan restrictions go out of scope. - //! This is either when the lifetime expires or when the - //! local variable which roots the loan-path goes out of scope, - //! whichever happens faster. - //! - //! It may seem surprising that we might have a loan region - //! larger than the variable which roots the loan-path; this can - //! come about when variables of `&mut` type are re-borrowed, - //! as in this example: - //! - //! struct Foo { counter: u32 } - //! - //! fn counter<'a>(v: &'a mut Foo) -> &'a mut u32 { - //! &mut v.counter - //! } - //! - //! In this case, the reference (`'a`) outlives the - //! variable `v` that hosts it. Note that this doesn't come up - //! with immutable `&` pointers, because borrows of such pointers - //! do not require restrictions and hence do not cause a loan. - - let lexical_scope = lp.kill_scope(self.bccx); - if self.bccx.region_scope_tree.is_subscope_of(lexical_scope, loan_scope) { - lexical_scope - } else { - assert!(self.bccx.region_scope_tree.is_subscope_of(loan_scope, lexical_scope)); - loan_scope - } - } -} diff --git a/src/librustc_ast_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_ast_borrowck/borrowck/gather_loans/restrictions.rs deleted file mode 100644 index 545c27b17bd58..0000000000000 --- a/src/librustc_ast_borrowck/borrowck/gather_loans/restrictions.rs +++ /dev/null @@ -1,179 +0,0 @@ -//! Computes the restrictions that result from a borrow. - -use crate::borrowck::*; -use rustc::middle::mem_categorization as mc; -use rustc::middle::mem_categorization::Categorization; -use rustc::ty; -use log::debug; - -use crate::borrowck::ToInteriorKind; - -use std::rc::Rc; - -#[derive(Debug)] -pub enum RestrictionResult<'tcx> { - Safe, - SafeIf(Rc>, Vec>>) -} - -pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - cmt: &mc::cmt_<'tcx>, - loan_region: ty::Region<'tcx>) - -> RestrictionResult<'tcx> { - let ctxt = RestrictionsContext { bccx, loan_region }; - - ctxt.restrict(cmt) -} - -/////////////////////////////////////////////////////////////////////////// -// Private - -struct RestrictionsContext<'a, 'tcx> { - bccx: &'a BorrowckCtxt<'a, 'tcx>, - loan_region: ty::Region<'tcx>, -} - -impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { - fn restrict(&self, - cmt: &mc::cmt_<'tcx>) -> RestrictionResult<'tcx> { - debug!("restrict(cmt={:?})", cmt); - - let new_lp = |v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty)); - - match cmt.cat.clone() { - Categorization::Rvalue(..) => { - // Effectively, rvalues are stored into a - // non-aliasable temporary on the stack. Since they - // are inherently non-aliasable, they can only be - // accessed later through the borrow itself and hence - // must inherently comply with its terms. - RestrictionResult::Safe - } - - Categorization::ThreadLocal(..) => { - // Thread-locals are statics that have a scope, with - // no underlying structure to provide restrictions. - RestrictionResult::Safe - } - - Categorization::Local(local_id) => { - // R-Variable, locally declared - let lp = new_lp(LpVar(local_id)); - RestrictionResult::SafeIf(lp.clone(), vec![lp]) - } - - Categorization::Upvar(mc::Upvar { id, .. }) => { - // R-Variable, captured into closure - let lp = new_lp(LpUpvar(id)); - RestrictionResult::SafeIf(lp.clone(), vec![lp]) - } - - Categorization::Downcast(cmt_base, _) => { - // When we borrow the interior of an enum, we have to - // ensure the enum itself is not mutated, because that - // could cause the type of the memory to change. - self.restrict(&cmt_base) - } - - Categorization::Interior(cmt_base, interior) => { - // R-Field - // - // Overwriting the base would not change the type of - // the memory, so no additional restrictions are - // needed. - let opt_variant_id = match cmt_base.cat { - Categorization::Downcast(_, variant_id) => Some(variant_id), - _ => None - }; - let interior = interior.cleaned(); - let base_ty = cmt_base.ty; - let result = self.restrict(&cmt_base); - // Borrowing one union field automatically borrows all its fields. - match base_ty.sty { - ty::Adt(adt_def, _) if adt_def.is_union() => match result { - RestrictionResult::Safe => RestrictionResult::Safe, - RestrictionResult::SafeIf(base_lp, mut base_vec) => { - for (i, field) in adt_def.non_enum_variant().fields.iter().enumerate() { - let field = InteriorKind::InteriorField( - mc::FieldIndex(i, field.ident.name) - ); - let field_ty = if field == interior { - cmt.ty - } else { - self.bccx.tcx.types.err // Doesn't matter - }; - let sibling_lp_kind = LpExtend(base_lp.clone(), cmt.mutbl, - LpInterior(opt_variant_id, field)); - let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty)); - base_vec.push(sibling_lp); - } - - let lp = new_lp(LpExtend(base_lp, cmt.mutbl, - LpInterior(opt_variant_id, interior))); - RestrictionResult::SafeIf(lp, base_vec) - } - }, - _ => self.extend(result, &cmt, LpInterior(opt_variant_id, interior)) - } - } - - Categorization::StaticItem => { - RestrictionResult::Safe - } - - Categorization::Deref(cmt_base, pk) => { - match pk { - mc::Unique => { - // R-Deref-Send-Pointer - // - // When we borrow the interior of a box, we - // cannot permit the base to be mutated, because that - // would cause the unique pointer to be freed. - // - // Eventually we should make these non-special and - // just rely on Deref implementation. - let result = self.restrict(&cmt_base); - self.extend(result, &cmt, LpDeref(pk)) - } - mc::BorrowedPtr(bk, lt) => { - // R-Deref-[Mut-]Borrowed - if !self.bccx.is_subregion_of(self.loan_region, lt) { - self.bccx.signal_error(); - return RestrictionResult::Safe; - } - - match bk { - ty::ImmBorrow => RestrictionResult::Safe, - ty::MutBorrow | ty::UniqueImmBorrow => { - // R-Deref-Mut-Borrowed - // - // The referent can be aliased after the - // references lifetime ends (by a newly-unfrozen - // borrow). - let result = self.restrict(&cmt_base); - self.extend(result, &cmt, LpDeref(pk)) - } - } - } - // Borrowck is not relevant for raw pointers - mc::UnsafePtr(..) => RestrictionResult::Safe - } - } - } - } - - fn extend(&self, - result: RestrictionResult<'tcx>, - cmt: &mc::cmt_<'tcx>, - elem: LoanPathElem<'tcx>) -> RestrictionResult<'tcx> { - match result { - RestrictionResult::Safe => RestrictionResult::Safe, - RestrictionResult::SafeIf(base_lp, mut base_vec) => { - let v = LpExtend(base_lp, cmt.mutbl, elem); - let lp = Rc::new(LoanPath::new(v, cmt.ty)); - base_vec.push(lp.clone()); - RestrictionResult::SafeIf(lp, base_vec) - } - } - } -} diff --git a/src/librustc_ast_borrowck/borrowck/mod.rs b/src/librustc_ast_borrowck/borrowck/mod.rs deleted file mode 100644 index 3bbd7ae5c352f..0000000000000 --- a/src/librustc_ast_borrowck/borrowck/mod.rs +++ /dev/null @@ -1,621 +0,0 @@ -//! See The Book chapter on the borrow checker for more details. - -#![allow(non_camel_case_types)] - -pub use LoanPathKind::*; -pub use LoanPathElem::*; - -use InteriorKind::*; - -use rustc::hir::HirId; -use rustc::hir::Node; -use rustc::cfg; -use rustc::middle::borrowck::{BorrowCheckResult, SignalledError}; -use rustc::hir::def_id::{DefId, LocalDefId}; -use rustc::middle::mem_categorization as mc; -use rustc::middle::mem_categorization::Categorization; -use rustc::middle::region; -use rustc::middle::free_region::RegionRelations; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::query::Providers; - -use std::borrow::Cow; -use std::cell::{Cell}; -use std::fmt; -use std::rc::Rc; -use std::hash::{Hash, Hasher}; -use log::debug; - -use rustc::hir; - -use crate::dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom}; - -pub mod check_loans; - -pub mod gather_loans; - -pub mod move_data; - -#[derive(Clone, Copy)] -pub struct LoanDataFlowOperator; - -pub type LoanDataFlow<'tcx> = DataFlowContext<'tcx, LoanDataFlowOperator>; - -pub fn check_crate(tcx: TyCtxt<'_>) { - tcx.par_body_owners(|body_owner_def_id| { - tcx.ensure().borrowck(body_owner_def_id); - }); -} - -pub fn provide(providers: &mut Providers<'_>) { - *providers = Providers { - borrowck, - ..*providers - }; -} - -/// Collection of conclusions determined via borrow checker analyses. -pub struct AnalysisData<'tcx> { - pub all_loans: Vec>, - pub loans: DataFlowContext<'tcx, LoanDataFlowOperator>, - pub move_data: move_data::FlowedMoveData<'tcx>, -} - -fn borrowck(tcx: TyCtxt<'_>, owner_def_id: DefId) -> &BorrowCheckResult { - assert!(tcx.use_ast_borrowck() || tcx.migrate_borrowck()); - - debug!("borrowck(body_owner_def_id={:?})", owner_def_id); - - let signalled_error = tcx.check_match(owner_def_id); - if let SignalledError::SawSomeError = signalled_error { - return tcx.arena.alloc(BorrowCheckResult { - signalled_any_error: SignalledError::SawSomeError, - }) - } - - let owner_id = tcx.hir().as_local_hir_id(owner_def_id).unwrap(); - - match tcx.hir().get(owner_id) { - Node::Ctor(..) => { - // We get invoked with anything that has MIR, but some of - // those things (notably the synthesized constructors from - // tuple structs/variants) do not have an associated body - // and do not need borrowchecking. - return tcx.arena.alloc(BorrowCheckResult { - signalled_any_error: SignalledError::NoErrorsSeen, - }) - } - _ => { } - } - - let body_id = tcx.hir().body_owned_by(owner_id); - let tables = tcx.typeck_tables_of(owner_def_id); - let region_scope_tree = tcx.region_scope_tree(owner_def_id); - let body = tcx.hir().body(body_id); - let mut bccx = BorrowckCtxt { - tcx, - tables, - region_scope_tree, - owner_def_id, - body, - signalled_any_error: Cell::new(SignalledError::NoErrorsSeen), - }; - - // Eventually, borrowck will always read the MIR, but at the - // moment we do not. So, for now, we always force MIR to be - // constructed for a given fn, since this may result in errors - // being reported and we want that to happen. - // - // Note that `mir_validated` is a "stealable" result; the - // thief, `optimized_mir()`, forces borrowck, so we know that - // is not yet stolen. - tcx.ensure().mir_validated(owner_def_id); - - // option dance because you can't capture an uninitialized variable - // by mut-ref. - let mut cfg = None; - if let Some(AnalysisData { all_loans, - loans: loan_dfcx, - move_data: flowed_moves }) = - build_borrowck_dataflow_data(&mut bccx, false, body_id, - |bccx| { - cfg = Some(cfg::CFG::new(bccx.tcx, &body)); - cfg.as_mut().unwrap() - }) - { - check_loans::check_loans(&mut bccx, &loan_dfcx, &flowed_moves, &all_loans, body); - } - - tcx.arena.alloc(BorrowCheckResult { - signalled_any_error: bccx.signalled_any_error.into_inner(), - }) -} - -fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>(this: &mut BorrowckCtxt<'a, 'tcx>, - force_analysis: bool, - body_id: hir::BodyId, - get_cfg: F) - -> Option> - where F: FnOnce(&mut BorrowckCtxt<'a, 'tcx>) -> &'c cfg::CFG -{ - // Check the body of fn items. - let (all_loans, move_data) = - gather_loans::gather_loans_in_fn(this, body_id); - - if !force_analysis && move_data.is_empty() && all_loans.is_empty() { - // large arrays of data inserted as constants can take a lot of - // time and memory to borrow-check - see issue #36799. However, - // they don't have places, so no borrow-check is actually needed. - // Recognize that case and skip borrow-checking. - debug!("skipping loan propagation for {:?} because of no loans", body_id); - return None; - } else { - debug!("propagating loans in {:?}", body_id); - } - - let cfg = get_cfg(this); - let mut loan_dfcx = - DataFlowContext::new(this.tcx, - "borrowck", - Some(this.body), - cfg, - LoanDataFlowOperator, - all_loans.len()); - for (loan_idx, loan) in all_loans.iter().enumerate() { - loan_dfcx.add_gen(loan.gen_scope.item_local_id(), loan_idx); - loan_dfcx.add_kill(KillFrom::ScopeEnd, - loan.kill_scope.item_local_id(), - loan_idx); - } - loan_dfcx.add_kills_from_flow_exits(cfg); - loan_dfcx.propagate(cfg, this.body); - - let flowed_moves = move_data::FlowedMoveData::new(move_data, - this, - cfg, - this.body); - - Some(AnalysisData { all_loans, - loans: loan_dfcx, - move_data:flowed_moves }) -} - -/// Accessor for introspective clients inspecting `AnalysisData` and -/// the `BorrowckCtxt` itself , e.g., the flowgraph visualizer. -pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( - tcx: TyCtxt<'tcx>, - body_id: hir::BodyId, - cfg: &cfg::CFG) - -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'tcx>) -{ - let owner_id = tcx.hir().body_owner(body_id); - let owner_def_id = tcx.hir().local_def_id(owner_id); - let tables = tcx.typeck_tables_of(owner_def_id); - let region_scope_tree = tcx.region_scope_tree(owner_def_id); - let body = tcx.hir().body(body_id); - let mut bccx = BorrowckCtxt { - tcx, - tables, - region_scope_tree, - owner_def_id, - body, - signalled_any_error: Cell::new(SignalledError::NoErrorsSeen), - }; - - let dataflow_data = build_borrowck_dataflow_data(&mut bccx, true, body_id, |_| cfg); - (bccx, dataflow_data.unwrap()) -} - -// ---------------------------------------------------------------------- -// Type definitions - -pub struct BorrowckCtxt<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - - // tables for the current thing we are checking; set to - // Some in `borrowck_fn` and cleared later - tables: &'a ty::TypeckTables<'tcx>, - - region_scope_tree: &'tcx region::ScopeTree, - - owner_def_id: DefId, - - body: &'tcx hir::Body, - - signalled_any_error: Cell, -} - - -impl<'a, 'tcx: 'a> BorrowckCtxt<'a, 'tcx> { - fn signal_error(&self) { - self.signalled_any_error.set(SignalledError::SawSomeError); - } -} - -/////////////////////////////////////////////////////////////////////////// -// Loans and loan paths - -/// Record of a loan that was issued. -pub struct Loan<'tcx> { - index: usize, - loan_path: Rc>, - kind: ty::BorrowKind, - restricted_paths: Vec>>, - - /// gen_scope indicates where loan is introduced. Typically the - /// loan is introduced at the point of the borrow, but in some - /// cases, notably method arguments, the loan may be introduced - /// only later, once it comes into scope. See also - /// `GatherLoanCtxt::compute_gen_scope`. - gen_scope: region::Scope, - - /// kill_scope indicates when the loan goes out of scope. This is - /// either when the lifetime expires or when the local variable - /// which roots the loan-path goes out of scope, whichever happens - /// faster. See also `GatherLoanCtxt::compute_kill_scope`. - kill_scope: region::Scope, -} - -impl<'tcx> Loan<'tcx> { - pub fn loan_path(&self) -> Rc> { - self.loan_path.clone() - } -} - -#[derive(Eq)] -pub struct LoanPath<'tcx> { - kind: LoanPathKind<'tcx>, - ty: Ty<'tcx>, -} - -impl<'tcx> PartialEq for LoanPath<'tcx> { - fn eq(&self, that: &LoanPath<'tcx>) -> bool { - self.kind == that.kind - } -} - -impl<'tcx> Hash for LoanPath<'tcx> { - fn hash(&self, state: &mut H) { - self.kind.hash(state); - } -} - -#[derive(PartialEq, Eq, Hash, Debug)] -pub enum LoanPathKind<'tcx> { - LpVar(hir::HirId), // `x` in README.md - LpUpvar(ty::UpvarId), // `x` captured by-value into closure - LpDowncast(Rc>, DefId), // `x` downcast to particular enum variant - LpExtend(Rc>, mc::MutabilityCategory, LoanPathElem<'tcx>) -} - -impl<'tcx> LoanPath<'tcx> { - fn new(kind: LoanPathKind<'tcx>, ty: Ty<'tcx>) -> LoanPath<'tcx> { - LoanPath { kind: kind, ty: ty } - } - - fn to_type(&self) -> Ty<'tcx> { self.ty } -} - -// FIXME (pnkfelix): See discussion here -// https://github.com/pnkfelix/rust/commit/ -// b2b39e8700e37ad32b486b9a8409b50a8a53aa51#commitcomment-7892003 -const DOWNCAST_PRINTED_OPERATOR: &'static str = " as "; - -// A local, "cleaned" version of `mc::InteriorKind` that drops -// information that is not relevant to loan-path analysis. (In -// particular, the distinction between how precisely an array-element -// is tracked is irrelevant here.) -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub enum InteriorKind { - InteriorField(mc::FieldIndex), - InteriorElement, -} - -trait ToInteriorKind { fn cleaned(self) -> InteriorKind; } -impl ToInteriorKind for mc::InteriorKind { - fn cleaned(self) -> InteriorKind { - match self { - mc::InteriorField(name) => InteriorField(name), - mc::InteriorElement(_) => InteriorElement, - } - } -} - -// This can be: -// - a pointer dereference (`*P` in README.md) -// - a field reference, with an optional definition of the containing -// enum variant (`P.f` in README.md) -// `DefId` is present when the field is part of struct that is in -// a variant of an enum. For instance in: -// `enum E { X { foo: u32 }, Y { foo: u32 }}` -// each `foo` is qualified by the definitition id of the variant (`X` or `Y`). -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum LoanPathElem<'tcx> { - LpDeref(mc::PointerKind<'tcx>), - LpInterior(Option, InteriorKind), -} - -fn closure_to_block(closure_id: LocalDefId, tcx: TyCtxt<'_>) -> HirId { - let closure_id = tcx.hir().local_def_id_to_hir_id(closure_id); - match tcx.hir().get(closure_id) { - Node::Expr(expr) => match expr.node { - hir::ExprKind::Closure(.., body_id, _, _) => { - body_id.hir_id - } - _ => { - bug!("encountered non-closure id: {}", closure_id) - } - }, - _ => bug!("encountered non-expr id: {}", closure_id) - } -} - -impl<'a, 'tcx> LoanPath<'tcx> { - pub fn kill_scope(&self, bccx: &BorrowckCtxt<'a, 'tcx>) -> region::Scope { - match self.kind { - LpVar(hir_id) => { - bccx.region_scope_tree.var_scope(hir_id.local_id) - } - LpUpvar(upvar_id) => { - let block_id = closure_to_block(upvar_id.closure_expr_id, bccx.tcx); - region::Scope { id: block_id.local_id, data: region::ScopeData::Node } - } - LpDowncast(ref base, _) | - LpExtend(ref base, ..) => base.kill_scope(bccx), - } - } -} - -// Avoid "cannot borrow immutable field `self.x` as mutable" as that implies that a field *can* be -// mutable independently of the struct it belongs to. (#35937) -pub fn opt_loan_path_is_field<'tcx>(cmt: &mc::cmt_<'tcx>) -> (Option>>, bool) { - let new_lp = |v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty)); - - match cmt.cat { - Categorization::Rvalue(..) | - Categorization::ThreadLocal(..) | - Categorization::StaticItem => { - (None, false) - } - - Categorization::Local(id) => { - (Some(new_lp(LpVar(id))), false) - } - - Categorization::Upvar(mc::Upvar { id, .. }) => { - (Some(new_lp(LpUpvar(id))), false) - } - - Categorization::Deref(ref cmt_base, pk) => { - let lp = opt_loan_path_is_field(cmt_base); - (lp.0.map(|lp| { - new_lp(LpExtend(lp, cmt.mutbl, LpDeref(pk))) - }), lp.1) - } - - Categorization::Interior(ref cmt_base, ik) => { - (opt_loan_path(cmt_base).map(|lp| { - let opt_variant_id = match cmt_base.cat { - Categorization::Downcast(_, did) => Some(did), - _ => None - }; - new_lp(LpExtend(lp, cmt.mutbl, LpInterior(opt_variant_id, ik.cleaned()))) - }), true) - } - - Categorization::Downcast(ref cmt_base, variant_def_id) => { - let lp = opt_loan_path_is_field(cmt_base); - (lp.0.map(|lp| { - new_lp(LpDowncast(lp, variant_def_id)) - }), lp.1) - } - } -} - -/// Computes the `LoanPath` (if any) for a `cmt`. -/// Note that this logic is somewhat duplicated in -/// the method `compute()` found in `gather_loans::restrictions`, -/// which allows it to share common loan path pieces as it -/// traverses the CMT. -pub fn opt_loan_path<'tcx>(cmt: &mc::cmt_<'tcx>) -> Option>> { - opt_loan_path_is_field(cmt).0 -} - -/////////////////////////////////////////////////////////////////////////// -// Misc - -impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { - pub fn is_subregion_of(&self, - r_sub: ty::Region<'tcx>, - r_sup: ty::Region<'tcx>) - -> bool - { - let region_rels = RegionRelations::new(self.tcx, - self.owner_def_id, - &self.region_scope_tree, - &self.tables.free_region_map); - region_rels.is_subregion_of(r_sub, r_sup) - } - - pub fn append_loan_path_to_string(&self, - loan_path: &LoanPath<'tcx>, - out: &mut String) { - match loan_path.kind { - LpUpvar(ty::UpvarId { var_path: ty::UpvarPath { hir_id: id }, closure_expr_id: _ }) => { - out.push_str(&self.tcx.hir().name(id).as_str()); - } - LpVar(id) => { - out.push_str(&self.tcx.hir().name(id).as_str()); - } - - LpDowncast(ref lp_base, variant_def_id) => { - out.push('('); - self.append_loan_path_to_string(&lp_base, out); - out.push_str(DOWNCAST_PRINTED_OPERATOR); - out.push_str(&self.tcx.def_path_str(variant_def_id)); - out.push(')'); - } - - LpExtend(ref lp_base, _, LpInterior(_, InteriorField(mc::FieldIndex(_, info)))) => { - self.append_autoderefd_loan_path_to_string(&lp_base, out); - out.push('.'); - out.push_str(&info.as_str()); - } - - LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) => { - self.append_autoderefd_loan_path_to_string(&lp_base, out); - out.push_str("[..]"); - } - - LpExtend(ref lp_base, _, LpDeref(_)) => { - out.push('*'); - self.append_loan_path_to_string(&lp_base, out); - } - } - } - - pub fn append_autoderefd_loan_path_to_string(&self, - loan_path: &LoanPath<'tcx>, - out: &mut String) { - match loan_path.kind { - LpExtend(ref lp_base, _, LpDeref(_)) => { - // For a path like `(*x).f` or `(*x)[3]`, autoderef - // rules would normally allow users to omit the `*x`. - // So just serialize such paths to `x.f` or x[3]` respectively. - self.append_autoderefd_loan_path_to_string(&lp_base, out) - } - - LpDowncast(ref lp_base, variant_def_id) => { - out.push('('); - self.append_autoderefd_loan_path_to_string(&lp_base, out); - out.push_str(DOWNCAST_PRINTED_OPERATOR); - out.push_str(&self.tcx.def_path_str(variant_def_id)); - out.push(')'); - } - - LpVar(..) | LpUpvar(..) | LpExtend(.., LpInterior(..)) => { - self.append_loan_path_to_string(loan_path, out) - } - } - } - - pub fn loan_path_to_string(&self, loan_path: &LoanPath<'tcx>) -> String { - let mut result = String::new(); - self.append_loan_path_to_string(loan_path, &mut result); - result - } - - pub fn cmt_to_cow_str(&self, cmt: &mc::cmt_<'tcx>) -> Cow<'static, str> { - cmt.descriptive_string(self.tcx) - } - - pub fn cmt_to_path_or_string(&self, cmt: &mc::cmt_<'tcx>) -> String { - match opt_loan_path(cmt) { - Some(lp) => format!("`{}`", self.loan_path_to_string(&lp)), - None => self.cmt_to_cow_str(cmt).into_owned(), - } - } -} - -impl BitwiseOperator for LoanDataFlowOperator { - #[inline] - fn join(&self, succ: usize, pred: usize) -> usize { - succ | pred // loans from both preds are in scope - } -} - -impl DataFlowOperator for LoanDataFlowOperator { - #[inline] - fn initial_value(&self) -> bool { - false // no loans in scope by default - } -} - -impl fmt::Debug for InteriorKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - InteriorField(mc::FieldIndex(_, info)) => write!(f, "{}", info), - InteriorElement => write!(f, "[]"), - } - } -} - -impl<'tcx> fmt::Debug for Loan<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Loan_{}({:?}, {:?}, {:?}-{:?}, {:?})", - self.index, - self.loan_path, - self.kind, - self.gen_scope, - self.kill_scope, - self.restricted_paths) - } -} - -impl<'tcx> fmt::Debug for LoanPath<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.kind { - LpVar(id) => { - write!(f, "$({})", ty::tls::with(|tcx| tcx.hir().node_to_string(id))) - } - - LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath {hir_id: var_id}, closure_expr_id }) => { - let s = ty::tls::with(|tcx| { - tcx.hir().node_to_string(var_id) - }); - write!(f, "$({} captured by id={:?})", s, closure_expr_id) - } - - LpDowncast(ref lp, variant_def_id) => { - let variant_str = if variant_def_id.is_local() { - ty::tls::with(|tcx| tcx.def_path_str(variant_def_id)) - } else { - format!("{:?}", variant_def_id) - }; - write!(f, "({:?}{}{})", lp, DOWNCAST_PRINTED_OPERATOR, variant_str) - } - - LpExtend(ref lp, _, LpDeref(_)) => { - write!(f, "{:?}.*", lp) - } - - LpExtend(ref lp, _, LpInterior(_, ref interior)) => { - write!(f, "{:?}.{:?}", lp, interior) - } - } - } -} - -impl<'tcx> fmt::Display for LoanPath<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.kind { - LpVar(id) => { - write!(f, "$({})", ty::tls::with(|tcx| tcx.hir().hir_to_user_string(id))) - } - - LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath { hir_id }, closure_expr_id: _ }) => { - let s = ty::tls::with(|tcx| { - tcx.hir().node_to_string(hir_id) - }); - write!(f, "$({} captured by closure)", s) - } - - LpDowncast(ref lp, variant_def_id) => { - let variant_str = if variant_def_id.is_local() { - ty::tls::with(|tcx| tcx.def_path_str(variant_def_id)) - } else { - format!("{:?}", variant_def_id) - }; - write!(f, "({}{}{})", lp, DOWNCAST_PRINTED_OPERATOR, variant_str) - } - - LpExtend(ref lp, _, LpDeref(_)) => { - write!(f, "{}.*", lp) - } - - LpExtend(ref lp, _, LpInterior(_, ref interior)) => { - write!(f, "{}.{:?}", lp, interior) - } - } - } -} diff --git a/src/librustc_ast_borrowck/borrowck/move_data.rs b/src/librustc_ast_borrowck/borrowck/move_data.rs deleted file mode 100644 index 887a0e2f20e16..0000000000000 --- a/src/librustc_ast_borrowck/borrowck/move_data.rs +++ /dev/null @@ -1,730 +0,0 @@ -//! Data structures used for tracking moves. Please see the extensive -//! comments in the section "Moves and initialization" in `README.md`. - -use crate::dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom}; - -use crate::borrowck::*; -use rustc::cfg; -use rustc::ty::{self, TyCtxt}; -use rustc::util::nodemap::FxHashMap; - -use std::cell::RefCell; -use std::rc::Rc; -use std::usize; -use syntax_pos::Span; -use rustc::hir; -use log::debug; - -#[derive(Default)] -pub struct MoveData<'tcx> { - /// Move paths. See section "Move paths" in `README.md`. - pub paths: RefCell>>, - - /// Cache of loan path to move path index, for easy lookup. - pub path_map: RefCell>, MovePathIndex>>, - - /// Each move or uninitialized variable gets an entry here. - pub moves: RefCell>, - - /// Assignments to a variable, like `x = foo`. These are assigned - /// bits for dataflow, since we must track them to ensure that - /// immutable variables are assigned at most once along each path. - pub var_assignments: RefCell>, - - /// Assignments to a path, like `x.f = foo`. These are not - /// assigned dataflow bits, but we track them because they still - /// kill move bits. - pub path_assignments: RefCell>, -} - -pub struct FlowedMoveData<'tcx> { - pub move_data: MoveData<'tcx>, - - pub dfcx_moves: MoveDataFlow<'tcx>, - - // We could (and maybe should, for efficiency) combine both move - // and assign data flow into one, but this way it's easier to - // distinguish the bits that correspond to moves and assignments. - pub dfcx_assign: AssignDataFlow<'tcx>, -} - -/// Index into `MoveData.paths`, used like a pointer -#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub struct MovePathIndex(usize); - -impl MovePathIndex { - fn get(&self) -> usize { - let MovePathIndex(v) = *self; v - } -} - -impl Clone for MovePathIndex { - fn clone(&self) -> MovePathIndex { - MovePathIndex(self.get()) - } -} - -#[allow(non_upper_case_globals)] -const InvalidMovePathIndex: MovePathIndex = MovePathIndex(usize::MAX); - -/// Index into `MoveData.moves`, used like a pointer -#[derive(Copy, Clone, PartialEq)] -pub struct MoveIndex(usize); - -impl MoveIndex { - fn get(&self) -> usize { - let MoveIndex(v) = *self; v - } -} - -#[allow(non_upper_case_globals)] -const InvalidMoveIndex: MoveIndex = MoveIndex(usize::MAX); - -pub struct MovePath<'tcx> { - /// Loan path corresponding to this move path - pub loan_path: Rc>, - - /// Parent pointer, `InvalidMovePathIndex` if root - pub parent: MovePathIndex, - - /// Head of linked list of moves to this path, - /// `InvalidMoveIndex` if not moved - pub first_move: MoveIndex, - - /// First node in linked list of children, `InvalidMovePathIndex` if leaf - pub first_child: MovePathIndex, - - /// Next node in linked list of parent's children (siblings), - /// `InvalidMovePathIndex` if none. - pub next_sibling: MovePathIndex, -} - - -#[derive(Copy, Clone)] -pub struct Move { - /// Path being moved. - pub path: MovePathIndex, - - /// ID of node that is doing the move. - pub id: hir::ItemLocalId, - - /// Next node in linked list of moves from `path`, or `InvalidMoveIndex` - pub next_move: MoveIndex -} - -#[derive(Copy, Clone)] -pub struct Assignment { - /// Path being assigned. - pub path: MovePathIndex, - - /// ID where assignment occurs - pub id: hir::ItemLocalId, - - /// span of node where assignment occurs - pub span: Span, -} - -#[derive(Clone, Copy)] -pub struct MoveDataFlowOperator; - -pub type MoveDataFlow<'tcx> = DataFlowContext<'tcx, MoveDataFlowOperator>; - -#[derive(Clone, Copy)] -pub struct AssignDataFlowOperator; - -pub type AssignDataFlow<'tcx> = DataFlowContext<'tcx, AssignDataFlowOperator>; - -fn loan_path_is_precise(loan_path: &LoanPath<'_>) -> bool { - match loan_path.kind { - LpVar(_) | LpUpvar(_) => { - true - } - LpExtend(.., LpInterior(_, InteriorKind::InteriorElement)) => { - // Paths involving element accesses a[i] do not refer to a unique - // location, as there is no accurate tracking of the indices. - // - // (Paths involving element accesses via slice pattern bindings - // can in principle be tracked precisely, but that is future - // work. For now, continue claiming that they are imprecise.) - false - } - LpDowncast(ref lp_base, _) | - LpExtend(ref lp_base, ..) => { - loan_path_is_precise(&lp_base) - } - } -} - -impl MoveData<'tcx> { - /// Returns `true` if there are no trackable assignments or moves - /// in this move data -- that means that there is nothing that - /// could cause a borrow error. - pub fn is_empty(&self) -> bool { - self.moves.borrow().is_empty() && - self.path_assignments.borrow().is_empty() && - self.var_assignments.borrow().is_empty() - } - - pub fn path_loan_path(&self, index: MovePathIndex) -> Rc> { - (*self.paths.borrow())[index.get()].loan_path.clone() - } - - fn path_parent(&self, index: MovePathIndex) -> MovePathIndex { - (*self.paths.borrow())[index.get()].parent - } - - fn path_first_move(&self, index: MovePathIndex) -> MoveIndex { - (*self.paths.borrow())[index.get()].first_move - } - - /// Returns the index of first child, or `InvalidMovePathIndex` if - /// `index` is leaf. - fn path_first_child(&self, index: MovePathIndex) -> MovePathIndex { - (*self.paths.borrow())[index.get()].first_child - } - - fn path_next_sibling(&self, index: MovePathIndex) -> MovePathIndex { - (*self.paths.borrow())[index.get()].next_sibling - } - - fn set_path_first_move(&self, - index: MovePathIndex, - first_move: MoveIndex) { - (*self.paths.borrow_mut())[index.get()].first_move = first_move - } - - fn set_path_first_child(&self, - index: MovePathIndex, - first_child: MovePathIndex) { - (*self.paths.borrow_mut())[index.get()].first_child = first_child - } - - fn move_next_move(&self, index: MoveIndex) -> MoveIndex { - //! Type safe indexing operator - (*self.moves.borrow())[index.get()].next_move - } - - fn is_var_path(&self, index: MovePathIndex) -> bool { - //! True if `index` refers to a variable - self.path_parent(index) == InvalidMovePathIndex - } - - /// Returns the existing move path index for `lp`, if any, and otherwise adds a new index for - /// `lp` and any of its base paths that do not yet have an index. - pub fn move_path(&self, tcx: TyCtxt<'tcx>, lp: Rc>) -> MovePathIndex { - if let Some(&index) = self.path_map.borrow().get(&lp) { - return index; - } - - let index = match lp.kind { - LpVar(..) | LpUpvar(..) => { - let index = MovePathIndex(self.paths.borrow().len()); - - self.paths.borrow_mut().push(MovePath { - loan_path: lp.clone(), - parent: InvalidMovePathIndex, - first_move: InvalidMoveIndex, - first_child: InvalidMovePathIndex, - next_sibling: InvalidMovePathIndex, - }); - - index - } - - LpDowncast(ref base, _) | - LpExtend(ref base, ..) => { - let parent_index = self.move_path(tcx, base.clone()); - - let index = MovePathIndex(self.paths.borrow().len()); - - let next_sibling = self.path_first_child(parent_index); - self.set_path_first_child(parent_index, index); - - self.paths.borrow_mut().push(MovePath { - loan_path: lp.clone(), - parent: parent_index, - first_move: InvalidMoveIndex, - first_child: InvalidMovePathIndex, - next_sibling, - }); - - index - } - }; - - debug!("move_path(lp={:?}, index={:?})", - lp, - index); - - assert_eq!(index.get(), self.paths.borrow().len() - 1); - self.path_map.borrow_mut().insert(lp, index); - return index; - } - - fn existing_move_path(&self, lp: &Rc>) - -> Option { - self.path_map.borrow().get(lp).cloned() - } - - fn existing_base_paths(&self, lp: &Rc>) - -> Vec { - let mut result = vec![]; - self.add_existing_base_paths(lp, &mut result); - result - } - - /// Adds any existing move path indices for `lp` and any base paths of `lp` to `result`, but - /// does not add new move paths - fn add_existing_base_paths(&self, lp: &Rc>, - result: &mut Vec) { - match self.path_map.borrow().get(lp).cloned() { - Some(index) => { - self.each_base_path(index, |p| { - result.push(p); - true - }); - } - None => { - match lp.kind { - LpVar(..) | LpUpvar(..) => { } - LpDowncast(ref b, _) | - LpExtend(ref b, ..) => { - self.add_existing_base_paths(b, result); - } - } - } - } - - } - - /// Adds a new move entry for a move of `lp` that occurs at location `id` with kind `kind`. - pub fn add_move( - &self, - tcx: TyCtxt<'tcx>, - orig_lp: Rc>, - id: hir::ItemLocalId, - ) { - // Moving one union field automatically moves all its fields. Also move siblings of - // all parent union fields, moves do not propagate upwards automatically. - let mut lp = orig_lp.clone(); - while let LpExtend(ref base_lp, mutbl, lp_elem) = lp.clone().kind { - if let (&ty::Adt(adt_def, _), LpInterior(opt_variant_id, interior)) - = (&base_lp.ty.sty, lp_elem) { - if adt_def.is_union() { - for (i, field) in adt_def.non_enum_variant().fields.iter().enumerate() { - let field = - InteriorKind::InteriorField(mc::FieldIndex(i, field.ident.name)); - if field != interior { - let sibling_lp_kind = - LpExtend(base_lp.clone(), mutbl, LpInterior(opt_variant_id, field)); - let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, tcx.types.err)); - self.add_move_helper(tcx, sibling_lp, id); - } - } - } - } - lp = base_lp.clone(); - } - - self.add_move_helper(tcx, orig_lp, id); - } - - fn add_move_helper( - &self, - tcx: TyCtxt<'tcx>, - lp: Rc>, - id: hir::ItemLocalId, - ) { - debug!("add_move(lp={:?}, id={:?})", lp, id); - - let path_index = self.move_path(tcx, lp); - let move_index = MoveIndex(self.moves.borrow().len()); - - let next_move = self.path_first_move(path_index); - self.set_path_first_move(path_index, move_index); - - self.moves.borrow_mut().push(Move { - path: path_index, - id, - next_move, - }); - } - - /// Adds a new record for an assignment to `lp` that occurs at location `id` with the given - /// `span`. - pub fn add_assignment( - &self, - tcx: TyCtxt<'tcx>, - lp: Rc>, - assign_id: hir::ItemLocalId, - span: Span, - ) { - // Assigning to one union field automatically assigns to all its fields. - if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind { - if let ty::Adt(adt_def, _) = base_lp.ty.sty { - if adt_def.is_union() { - for (i, field) in adt_def.non_enum_variant().fields.iter().enumerate() { - let field = - InteriorKind::InteriorField(mc::FieldIndex(i, field.ident.name)); - let field_ty = if field == interior { - lp.ty - } else { - tcx.types.err // Doesn't matter - }; - let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, - LpInterior(opt_variant_id, field)); - let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty)); - self.add_assignment_helper(tcx, sibling_lp, assign_id, - span); - } - return; - } - } - } - - self.add_assignment_helper(tcx, lp, assign_id, span); - } - - fn add_assignment_helper( - &self, - tcx: TyCtxt<'tcx>, - lp: Rc>, - assign_id: hir::ItemLocalId, - span: Span, - ) { - debug!("add_assignment(lp={:?}, assign_id={:?}", lp, assign_id); - - let path_index = self.move_path(tcx, lp.clone()); - - let assignment = Assignment { - path: path_index, - id: assign_id, - span, - }; - - if self.is_var_path(path_index) { - debug!("add_assignment[var](lp={:?}, assignment={}, path_index={:?})", - lp, self.var_assignments.borrow().len(), path_index); - - self.var_assignments.borrow_mut().push(assignment); - } else { - debug!("add_assignment[path](lp={:?}, path_index={:?})", - lp, path_index); - - self.path_assignments.borrow_mut().push(assignment); - } - } - - /// Adds the gen/kills for the various moves and - /// assignments into the provided data flow contexts. - /// Moves are generated by moves and killed by assignments and - /// scoping. Assignments are generated by assignment to variables and - /// killed by scoping. See `README.md` for more details. - fn add_gen_kills( - &self, - bccx: &BorrowckCtxt<'_, 'tcx>, - dfcx_moves: &mut MoveDataFlow<'_>, - dfcx_assign: &mut AssignDataFlow<'_>, - ) { - for (i, the_move) in self.moves.borrow().iter().enumerate() { - dfcx_moves.add_gen(the_move.id, i); - } - - for (i, assignment) in self.var_assignments.borrow().iter().enumerate() { - dfcx_assign.add_gen(assignment.id, i); - self.kill_moves(assignment.path, assignment.id, - KillFrom::Execution, dfcx_moves); - } - - for assignment in self.path_assignments.borrow().iter() { - self.kill_moves(assignment.path, assignment.id, - KillFrom::Execution, dfcx_moves); - } - - // Kill all moves related to a variable `x` when - // it goes out of scope: - for path in self.paths.borrow().iter() { - match path.loan_path.kind { - LpVar(..) | LpUpvar(..) | LpDowncast(..) => { - let kill_scope = path.loan_path.kill_scope(bccx); - let path = *self.path_map.borrow().get(&path.loan_path).unwrap(); - self.kill_moves(path, kill_scope.item_local_id(), - KillFrom::ScopeEnd, dfcx_moves); - } - LpExtend(..) => {} - } - } - - // Kill all assignments when the variable goes out of scope: - for (assignment_index, assignment) in - self.var_assignments.borrow().iter().enumerate() { - let lp = self.path_loan_path(assignment.path); - match lp.kind { - LpVar(..) | LpUpvar(..) | LpDowncast(..) => { - let kill_scope = lp.kill_scope(bccx); - dfcx_assign.add_kill(KillFrom::ScopeEnd, - kill_scope.item_local_id(), - assignment_index); - } - LpExtend(..) => { - bug!("var assignment for non var path"); - } - } - } - } - - fn each_base_path(&self, index: MovePathIndex, mut f: F) -> bool where - F: FnMut(MovePathIndex) -> bool, - { - let mut p = index; - while p != InvalidMovePathIndex { - if !f(p) { - return false; - } - p = self.path_parent(p); - } - return true; - } - - // FIXME(#19596) This is a workaround, but there should be better way to do this - fn each_extending_path_(&self, index: MovePathIndex, f: &mut F) -> bool where - F: FnMut(MovePathIndex) -> bool, - { - if !(*f)(index) { - return false; - } - - let mut p = self.path_first_child(index); - while p != InvalidMovePathIndex { - if !self.each_extending_path_(p, f) { - return false; - } - p = self.path_next_sibling(p); - } - - return true; - } - - fn each_extending_path(&self, index: MovePathIndex, mut f: F) -> bool where - F: FnMut(MovePathIndex) -> bool, - { - self.each_extending_path_(index, &mut f) - } - - fn each_applicable_move(&self, index0: MovePathIndex, mut f: F) -> bool where - F: FnMut(MoveIndex) -> bool, - { - let mut ret = true; - self.each_extending_path(index0, |index| { - let mut p = self.path_first_move(index); - while p != InvalidMoveIndex { - if !f(p) { - ret = false; - break; - } - p = self.move_next_move(p); - } - ret - }); - ret - } - - fn kill_moves( - &self, - path: MovePathIndex, - kill_id: hir::ItemLocalId, - kill_kind: KillFrom, - dfcx_moves: &mut MoveDataFlow<'_>, - ) { - // We can only perform kills for paths that refer to a unique location, - // since otherwise we may kill a move from one location with an - // assignment referring to another location. - - let loan_path = self.path_loan_path(path); - if loan_path_is_precise(&loan_path) { - self.each_applicable_move(path, |move_index| { - debug!("kill_moves add_kill {:?} kill_id={:?} move_index={}", - kill_kind, kill_id, move_index.get()); - dfcx_moves.add_kill(kill_kind, kill_id, move_index.get()); - true - }); - } - } -} - -impl<'tcx> FlowedMoveData<'tcx> { - pub fn new( - move_data: MoveData<'tcx>, - bccx: &BorrowckCtxt<'_, 'tcx>, - cfg: &cfg::CFG, - body: &hir::Body, - ) -> FlowedMoveData<'tcx> { - let tcx = bccx.tcx; - - let mut dfcx_moves = - DataFlowContext::new(tcx, - "flowed_move_data_moves", - Some(body), - cfg, - MoveDataFlowOperator, - move_data.moves.borrow().len()); - let mut dfcx_assign = - DataFlowContext::new(tcx, - "flowed_move_data_assigns", - Some(body), - cfg, - AssignDataFlowOperator, - move_data.var_assignments.borrow().len()); - - move_data.add_gen_kills(bccx, - &mut dfcx_moves, - &mut dfcx_assign); - - dfcx_moves.add_kills_from_flow_exits(cfg); - dfcx_assign.add_kills_from_flow_exits(cfg); - - dfcx_moves.propagate(cfg, body); - dfcx_assign.propagate(cfg, body); - - FlowedMoveData { - move_data, - dfcx_moves, - dfcx_assign, - } - } - - pub fn is_move_path(&self, id: hir::ItemLocalId, loan_path: &Rc>) -> bool { - //! Returns the kind of a move of `loan_path` by `id`, if one exists. - - let mut ret = false; - if let Some(loan_path_index) = self.move_data.path_map.borrow().get(&*loan_path) { - self.dfcx_moves.each_gen_bit(id, |move_index| { - let the_move = self.move_data.moves.borrow(); - let the_move = (*the_move)[move_index]; - if the_move.path == *loan_path_index { - ret = true; - false - } else { - true - } - }); - } - ret - } - - /// Iterates through each move of `loan_path` (or some base path of `loan_path`) that *may* - /// have occurred on entry to `id` without an intervening assignment. In other words, any moves - /// that would invalidate a reference to `loan_path` at location `id`. - pub fn each_move_of(&self, - id: hir::ItemLocalId, - loan_path: &Rc>, - mut f: F) - -> bool where - F: FnMut(&Move, &LoanPath<'tcx>) -> bool, - { - // Bad scenarios: - // - // 1. Move of `a.b.c`, use of `a.b.c` - // 2. Move of `a.b.c`, use of `a.b.c.d` - // 3. Move of `a.b.c`, use of `a` or `a.b` - // - // OK scenario: - // - // 4. move of `a.b.c`, use of `a.b.d` - - let base_indices = self.move_data.existing_base_paths(loan_path); - if base_indices.is_empty() { - return true; - } - - let opt_loan_path_index = self.move_data.existing_move_path(loan_path); - - let mut ret = true; - - self.dfcx_moves.each_bit_on_entry(id, |index| { - let the_move = self.move_data.moves.borrow(); - let the_move = &(*the_move)[index]; - let moved_path = the_move.path; - if base_indices.iter().any(|x| x == &moved_path) { - // Scenario 1 or 2: `loan_path` or some base path of - // `loan_path` was moved. - if !f(the_move, &self.move_data.path_loan_path(moved_path)) { - ret = false; - } - } else { - if let Some(loan_path_index) = opt_loan_path_index { - let cont = self.move_data.each_base_path(moved_path, |p| { - if p == loan_path_index { - // Scenario 3: some extension of `loan_path` - // was moved - f(the_move, - &self.move_data.path_loan_path(moved_path)) - } else { - true - } - }); - if !cont { ret = false; } - } - } - ret - }) - } - - /// Iterates through every assignment to `loan_path` that may have occurred on entry to `id`. - /// `loan_path` must be a single variable. - pub fn each_assignment_of(&self, - id: hir::ItemLocalId, - loan_path: &Rc>, - mut f: F) - -> bool where - F: FnMut(&Assignment) -> bool, - { - let loan_path_index = { - match self.move_data.existing_move_path(loan_path) { - Some(i) => i, - None => { - // if there were any assignments, it'd have an index - return true; - } - } - }; - - self.dfcx_assign.each_bit_on_entry(id, |index| { - let assignment = self.move_data.var_assignments.borrow(); - let assignment = &(*assignment)[index]; - if assignment.path == loan_path_index && !f(assignment) { - false - } else { - true - } - }) - } -} - -impl BitwiseOperator for MoveDataFlowOperator { - #[inline] - fn join(&self, succ: usize, pred: usize) -> usize { - succ | pred // moves from both preds are in scope - } -} - -impl DataFlowOperator for MoveDataFlowOperator { - #[inline] - fn initial_value(&self) -> bool { - false // no loans in scope by default - } -} - -impl BitwiseOperator for AssignDataFlowOperator { - #[inline] - fn join(&self, succ: usize, pred: usize) -> usize { - succ | pred // moves from both preds are in scope - } -} - -impl DataFlowOperator for AssignDataFlowOperator { - #[inline] - fn initial_value(&self) -> bool { - false // no assignments in scope by default - } -} diff --git a/src/librustc_ast_borrowck/dataflow.rs b/src/librustc_ast_borrowck/dataflow.rs deleted file mode 100644 index 94849728a9319..0000000000000 --- a/src/librustc_ast_borrowck/dataflow.rs +++ /dev/null @@ -1,673 +0,0 @@ -//! A module for propagating forward dataflow information. The analysis -//! assumes that the items to be propagated can be represented as bits -//! and thus uses bitvectors. Your job is simply to specify the so-called -//! GEN and KILL bits for each expression. - -use rustc::cfg; -use rustc::cfg::CFGIndex; -use rustc::ty::TyCtxt; -use std::mem; -use std::usize; -use log::debug; - -use rustc_data_structures::graph::implementation::OUTGOING; - -use rustc::util::nodemap::FxHashMap; -use rustc::hir; -use rustc::hir::intravisit; -use rustc::hir::print as pprust; - -#[derive(Copy, Clone, Debug)] -pub enum EntryOrExit { - Entry, - Exit, -} - -#[derive(Clone)] -pub struct DataFlowContext<'tcx, O> { - tcx: TyCtxt<'tcx>, - - /// a name for the analysis using this dataflow instance - analysis_name: &'static str, - - /// the data flow operator - oper: O, - - /// number of bits to propagate per id - bits_per_id: usize, - - /// number of words we will use to store bits_per_id. - /// equal to bits_per_id/usize::BITS rounded up. - words_per_id: usize, - - // mapping from node to cfg node index - // FIXME (#6298): Shouldn't this go with CFG? - local_id_to_index: FxHashMap>, - - // Bit sets per cfg node. The following three fields (`gens`, `kills`, - // and `on_entry`) all have the same structure. For each id in - // `id_range`, there is a range of words equal to `words_per_id`. - // So, to access the bits for any given id, you take a slice of - // the full vector (see the method `compute_id_range()`). - /// bits generated as we exit the cfg node. Updated by `add_gen()`. - gens: Vec, - - /// bits killed as we exit the cfg node, or non-locally jump over - /// it. Updated by `add_kill(KillFrom::ScopeEnd)`. - scope_kills: Vec, - - /// bits killed as we exit the cfg node directly; if it is jumped - /// over, e.g., via `break`, the kills are not reflected in the - /// jump's effects. Updated by `add_kill(KillFrom::Execution)`. - action_kills: Vec, - - /// bits that are valid on entry to the cfg node. Updated by - /// `propagate()`. - on_entry: Vec, -} - -pub trait BitwiseOperator { - /// Joins two predecessor bits together, typically either `|` or `&` - fn join(&self, succ: usize, pred: usize) -> usize; -} - -/// Parameterization for the precise form of data flow that is used. -pub trait DataFlowOperator : BitwiseOperator { - /// Specifies the initial value for each bit in the `on_entry` set - fn initial_value(&self) -> bool; -} - -struct PropagationContext<'a, 'tcx, O> { - dfcx: &'a mut DataFlowContext<'tcx, O>, - changed: bool, -} - -fn get_cfg_indices(id: hir::ItemLocalId, - index: &FxHashMap>) - -> &[CFGIndex] { - index.get(&id).map_or(&[], |v| &v[..]) -} - -impl<'tcx, O: DataFlowOperator> DataFlowContext<'tcx, O> { - fn has_bitset_for_local_id(&self, n: hir::ItemLocalId) -> bool { - assert!(n != hir::DUMMY_ITEM_LOCAL_ID); - self.local_id_to_index.contains_key(&n) - } -} - -impl<'tcx, O: DataFlowOperator> pprust::PpAnn for DataFlowContext<'tcx, O> { - fn nested(&self, state: &mut pprust::State<'_>, nested: pprust::Nested) { - pprust::PpAnn::nested(self.tcx.hir(), state, nested) - } - fn pre(&self, - ps: &mut pprust::State<'_>, - node: pprust::AnnNode<'_>) { - let id = match node { - pprust::AnnNode::Name(_) => return, - pprust::AnnNode::Expr(expr) => expr.hir_id.local_id, - pprust::AnnNode::Block(blk) => blk.hir_id.local_id, - pprust::AnnNode::Item(_) | - pprust::AnnNode::SubItem(_) => return, - pprust::AnnNode::Pat(pat) => pat.hir_id.local_id, - pprust::AnnNode::Arm(arm) => arm.hir_id.local_id, - }; - - if !self.has_bitset_for_local_id(id) { - return; - } - - assert!(self.bits_per_id > 0); - let indices = get_cfg_indices(id, &self.local_id_to_index); - for &cfgidx in indices { - let (start, end) = self.compute_id_range(cfgidx); - let on_entry = &self.on_entry[start.. end]; - let entry_str = bits_to_string(on_entry); - - let gens = &self.gens[start.. end]; - let gens_str = if gens.iter().any(|&u| u != 0) { - format!(" gen: {}", bits_to_string(gens)) - } else { - String::new() - }; - - let action_kills = &self.action_kills[start .. end]; - let action_kills_str = if action_kills.iter().any(|&u| u != 0) { - format!(" action_kill: {}", bits_to_string(action_kills)) - } else { - String::new() - }; - - let scope_kills = &self.scope_kills[start .. end]; - let scope_kills_str = if scope_kills.iter().any(|&u| u != 0) { - format!(" scope_kill: {}", bits_to_string(scope_kills)) - } else { - String::new() - }; - - ps.synth_comment( - format!("id {}: {}{}{}{}", id.as_usize(), entry_str, - gens_str, action_kills_str, scope_kills_str)); - ps.s.space(); - } - } -} - -fn build_local_id_to_index(body: Option<&hir::Body>, - cfg: &cfg::CFG) - -> FxHashMap> { - let mut index = FxHashMap::default(); - - // FIXME(#15020) Would it be better to fold formals from decl - // into cfg itself? i.e., introduce a fn-based flow-graph in - // addition to the current block-based flow-graph, rather than - // have to put traversals like this here? - if let Some(body) = body { - add_entries_from_fn_body(&mut index, body, cfg.entry); - } - - cfg.graph.each_node(|node_idx, node| { - if let cfg::CFGNodeData::AST(id) = node.data { - index.entry(id).or_default().push(node_idx); - } - true - }); - - return index; - - /// Adds mappings from the ast nodes for the formal bindings to - /// the entry-node in the graph. - fn add_entries_from_fn_body(index: &mut FxHashMap>, - body: &hir::Body, - entry: CFGIndex) { - use rustc::hir::intravisit::Visitor; - - struct Formals<'a> { - entry: CFGIndex, - index: &'a mut FxHashMap>, - } - let mut formals = Formals { entry: entry, index: index }; - for arg in &body.arguments { - formals.visit_pat(&arg.pat); - } - impl<'a, 'v> Visitor<'v> for Formals<'a> { - fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'v> { - intravisit::NestedVisitorMap::None - } - - fn visit_pat(&mut self, p: &hir::Pat) { - self.index.entry(p.hir_id.local_id).or_default().push(self.entry); - intravisit::walk_pat(self, p) - } - } - } -} - -/// Flag used by `add_kill` to indicate whether the provided kill -/// takes effect only when control flows directly through the node in -/// question, or if the kill's effect is associated with any -/// control-flow directly through or indirectly over the node. -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum KillFrom { - /// A `ScopeEnd` kill is one that takes effect when any control - /// flow goes over the node. A kill associated with the end of the - /// scope of a variable declaration `let x;` is an example of a - /// `ScopeEnd` kill. - ScopeEnd, - - /// An `Execution` kill is one that takes effect only when control - /// flow goes through the node to completion. A kill associated - /// with an assignment statement `x = expr;` is an example of an - /// `Execution` kill. - Execution, -} - -impl<'tcx, O: DataFlowOperator> DataFlowContext<'tcx, O> { - pub fn new( - tcx: TyCtxt<'tcx>, - analysis_name: &'static str, - body: Option<&hir::Body>, - cfg: &cfg::CFG, - oper: O, - bits_per_id: usize, - ) -> DataFlowContext<'tcx, O> { - let usize_bits = mem::size_of::() * 8; - let words_per_id = (bits_per_id + usize_bits - 1) / usize_bits; - let num_nodes = cfg.graph.all_nodes().len(); - - debug!("DataFlowContext::new(analysis_name: {}, \ - bits_per_id={}, words_per_id={}) \ - num_nodes: {}", - analysis_name, bits_per_id, words_per_id, - num_nodes); - - let entry = if oper.initial_value() { usize::MAX } else {0}; - - let zeroes = vec![0; num_nodes * words_per_id]; - let gens = zeroes.clone(); - let kills1 = zeroes.clone(); - let kills2 = zeroes; - let on_entry = vec![entry; num_nodes * words_per_id]; - - let local_id_to_index = build_local_id_to_index(body, cfg); - - DataFlowContext { - tcx, - analysis_name, - words_per_id, - local_id_to_index, - bits_per_id, - oper, - gens, - action_kills: kills1, - scope_kills: kills2, - on_entry, - } - } - - pub fn add_gen(&mut self, id: hir::ItemLocalId, bit: usize) { - //! Indicates that `id` generates `bit` - debug!("{} add_gen(id={:?}, bit={})", - self.analysis_name, id, bit); - assert!(self.local_id_to_index.contains_key(&id)); - assert!(self.bits_per_id > 0); - - let indices = get_cfg_indices(id, &self.local_id_to_index); - for &cfgidx in indices { - let (start, end) = self.compute_id_range(cfgidx); - let gens = &mut self.gens[start.. end]; - set_bit(gens, bit); - } - } - - pub fn add_kill(&mut self, kind: KillFrom, id: hir::ItemLocalId, bit: usize) { - //! Indicates that `id` kills `bit` - debug!("{} add_kill(id={:?}, bit={})", - self.analysis_name, id, bit); - assert!(self.local_id_to_index.contains_key(&id)); - assert!(self.bits_per_id > 0); - - let indices = get_cfg_indices(id, &self.local_id_to_index); - for &cfgidx in indices { - let (start, end) = self.compute_id_range(cfgidx); - let kills = match kind { - KillFrom::Execution => &mut self.action_kills[start.. end], - KillFrom::ScopeEnd => &mut self.scope_kills[start.. end], - }; - set_bit(kills, bit); - } - } - - fn apply_gen_kill(&self, cfgidx: CFGIndex, bits: &mut [usize]) { - //! Applies the gen and kill sets for `cfgidx` to `bits` - debug!("{} apply_gen_kill(cfgidx={:?}, bits={}) [before]", - self.analysis_name, cfgidx, mut_bits_to_string(bits)); - assert!(self.bits_per_id > 0); - - let (start, end) = self.compute_id_range(cfgidx); - let gens = &self.gens[start.. end]; - bitwise(bits, gens, &Union); - let kills = &self.action_kills[start.. end]; - bitwise(bits, kills, &Subtract); - let kills = &self.scope_kills[start.. end]; - bitwise(bits, kills, &Subtract); - - debug!("{} apply_gen_kill(cfgidx={:?}, bits={}) [after]", - self.analysis_name, cfgidx, mut_bits_to_string(bits)); - } - - fn compute_id_range(&self, cfgidx: CFGIndex) -> (usize, usize) { - let n = cfgidx.node_id(); - let start = n * self.words_per_id; - let end = start + self.words_per_id; - - assert!(start < self.gens.len()); - assert!(end <= self.gens.len()); - assert!(self.gens.len() == self.action_kills.len()); - assert!(self.gens.len() == self.scope_kills.len()); - assert!(self.gens.len() == self.on_entry.len()); - - (start, end) - } - - - pub fn each_bit_on_entry(&self, id: hir::ItemLocalId, mut f: F) -> bool where - F: FnMut(usize) -> bool, - { - //! Iterates through each bit that is set on entry to `id`. - //! Only useful after `propagate()` has been called. - if !self.has_bitset_for_local_id(id) { - return true; - } - let indices = get_cfg_indices(id, &self.local_id_to_index); - for &cfgidx in indices { - if !self.each_bit_for_node(EntryOrExit::Entry, cfgidx, |i| f(i)) { - return false; - } - } - return true; - } - - pub fn each_bit_for_node(&self, e: EntryOrExit, cfgidx: CFGIndex, f: F) -> bool where - F: FnMut(usize) -> bool, - { - //! Iterates through each bit that is set on entry/exit to `cfgidx`. - //! Only useful after `propagate()` has been called. - - if self.bits_per_id == 0 { - // Skip the surprisingly common degenerate case. (Note - // compute_id_range requires self.words_per_id > 0.) - return true; - } - - let (start, end) = self.compute_id_range(cfgidx); - let on_entry = &self.on_entry[start.. end]; - let temp_bits; - let slice = match e { - EntryOrExit::Entry => on_entry, - EntryOrExit::Exit => { - let mut t = on_entry.to_vec(); - self.apply_gen_kill(cfgidx, &mut t); - temp_bits = t; - &temp_bits[..] - } - }; - debug!("{} each_bit_for_node({:?}, cfgidx={:?}) bits={}", - self.analysis_name, e, cfgidx, bits_to_string(slice)); - self.each_bit(slice, f) - } - - pub fn each_gen_bit(&self, id: hir::ItemLocalId, mut f: F) -> bool where - F: FnMut(usize) -> bool, - { - //! Iterates through each bit in the gen set for `id`. - if !self.has_bitset_for_local_id(id) { - return true; - } - - if self.bits_per_id == 0 { - // Skip the surprisingly common degenerate case. (Note - // compute_id_range requires self.words_per_id > 0.) - return true; - } - - let indices = get_cfg_indices(id, &self.local_id_to_index); - for &cfgidx in indices { - let (start, end) = self.compute_id_range(cfgidx); - let gens = &self.gens[start.. end]; - debug!("{} each_gen_bit(id={:?}, gens={})", - self.analysis_name, id, bits_to_string(gens)); - if !self.each_bit(gens, |i| f(i)) { - return false; - } - } - return true; - } - - fn each_bit(&self, words: &[usize], mut f: F) -> bool where - F: FnMut(usize) -> bool, - { - //! Helper for iterating over the bits in a bit set. - //! Returns false on the first call to `f` that returns false; - //! if all calls to `f` return true, then returns true. - - let usize_bits = mem::size_of::() * 8; - for (word_index, &word) in words.iter().enumerate() { - if word != 0 { - let base_index = word_index * usize_bits; - for offset in 0..usize_bits { - let bit = 1 << offset; - if (word & bit) != 0 { - // N.B., we round up the total number of bits - // that we store in any given bit set so that - // it is an even multiple of usize::BITS. This - // means that there may be some stray bits at - // the end that do not correspond to any - // actual value. So before we callback, check - // whether the bit_index is greater than the - // actual value the user specified and stop - // iterating if so. - let bit_index = base_index + offset as usize; - if bit_index >= self.bits_per_id { - return true; - } else if !f(bit_index) { - return false; - } - } - } - } - } - return true; - } - - pub fn add_kills_from_flow_exits(&mut self, cfg: &cfg::CFG) { - //! Whenever you have a `break` or `continue` statement, flow - //! exits through any number of enclosing scopes on its way to - //! the new destination. This function infers the kill bits of - //! those control operators based on the kill bits associated - //! with those scopes. - //! - //! This is usually called (if it is called at all), after - //! all add_gen and add_kill calls, but before propagate. - - debug!("{} add_kills_from_flow_exits", self.analysis_name); - if self.bits_per_id == 0 { - // Skip the surprisingly common degenerate case. (Note - // compute_id_range requires self.words_per_id > 0.) - return; - } - cfg.graph.each_edge(|_edge_index, edge| { - let flow_exit = edge.source(); - let (start, end) = self.compute_id_range(flow_exit); - let mut orig_kills = self.scope_kills[start.. end].to_vec(); - - let mut changed = false; - for &id in &edge.data.exiting_scopes { - let opt_cfg_idx = self.local_id_to_index.get(&id); - match opt_cfg_idx { - Some(indices) => { - for &cfg_idx in indices { - let (start, end) = self.compute_id_range(cfg_idx); - let kills = &self.scope_kills[start.. end]; - if bitwise(&mut orig_kills, kills, &Union) { - debug!("scope exits: scope id={:?} \ - (node={:?} of {:?}) added killset: {}", - id, cfg_idx, indices, - bits_to_string(kills)); - changed = true; - } - } - } - None => { - debug!("{} add_kills_from_flow_exits flow_exit={:?} \ - no cfg_idx for exiting_scope={:?}", - self.analysis_name, flow_exit, id); - } - } - } - - if changed { - let bits = &mut self.scope_kills[start.. end]; - debug!("{} add_kills_from_flow_exits flow_exit={:?} bits={} [before]", - self.analysis_name, flow_exit, mut_bits_to_string(bits)); - bits.copy_from_slice(&orig_kills[..]); - debug!("{} add_kills_from_flow_exits flow_exit={:?} bits={} [after]", - self.analysis_name, flow_exit, mut_bits_to_string(bits)); - } - true - }); - } -} - -// N.B. `Clone + 'static` only needed for pretty printing. -impl<'tcx, O: DataFlowOperator + Clone + 'static> DataFlowContext<'tcx, O> { - pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Body) { - //! Performs the data flow analysis. - - if self.bits_per_id == 0 { - // Optimize the surprisingly common degenerate case. - return; - } - - { - let words_per_id = self.words_per_id; - let mut propcx = PropagationContext { - dfcx: &mut *self, - changed: true - }; - - let nodes_po = cfg.graph.nodes_in_postorder(OUTGOING, cfg.entry); - let mut temp = vec![0; words_per_id]; - let mut num_passes = 0; - while propcx.changed { - num_passes += 1; - propcx.changed = false; - propcx.reset(&mut temp); - propcx.walk_cfg(cfg, &nodes_po, &mut temp); - } - debug!("finished in {} iterations", num_passes); - } - - debug!("Dataflow result for {}:", self.analysis_name); - debug!("{}", pprust::to_string(self, |s| { - s.cbox(pprust::INDENT_UNIT); - s.ibox(0); - s.print_expr(&body.value) - })); - } -} - -impl PropagationContext<'_, 'tcx, O> { - fn walk_cfg(&mut self, - cfg: &cfg::CFG, - nodes_po: &[CFGIndex], - in_out: &mut [usize]) { - debug!("DataFlowContext::walk_cfg(in_out={}) {}", - bits_to_string(in_out), self.dfcx.analysis_name); - assert!(self.dfcx.bits_per_id > 0); - - // Iterate over nodes in reverse post-order. - for &node_index in nodes_po.iter().rev() { - let node = cfg.graph.node(node_index); - debug!("DataFlowContext::walk_cfg idx={:?} id={:?} begin in_out={}", - node_index, node.data.id(), bits_to_string(in_out)); - - let (start, end) = self.dfcx.compute_id_range(node_index); - - // Initialize local bitvector with state on-entry. - in_out.copy_from_slice(&self.dfcx.on_entry[start.. end]); - - // Compute state on-exit by applying transfer function to - // state on-entry. - self.dfcx.apply_gen_kill(node_index, in_out); - - // Propagate state on-exit from node into its successors. - self.propagate_bits_into_graph_successors_of(in_out, cfg, node_index); - } - } - - fn reset(&mut self, bits: &mut [usize]) { - let e = if self.dfcx.oper.initial_value() {usize::MAX} else {0}; - for b in bits { - *b = e; - } - } - - fn propagate_bits_into_graph_successors_of(&mut self, - pred_bits: &[usize], - cfg: &cfg::CFG, - cfgidx: CFGIndex) { - for (_, edge) in cfg.graph.outgoing_edges(cfgidx) { - self.propagate_bits_into_entry_set_for(pred_bits, edge); - } - } - - fn propagate_bits_into_entry_set_for(&mut self, - pred_bits: &[usize], - edge: &cfg::CFGEdge) { - let source = edge.source(); - let cfgidx = edge.target(); - debug!("{} propagate_bits_into_entry_set_for(pred_bits={}, {:?} to {:?})", - self.dfcx.analysis_name, bits_to_string(pred_bits), source, cfgidx); - assert!(self.dfcx.bits_per_id > 0); - - let (start, end) = self.dfcx.compute_id_range(cfgidx); - let changed = { - // (scoping mutable borrow of self.dfcx.on_entry) - let on_entry = &mut self.dfcx.on_entry[start.. end]; - bitwise(on_entry, pred_bits, &self.dfcx.oper) - }; - if changed { - debug!("{} changed entry set for {:?} to {}", - self.dfcx.analysis_name, cfgidx, - bits_to_string(&self.dfcx.on_entry[start.. end])); - self.changed = true; - } - } -} - -fn mut_bits_to_string(words: &mut [usize]) -> String { - bits_to_string(words) -} - -fn bits_to_string(words: &[usize]) -> String { - let mut result = String::new(); - let mut sep = '['; - - // Note: this is a little endian printout of bytes. - - for &word in words { - let mut v = word; - for _ in 0..mem::size_of::() { - result.push(sep); - result.push_str(&format!("{:02x}", v & 0xFF)); - v >>= 8; - sep = '-'; - } - } - result.push(']'); - return result -} - -#[inline] -fn bitwise(out_vec: &mut [usize], - in_vec: &[usize], - op: &Op) -> bool { - assert_eq!(out_vec.len(), in_vec.len()); - let mut changed = false; - for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) { - let old_val = *out_elt; - let new_val = op.join(old_val, *in_elt); - *out_elt = new_val; - changed |= old_val != new_val; - } - changed -} - -fn set_bit(words: &mut [usize], bit: usize) -> bool { - debug!("set_bit: words={} bit={}", - mut_bits_to_string(words), bit_str(bit)); - let usize_bits = mem::size_of::() * 8; - let word = bit / usize_bits; - let bit_in_word = bit % usize_bits; - let bit_mask = 1 << bit_in_word; - debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask); - let oldv = words[word]; - let newv = oldv | bit_mask; - words[word] = newv; - oldv != newv -} - -fn bit_str(bit: usize) -> String { - let byte = bit >> 3; - let lobits = 1 << (bit & 0b111); - format!("[{}:{}-{:02x}]", bit, byte, lobits) -} - -struct Union; -impl BitwiseOperator for Union { - fn join(&self, a: usize, b: usize) -> usize { a | b } -} -struct Subtract; -impl BitwiseOperator for Subtract { - fn join(&self, a: usize, b: usize) -> usize { a & !b } -} diff --git a/src/librustc_ast_borrowck/graphviz.rs b/src/librustc_ast_borrowck/graphviz.rs deleted file mode 100644 index 7a8a23ca76afc..0000000000000 --- a/src/librustc_ast_borrowck/graphviz.rs +++ /dev/null @@ -1,146 +0,0 @@ -//! This module provides linkage between rustc::middle::graph and -//! libgraphviz traits, specialized to attaching borrowck analysis -//! data to rendered labels. - -pub use Variant::*; - -pub use rustc::cfg::graphviz::{Node, Edge}; -use rustc::cfg::graphviz as cfg_dot; - -use crate::borrowck::{self, BorrowckCtxt, LoanPath}; -use crate::dataflow::{DataFlowOperator, DataFlowContext, EntryOrExit}; -use log::debug; -use rustc::cfg::CFGIndex; -use std::rc::Rc; - -#[derive(Debug, Copy, Clone)] -pub enum Variant { - Loans, - Moves, - Assigns, -} - -impl Variant { - pub fn short_name(&self) -> &'static str { - match *self { - Loans => "loans", - Moves => "moves", - Assigns => "assigns", - } - } -} - -pub struct DataflowLabeller<'a, 'tcx> { - pub inner: cfg_dot::LabelledCFG<'a, 'tcx>, - pub variants: Vec, - pub borrowck_ctxt: &'a BorrowckCtxt<'a, 'tcx>, - pub analysis_data: &'a borrowck::AnalysisData<'tcx>, -} - -impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> { - fn dataflow_for(&self, e: EntryOrExit, n: &Node<'a>) -> String { - let id = n.1.data.id(); - debug!("dataflow_for({:?}, id={:?}) {:?}", e, id, self.variants); - let mut sets = String::new(); - let mut seen_one = false; - for &variant in &self.variants { - if seen_one { sets.push_str(" "); } else { seen_one = true; } - sets.push_str(variant.short_name()); - sets.push_str(": "); - sets.push_str(&self.dataflow_for_variant(e, n, variant)); - } - sets - } - - fn dataflow_for_variant(&self, e: EntryOrExit, n: &Node<'_>, v: Variant) -> String { - let cfgidx = n.0; - match v { - Loans => self.dataflow_loans_for(e, cfgidx), - Moves => self.dataflow_moves_for(e, cfgidx), - Assigns => self.dataflow_assigns_for(e, cfgidx), - } - } - - fn build_set( - &self, - e: EntryOrExit, - cfgidx: CFGIndex, - dfcx: &DataFlowContext<'tcx, O>, - mut to_lp: F, - ) -> String - where - F: FnMut(usize) -> Rc>, - { - let mut saw_some = false; - let mut set = "{".to_string(); - dfcx.each_bit_for_node(e, cfgidx, |index| { - let lp = to_lp(index); - if saw_some { - set.push_str(", "); - } - let loan_str = self.borrowck_ctxt.loan_path_to_string(&lp); - set.push_str(&loan_str); - saw_some = true; - true - }); - set.push_str("}"); - set - } - - fn dataflow_loans_for(&self, e: EntryOrExit, cfgidx: CFGIndex) -> String { - let dfcx = &self.analysis_data.loans; - let loan_index_to_path = |loan_index| { - let all_loans = &self.analysis_data.all_loans; - let l: &borrowck::Loan<'_> = &all_loans[loan_index]; - l.loan_path() - }; - self.build_set(e, cfgidx, dfcx, loan_index_to_path) - } - - fn dataflow_moves_for(&self, e: EntryOrExit, cfgidx: CFGIndex) -> String { - let dfcx = &self.analysis_data.move_data.dfcx_moves; - let move_index_to_path = |move_index| { - let move_data = &self.analysis_data.move_data.move_data; - let moves = move_data.moves.borrow(); - let the_move: &borrowck::move_data::Move = &(*moves)[move_index]; - move_data.path_loan_path(the_move.path) - }; - self.build_set(e, cfgidx, dfcx, move_index_to_path) - } - - fn dataflow_assigns_for(&self, e: EntryOrExit, cfgidx: CFGIndex) -> String { - let dfcx = &self.analysis_data.move_data.dfcx_assign; - let assign_index_to_path = |assign_index| { - let move_data = &self.analysis_data.move_data.move_data; - let assignments = move_data.var_assignments.borrow(); - let assignment: &borrowck::move_data::Assignment = &(*assignments)[assign_index]; - move_data.path_loan_path(assignment.path) - }; - self.build_set(e, cfgidx, dfcx, assign_index_to_path) - } -} - -impl<'a, 'tcx> dot::Labeller<'a> for DataflowLabeller<'a, 'tcx> { - type Node = Node<'a>; - type Edge = Edge<'a>; - fn graph_id(&'a self) -> dot::Id<'a> { self.inner.graph_id() } - fn node_id(&'a self, n: &Node<'a>) -> dot::Id<'a> { self.inner.node_id(n) } - fn node_label(&'a self, n: &Node<'a>) -> dot::LabelText<'a> { - let prefix = self.dataflow_for(EntryOrExit::Entry, n); - let suffix = self.dataflow_for(EntryOrExit::Exit, n); - let inner_label = self.inner.node_label(n); - inner_label - .prefix_line(dot::LabelText::LabelStr(prefix.into())) - .suffix_line(dot::LabelText::LabelStr(suffix.into())) - } - fn edge_label(&'a self, e: &Edge<'a>) -> dot::LabelText<'a> { self.inner.edge_label(e) } -} - -impl<'a, 'tcx> dot::GraphWalk<'a> for DataflowLabeller<'a, 'tcx> { - type Node = Node<'a>; - type Edge = Edge<'a>; - fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { self.inner.nodes() } - fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { self.inner.edges() } - fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { self.inner.source(edge) } - fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { self.inner.target(edge) } -} diff --git a/src/librustc_ast_borrowck/lib.rs b/src/librustc_ast_borrowck/lib.rs deleted file mode 100644 index dc818278a4b74..0000000000000 --- a/src/librustc_ast_borrowck/lib.rs +++ /dev/null @@ -1,22 +0,0 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] - -#![allow(non_camel_case_types)] - -#![feature(in_band_lifetimes)] -#![feature(nll)] - -#![recursion_limit="256"] - -#[macro_use] -extern crate rustc; - -pub use borrowck::check_crate; -pub use borrowck::build_borrowck_dataflow_data_for_fn; - -mod borrowck; - -pub mod graphviz; - -mod dataflow; - -pub use borrowck::provide; diff --git a/src/librustc_codegen_llvm/Cargo.toml b/src/librustc_codegen_llvm/Cargo.toml index 5e1b0eafdec36..98efa6a5804bd 100644 --- a/src/librustc_codegen_llvm/Cargo.toml +++ b/src/librustc_codegen_llvm/Cargo.toml @@ -11,11 +11,7 @@ crate-type = ["dylib"] test = false [dependencies] -cc = "1.0.1" # Used to locate MSVC -num_cpus = "1.0" -tempfile = "3.0" rustc_llvm = { path = "../librustc_llvm" } -memmap = "0.6" [features] # This is used to convince Cargo to separately cache builds of `rustc_codegen_llvm` diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index ff87afe0c444b..ae5cfc4d97b59 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -229,7 +229,7 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> { // We instead thus allocate some scratch space... let scratch_size = cast.size(bx); let scratch_align = cast.align(bx); - let llscratch = bx.alloca(cast.llvm_type(bx), "abi_cast", scratch_align); + let llscratch = bx.alloca(cast.llvm_type(bx), scratch_align); bx.lifetime_start(llscratch, scratch_size); // ...where we first store the value... @@ -264,7 +264,7 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> { val }; match self.mode { - PassMode::Ignore(_) => {} + PassMode::Ignore => {} PassMode::Pair(..) => { OperandValue::Pair(next(), next()).store(bx, dst); } @@ -319,9 +319,7 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> { ); let llreturn_ty = match self.ret.mode { - PassMode::Ignore(IgnoreMode::Zst) => cx.type_void(), - PassMode::Ignore(IgnoreMode::CVarArgs) => - bug!("`va_list` should never be a return type"), + PassMode::Ignore => cx.type_void(), PassMode::Direct(_) | PassMode::Pair(..) => { self.ret.layout.immediate_llvm_type(cx) } @@ -339,7 +337,7 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> { } let llarg_ty = match arg.mode { - PassMode::Ignore(_) => continue, + PassMode::Ignore => continue, PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx), PassMode::Pair(..) => { llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true)); @@ -408,7 +406,7 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> { apply(&ArgAttributes::new(), None); } match arg.mode { - PassMode::Ignore(_) => {} + PassMode::Ignore => {} PassMode::Direct(ref attrs) | PassMode::Indirect(ref attrs, None) => apply(attrs, Some(arg.layout.llvm_type(cx))), PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => { @@ -455,7 +453,7 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> { apply(&ArgAttributes::new(), None); } match arg.mode { - PassMode::Ignore(_) => {} + PassMode::Ignore => {} PassMode::Direct(ref attrs) | PassMode::Indirect(ref attrs, None) => apply(attrs, Some(arg.layout.llvm_type(bx))), PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => { diff --git a/src/librustc_codegen_llvm/allocator.rs b/src/librustc_codegen_llvm/allocator.rs index 5d43bf6ae28bf..f31765cea4f12 100644 --- a/src/librustc_codegen_llvm/allocator.rs +++ b/src/librustc_codegen_llvm/allocator.rs @@ -68,7 +68,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut ModuleLlvm, kind: Alloc let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, - "entry\0".as_ptr() as *const _); + "entry\0".as_ptr().cast()); let llbuilder = llvm::LLVMCreateBuilderInContext(llcx); llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb); @@ -80,7 +80,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut ModuleLlvm, kind: Alloc args.as_ptr(), args.len() as c_uint, None, - "\0".as_ptr() as *const _); + "\0".as_ptr().cast()); llvm::LLVMSetTailCall(ret, True); if output.is_some() { llvm::LLVMBuildRet(llbuilder, ret); diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs index 9763d523a2ac4..b68ee2cb44d4b 100644 --- a/src/librustc_codegen_llvm/asm.rs +++ b/src/librustc_codegen_llvm/asm.rs @@ -6,9 +6,9 @@ use crate::value::Value; use rustc::hir; use rustc_codegen_ssa::traits::*; - use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::mir::operand::OperandValue; +use syntax_pos::Span; use std::ffi::{CStr, CString}; use libc::{c_uint, c_char}; @@ -19,7 +19,8 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { &mut self, ia: &hir::InlineAsm, outputs: Vec>, - mut inputs: Vec<&'ll Value> + mut inputs: Vec<&'ll Value>, + span: Span, ) -> bool { let mut ext_constraints = vec![]; let mut output_types = vec![]; @@ -102,7 +103,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { let kind = llvm::LLVMGetMDKindIDInContext(self.llcx, key.as_ptr() as *const c_char, key.len() as c_uint); - let val: &'ll Value = self.const_i32(ia.ctxt.outer_expn().as_u32() as i32); + let val: &'ll Value = self.const_i32(span.ctxt().outer_expn().as_u32() as i32); llvm::LLVMSetMetadata(r, kind, llvm::LLVMMDNodeInContext(self.llcx, &val, 1)); diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index 33b50401b22f1..2260747602114 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -96,10 +96,12 @@ pub fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { } // Currently stack probes seem somewhat incompatible with the address - // sanitizer. With asan we're already protected from stack overflow anyway - // so we don't really need stack probes regardless. - if let Some(Sanitizer::Address) = cx.sess().opts.debugging_opts.sanitizer { - return + // sanitizer and thread sanitizer. With asan we're already protected from + // stack overflow anyway so we don't really need stack probes regardless. + match cx.sess().opts.debugging_opts.sanitizer { + Some(Sanitizer::Address) | + Some(Sanitizer::Thread) => return, + _ => {}, } // probestack doesn't play nice either with `-C profile-generate`. @@ -273,25 +275,51 @@ pub fn from_fn_attrs( } else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) { // Special attribute for allocator functions, which can't unwind false - } else if let Some(id) = id { + } else if let Some(_) = id { + // rust-lang/rust#64655, rust-lang/rust#63909: to minimize + // risk associated with changing cases where nounwind + // attribute is attached, this code is deliberately mimicking + // old control flow based on whether `id` is `Some` or `None`. + // + // However, in the long term we should either: + // - fold this into final else (i.e. stop inspecting `id`) + // - or, adopt Rust PR #63909. + // + // see also Rust RFC 2753. + let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - if cx.tcx.is_foreign_item(id) { - // Foreign items like `extern "C" { fn foo(); }` are assumed not to - // unwind - false - } else if sig.abi != Abi::Rust && sig.abi != Abi::RustCall { - // Any items defined in Rust that *don't* have the `extern` ABI are - // defined to not unwind. We insert shims to abort if an unwind - // happens to enforce this. - false - } else { - // Anything else defined in Rust is assumed that it can possibly - // unwind + if sig.abi == Abi::Rust || sig.abi == Abi::RustCall { + // Any Rust method (or `extern "Rust" fn` or `extern + // "rust-call" fn`) is explicitly allowed to unwind + // (unless it has no-unwind attribute, handled above). true + } else { + // Anything else is either: + // + // 1. A foreign item using a non-Rust ABI (like `extern "C" { fn foo(); }`), or + // + // 2. A Rust item using a non-Rust ABI (like `extern "C" fn foo() { ... }`). + // + // Foreign items (case 1) are assumed to not unwind; it is + // UB otherwise. (At least for now; see also + // rust-lang/rust#63909 and Rust RFC 2753.) + // + // Items defined in Rust with non-Rust ABIs (case 2) are also + // not supposed to unwind. Whether this should be enforced + // (versus stating it is UB) and *how* it would be enforced + // is currently under discussion; see rust-lang/rust#58794. + // + // In either case, we mark item as explicitly nounwind. + false } } else { // assume this can possibly unwind, avoiding the application of a // `nounwind` attribute below. + // + // (But: See comments in previous branch. Specifically, it is + // unclear whether there is real value in the assumption this + // can unwind. The conservatism here may just be papering over + // a real problem by making some UB a bit harder to hit.) true }); diff --git a/src/librustc_codegen_llvm/back/archive.rs b/src/librustc_codegen_llvm/back/archive.rs index e3b7cb235c678..68d3f90cd3991 100644 --- a/src/librustc_codegen_llvm/back/archive.rs +++ b/src/librustc_codegen_llvm/back/archive.rs @@ -12,6 +12,7 @@ use crate::llvm::{self, ArchiveKind}; use rustc_codegen_ssa::{METADATA_FILENAME, RLIB_BYTECODE_EXTENSION}; use rustc_codegen_ssa::back::archive::{ArchiveBuilder, find_library}; use rustc::session::Session; +use syntax::symbol::Symbol; struct ArchiveConfig<'a> { pub sess: &'a Session, @@ -109,7 +110,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { /// Adds all of the contents of a native library to this archive. This will /// search in the relevant locations for a library named `name`. - fn add_native_library(&mut self, name: &str) { + fn add_native_library(&mut self, name: Symbol) { let location = find_library(name, &self.config.lib_search_paths, self.config.sess); self.add_archive(&location, |_| false).unwrap_or_else(|e| { diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index 5d3cc0c0a255f..7437b1e3c8a32 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -62,11 +62,13 @@ fn prepare_lto(cgcx: &CodegenContext, }; let exported_symbols = cgcx.exported_symbols .as_ref().expect("needs exported symbols for LTO"); - let mut symbol_white_list = exported_symbols[&LOCAL_CRATE] - .iter() - .filter_map(symbol_filter) - .collect::>(); - let _timer = cgcx.profile_activity("generate_symbol_white_list_for_thinlto"); + let mut symbol_white_list = { + let _timer = cgcx.prof.generic_activity("LLVM_lto_generate_symbol_white_list"); + exported_symbols[&LOCAL_CRATE] + .iter() + .filter_map(symbol_filter) + .collect::>() + }; info!("{} symbols to preserve in this crate", symbol_white_list.len()); // If we're performing LTO for the entire crate graph, then for each of our @@ -95,14 +97,17 @@ fn prepare_lto(cgcx: &CodegenContext, } for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() { - let _timer = cgcx.profile_activity(format!("load: {}", path.display())); let exported_symbols = cgcx.exported_symbols .as_ref().expect("needs exported symbols for LTO"); - symbol_white_list.extend( - exported_symbols[&cnum] - .iter() - .filter_map(symbol_filter)); + { + let _timer = cgcx.prof.generic_activity("LLVM_lto_generate_symbol_white_list"); + symbol_white_list.extend( + exported_symbols[&cnum] + .iter() + .filter_map(symbol_filter)); + } + let _timer = cgcx.prof.generic_activity("LLVM_lto_load_upstream_bitcode"); let archive = ArchiveRO::open(&path).expect("wanted an rlib"); let bytecodes = archive.iter().filter_map(|child| { child.ok().and_then(|c| c.name().map(|name| (name, c))) @@ -111,7 +116,7 @@ fn prepare_lto(cgcx: &CodegenContext, info!("adding bytecode {}", name); let bc_encoded = data.data(); - let (bc, id) = time_ext(cgcx.time_passes, None, &format!("decode {}", name), || { + let (bc, id) = time_ext(cgcx.time_passes, &format!("decode {}", name), || { match DecodedBytecode::new(bc_encoded) { Ok(b) => Ok((b.bytecode(), b.identifier().to_string())), Err(e) => Err(diag_handler.fatal(&e)), @@ -183,14 +188,41 @@ pub(crate) fn prepare_thin( fn fat_lto(cgcx: &CodegenContext, diag_handler: &Handler, - mut modules: Vec>, + modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule, CString)>, symbol_white_list: &[*const libc::c_char]) -> Result, FatalError> { + let _timer = cgcx.prof.generic_activity("LLVM_fat_lto_build_monolithic_module"); info!("going for a fat lto"); + // Sort out all our lists of incoming modules into two lists. + // + // * `serialized_modules` (also and argument to this function) contains all + // modules that are serialized in-memory. + // * `in_memory` contains modules which are already parsed and in-memory, + // such as from multi-CGU builds. + // + // All of `cached_modules` (cached from previous incremental builds) can + // immediately go onto the `serialized_modules` modules list and then we can + // split the `modules` array into these two lists. + let mut in_memory = Vec::new(); + serialized_modules.extend(cached_modules.into_iter().map(|(buffer, wp)| { + info!("pushing cached module {:?}", wp.cgu_name); + (buffer, CString::new(wp.cgu_name).unwrap()) + })); + for module in modules { + match module { + FatLTOInput::InMemory(m) => in_memory.push(m), + FatLTOInput::Serialized { name, buffer } => { + info!("pushing serialized module {:?}", name); + let buffer = SerializedModule::Local(buffer); + serialized_modules.push((buffer, CString::new(name).unwrap())); + } + } + } + // Find the "costliest" module and merge everything into that codegen unit. // All the other modules will be serialized and reparsed into the new // context, so this hopefully avoids serializing and parsing the largest @@ -200,14 +232,8 @@ fn fat_lto(cgcx: &CodegenContext, // file copy operations in the backend work correctly. The only other kind // of module here should be an allocator one, and if your crate is smaller // than the allocator module then the size doesn't really matter anyway. - let costliest_module = modules.iter() + let costliest_module = in_memory.iter() .enumerate() - .filter_map(|(i, module)| { - match module { - FatLTOInput::InMemory(m) => Some((i, m)), - FatLTOInput::Serialized { .. } => None, - } - }) .filter(|&(_, module)| module.kind == ModuleKind::Regular) .map(|(i, module)| { let cost = unsafe { @@ -223,26 +249,14 @@ fn fat_lto(cgcx: &CodegenContext, // re-executing the LTO passes. If that's the case deserialize the first // module and create a linker with it. let module: ModuleCodegen = match costliest_module { - Some((_cost, i)) => { - match modules.remove(i) { - FatLTOInput::InMemory(m) => m, - FatLTOInput::Serialized { .. } => unreachable!(), - } - } + Some((_cost, i)) => in_memory.remove(i), None => { - let pos = modules.iter().position(|m| { - match m { - FatLTOInput::InMemory(_) => false, - FatLTOInput::Serialized { .. } => true, - } - }).expect("must have at least one serialized module"); - let (name, buffer) = match modules.remove(pos) { - FatLTOInput::Serialized { name, buffer } => (name, buffer), - FatLTOInput::InMemory(_) => unreachable!(), - }; + assert!(serialized_modules.len() > 0, "must have at least one serialized module"); + let (buffer, name) = serialized_modules.remove(0); + info!("no in-memory regular modules to choose from, parsing {:?}", name); ModuleCodegen { - module_llvm: ModuleLlvm::parse(cgcx, &name, &buffer, diag_handler)?, - name, + module_llvm: ModuleLlvm::parse(cgcx, &name, buffer.data(), diag_handler)?, + name: name.into_string().unwrap(), kind: ModuleKind::Regular, } } @@ -265,22 +279,13 @@ fn fat_lto(cgcx: &CodegenContext, // and we want to move everything to the same LLVM context. Currently the // way we know of to do that is to serialize them to a string and them parse // them later. Not great but hey, that's why it's "fat" LTO, right? - serialized_modules.extend(modules.into_iter().map(|module| { - match module { - FatLTOInput::InMemory(module) => { - let buffer = ModuleBuffer::new(module.module_llvm.llmod()); - let llmod_id = CString::new(&module.name[..]).unwrap(); - (SerializedModule::Local(buffer), llmod_id) - } - FatLTOInput::Serialized { name, buffer } => { - let llmod_id = CString::new(name).unwrap(); - (SerializedModule::Local(buffer), llmod_id) - } - } - })); - serialized_modules.extend(cached_modules.into_iter().map(|(buffer, wp)| { - (buffer, CString::new(wp.cgu_name).unwrap()) - })); + for module in in_memory { + let buffer = ModuleBuffer::new(module.module_llvm.llmod()); + let llmod_id = CString::new(&module.name[..]).unwrap(); + serialized_modules.push((SerializedModule::Local(buffer), llmod_id)); + } + // Sort the modules to ensure we produce deterministic results. + serialized_modules.sort_by(|module1, module2| module1.1.cmp(&module2.1)); // For all serialized bitcode files we parse them and link them in as we did // above, this is all mostly handled in C++. Like above, though, we don't @@ -288,8 +293,9 @@ fn fat_lto(cgcx: &CodegenContext, // save and persist everything with the original module. let mut linker = Linker::new(llmod); for (bc_decoded, name) in serialized_modules { + let _timer = cgcx.prof.generic_activity("LLVM_fat_lto_link_module"); info!("linking {:?}", name); - time_ext(cgcx.time_passes, None, &format!("ll link {:?}", name), || { + time_ext(cgcx.time_passes, &format!("ll link {:?}", name), || { let data = bc_decoded.data(); linker.add(&data).map_err(|()| { let msg = format!("failed to load bc of {:?}", name); @@ -389,6 +395,7 @@ fn thin_lto(cgcx: &CodegenContext, symbol_white_list: &[*const libc::c_char]) -> Result<(Vec>, Vec), FatalError> { + let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_global_analysis"); unsafe { info!("going for that thin, thin LTO"); @@ -539,7 +546,7 @@ pub(crate) fn run_pass_manager(cgcx: &CodegenContext, llvm::LLVMRustAddAnalysisPasses(module.module_llvm.tm, pm, module.module_llvm.llmod()); if config.verify_llvm_ir { - let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _); + let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr().cast()); llvm::LLVMRustAddPass(pm, pass.unwrap()); } @@ -574,16 +581,16 @@ pub(crate) fn run_pass_manager(cgcx: &CodegenContext, // We always generate bitcode through ThinLTOBuffers, // which do not support anonymous globals if config.bitcode_needed() { - let pass = llvm::LLVMRustFindAndCreatePass("name-anon-globals\0".as_ptr() as *const _); + let pass = llvm::LLVMRustFindAndCreatePass("name-anon-globals\0".as_ptr().cast()); llvm::LLVMRustAddPass(pm, pass.unwrap()); } if config.verify_llvm_ir { - let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _); + let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr().cast()); llvm::LLVMRustAddPass(pm, pass.unwrap()); } - time_ext(cgcx.time_passes, None, "LTO passes", || + time_ext(cgcx.time_passes, "LTO passes", || llvm::LLVMRunPassManager(pm, module.module_llvm.llmod())); llvm::LLVMDisposePassManager(pm); @@ -602,16 +609,6 @@ impl ModuleBuffer { llvm::LLVMRustModuleBufferCreate(m) }) } - - pub fn parse<'a>( - &self, - name: &str, - cx: &'a llvm::Context, - handler: &Handler, - ) -> Result<&'a llvm::Module, FatalError> { - let name = CString::new(name).unwrap(); - parse_module(cx, &name, self.data(), handler) - } } impl ModuleBufferMethods for ModuleBuffer { @@ -724,7 +721,7 @@ pub unsafe fn optimize_thin_module( // Like with "fat" LTO, get some better optimizations if landing pads // are disabled by removing all landing pads. if cgcx.no_landing_pads { - let _timer = cgcx.profile_activity("LLVM_remove_landing_pads"); + let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_remove_landing_pads"); llvm::LLVMRustMarkAllFunctionsNounwind(llmod); save_temp_bitcode(&cgcx, &module, "thin-lto-after-nounwind"); } @@ -737,26 +734,41 @@ pub unsafe fn optimize_thin_module( // // You can find some more comments about these functions in the LLVM // bindings we've got (currently `PassWrapper.cpp`) - if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod) { - let msg = "failed to prepare thin LTO module"; - return Err(write::llvm_err(&diag_handler, msg)) + { + let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_rename"); + if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod) { + let msg = "failed to prepare thin LTO module"; + return Err(write::llvm_err(&diag_handler, msg)) + } + save_temp_bitcode(cgcx, &module, "thin-lto-after-rename"); } - save_temp_bitcode(cgcx, &module, "thin-lto-after-rename"); - if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) { - let msg = "failed to prepare thin LTO module"; - return Err(write::llvm_err(&diag_handler, msg)) + + { + let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_resolve_weak"); + if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) { + let msg = "failed to prepare thin LTO module"; + return Err(write::llvm_err(&diag_handler, msg)) + } + save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve"); } - save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve"); - if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) { - let msg = "failed to prepare thin LTO module"; - return Err(write::llvm_err(&diag_handler, msg)) + + { + let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_internalize"); + if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) { + let msg = "failed to prepare thin LTO module"; + return Err(write::llvm_err(&diag_handler, msg)) + } + save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize"); } - save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize"); - if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod) { - let msg = "failed to prepare thin LTO module"; - return Err(write::llvm_err(&diag_handler, msg)) + + { + let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_import"); + if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod) { + let msg = "failed to prepare thin LTO module"; + return Err(write::llvm_err(&diag_handler, msg)) + } + save_temp_bitcode(cgcx, &module, "thin-lto-after-import"); } - save_temp_bitcode(cgcx, &module, "thin-lto-after-import"); // Ok now this is a bit unfortunate. This is also something you won't // find upstream in LLVM's ThinLTO passes! This is a hack for now to @@ -787,18 +799,24 @@ pub unsafe fn optimize_thin_module( // not too much) but for now at least gets LLVM to emit valid DWARF (or // so it appears). Hopefully we can remove this once upstream bugs are // fixed in LLVM. - llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1); - save_temp_bitcode(cgcx, &module, "thin-lto-after-patch"); + { + let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_patch_debuginfo"); + llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1); + save_temp_bitcode(cgcx, &module, "thin-lto-after-patch"); + } // Alright now that we've done everything related to the ThinLTO // analysis it's time to run some optimizations! Here we use the same // `run_pass_manager` as the "fat" LTO above except that we tell it to // populate a thin-specific pass manager, which presumably LLVM treats a // little differently. - info!("running thin lto passes over {}", module.name); - let config = cgcx.config(module.kind); - run_pass_manager(cgcx, &module, config, true); - save_temp_bitcode(cgcx, &module, "thin-lto-after-pm"); + { + let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_optimize"); + info!("running thin lto passes over {}", module.name); + let config = cgcx.config(module.kind); + run_pass_manager(cgcx, &module, config, true); + save_temp_bitcode(cgcx, &module, "thin-lto-after-pm"); + } } Ok(module) } @@ -847,7 +865,7 @@ fn module_name_to_str(c_str: &CStr) -> &str { bug!("Encountered non-utf8 LLVM module name `{}`: {}", c_str.to_string_lossy(), e)) } -fn parse_module<'a>( +pub fn parse_module<'a>( cx: &'a llvm::Context, name: &CStr, data: &[u8], diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 253110dcb34c0..52f3a1cbb5c30 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -221,8 +221,8 @@ impl<'a> DiagnosticHandlers<'a> { llcx: &'a llvm::Context) -> Self { let data = Box::into_raw(Box::new((cgcx, handler))); unsafe { - llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data as *mut _); - llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, data as *mut _); + llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data.cast()); + llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, data.cast()); } DiagnosticHandlers { data, llcx } } @@ -306,6 +306,8 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext, config: &ModuleConfig) -> Result<(), FatalError> { + let _timer = cgcx.prof.generic_activity("LLVM_module_optimize"); + let llmod = module.module_llvm.llmod(); let llcx = &*module.module_llvm.llcx; let tm = &*module.module_llvm.tm; @@ -423,18 +425,16 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext, // Finally, run the actual optimization passes { - let _timer = cgcx.profile_activity("LLVM_function_passes"); + let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_function_passes"); time_ext(config.time_passes, - None, &format!("llvm function passes [{}]", module_name.unwrap()), || { llvm::LLVMRustRunFunctionPassManager(fpm, llmod) }); } { - let _timer = cgcx.profile_activity("LLVM_module_passes"); + let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_module_passes"); time_ext(config.time_passes, - None, &format!("llvm module passes [{}]", module_name.unwrap()), || { llvm::LLVMRunPassManager(mpm, llmod) @@ -454,7 +454,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, config: &ModuleConfig) -> Result { - let _timer = cgcx.profile_activity("codegen"); + let _timer = cgcx.prof.generic_activity("LLVM_module_codegen"); { let llmod = module.module_llvm.llmod(); let llcx = &*module.module_llvm.llcx; @@ -505,12 +505,12 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, if write_bc || config.emit_bc_compressed || config.embed_bitcode { - let _timer = cgcx.profile_activity("LLVM_make_bitcode"); + let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_make_bitcode"); let thin = ThinBuffer::new(llmod); let data = thin.data(); if write_bc { - let _timer = cgcx.profile_activity("LLVM_emit_bitcode"); + let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_bitcode"); if let Err(e) = fs::write(&bc_out, data) { let msg = format!("failed to write bytecode to {}: {}", bc_out.display(), e); diag_handler.err(&msg); @@ -518,12 +518,13 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, } if config.embed_bitcode { - let _timer = cgcx.profile_activity("LLVM_embed_bitcode"); + let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_embed_bitcode"); embed_bitcode(cgcx, llcx, llmod, Some(data)); } if config.emit_bc_compressed { - let _timer = cgcx.profile_activity("LLVM_compress_bitcode"); + let _timer = + cgcx.prof.generic_activity("LLVM_module_codegen_emit_compressed_bitcode"); let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION); let data = bytecode::encode(&module.name, data); if let Err(e) = fs::write(&dst, data) { @@ -535,10 +536,10 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, embed_bitcode(cgcx, llcx, llmod, None); } - time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()), + time_ext(config.time_passes, &format!("codegen passes [{}]", module_name.unwrap()), || -> Result<(), FatalError> { if config.emit_ir { - let _timer = cgcx.profile_activity("LLVM_emit_ir"); + let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_ir"); let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name); let out_c = path_to_c_string(&out); @@ -585,7 +586,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, } if config.emit_asm || asm_to_obj { - let _timer = cgcx.profile_activity("LLVM_emit_asm"); + let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_asm"); let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); // We can't use the same module for asm and binary output, because that triggers @@ -603,13 +604,13 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, } if write_obj { - let _timer = cgcx.profile_activity("LLVM_emit_obj"); + let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_obj"); with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file(diag_handler, tm, cpm, llmod, &obj_out, llvm::FileType::ObjectFile) })?; } else if asm_to_obj { - let _timer = cgcx.profile_activity("LLVM_asm_to_obj"); + let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_asm_to_obj"); let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); run_assembler(cgcx, diag_handler, &assembly, &obj_out); @@ -669,7 +670,7 @@ unsafe fn embed_bitcode(cgcx: &CodegenContext, let llglobal = llvm::LLVMAddGlobal( llmod, common::val_ty(llconst), - "rustc.embedded.module\0".as_ptr() as *const _, + "rustc.embedded.module\0".as_ptr().cast(), ); llvm::LLVMSetInitializer(llglobal, llconst); @@ -681,7 +682,7 @@ unsafe fn embed_bitcode(cgcx: &CodegenContext, } else { ".llvmbc\0" }; - llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _); + llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); llvm::LLVMSetGlobalConstant(llglobal, llvm::True); @@ -689,7 +690,7 @@ unsafe fn embed_bitcode(cgcx: &CodegenContext, let llglobal = llvm::LLVMAddGlobal( llmod, common::val_ty(llconst), - "rustc.embedded.cmdline\0".as_ptr() as *const _, + "rustc.embedded.cmdline\0".as_ptr().cast(), ); llvm::LLVMSetInitializer(llglobal, llconst); let section = if is_apple { @@ -697,7 +698,7 @@ unsafe fn embed_bitcode(cgcx: &CodegenContext, } else { ".llvmcmd\0" }; - llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _); + llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); } @@ -839,7 +840,7 @@ fn create_msvc_imps( for (imp_name, val) in globals { let imp = llvm::LLVMAddGlobal(llmod, i8p_ty, - imp_name.as_ptr() as *const _); + imp_name.as_ptr().cast()); llvm::LLVMSetInitializer(imp, consts::ptrcast(val, i8p_ty)); llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage); } diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 21c19e167cfbe..bd7d0d4017dce 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -103,7 +103,12 @@ pub fn iter_globals(llmod: &'ll llvm::Module) -> ValueIter<'ll> { } } -pub fn compile_codegen_unit(tcx: TyCtxt<'tcx>, cgu_name: InternedString) { +pub fn compile_codegen_unit( + tcx: TyCtxt<'tcx>, + cgu_name: InternedString, + tx_to_llvm_workers: &std::sync::mpsc::Sender>, +) { + let prof_timer = tcx.prof.generic_activity("codegen_module"); let start_time = Instant::now(); let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); @@ -115,13 +120,14 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'tcx>, cgu_name: InternedString) { dep_graph::hash_result, ); let time_to_codegen = start_time.elapsed(); + drop(prof_timer); // We assume that the cost to run LLVM on a CGU is proportional to // the time we needed for codegenning it. let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64; - submit_codegened_module_to_llvm(&LlvmCodegenBackend(()), tcx, module, cost); + submit_codegened_module_to_llvm(&LlvmCodegenBackend(()), tx_to_llvm_workers, module, cost); fn module_codegen( tcx: TyCtxt<'_>, diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index 894e5c2fd3d93..71a6067fd48a1 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -5,7 +5,6 @@ use crate::context::CodegenCx; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; -use syntax::symbol::LocalInternedString; use rustc_codegen_ssa::common::{IntPredicate, TypeKind, RealPredicate}; use rustc_codegen_ssa::MemFlags; use libc::{c_uint, c_char}; @@ -24,6 +23,7 @@ use std::ffi::CStr; use std::ops::{Deref, Range}; use std::ptr; use std::iter::TrustedLen; +use syntax::symbol::Symbol; // All Builders must have an llfn associated with them #[must_use] @@ -324,7 +324,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { use syntax::ast::UintTy::*; use rustc::ty::{Int, Uint}; - let new_sty = match ty.sty { + let new_kind = match ty.kind { Int(Isize) => Int(self.tcx.sess.target.isize_ty), Uint(Usize) => Uint(self.tcx.sess.target.usize_ty), ref t @ Uint(_) | ref t @ Int(_) => t.clone(), @@ -332,7 +332,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { }; let name = match oop { - OverflowOp::Add => match new_sty { + OverflowOp::Add => match new_kind { Int(I8) => "llvm.sadd.with.overflow.i8", Int(I16) => "llvm.sadd.with.overflow.i16", Int(I32) => "llvm.sadd.with.overflow.i32", @@ -347,7 +347,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { _ => unreachable!(), }, - OverflowOp::Sub => match new_sty { + OverflowOp::Sub => match new_kind { Int(I8) => "llvm.ssub.with.overflow.i8", Int(I16) => "llvm.ssub.with.overflow.i16", Int(I32) => "llvm.ssub.with.overflow.i32", @@ -362,7 +362,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { _ => unreachable!(), }, - OverflowOp::Mul => match new_sty { + OverflowOp::Mul => match new_kind { Int(I8) => "llvm.smul.with.overflow.i8", Int(I16) => "llvm.smul.with.overflow.i16", Int(I32) => "llvm.smul.with.overflow.i32", @@ -387,23 +387,17 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { ) } - fn alloca(&mut self, ty: &'ll Type, name: &str, align: Align) -> &'ll Value { + fn alloca(&mut self, ty: &'ll Type, align: Align) -> &'ll Value { let mut bx = Builder::with_cx(self.cx); bx.position_at_start(unsafe { llvm::LLVMGetFirstBasicBlock(self.llfn()) }); - bx.dynamic_alloca(ty, name, align) + bx.dynamic_alloca(ty, align) } - fn dynamic_alloca(&mut self, ty: &'ll Type, name: &str, align: Align) -> &'ll Value { + fn dynamic_alloca(&mut self, ty: &'ll Type, align: Align) -> &'ll Value { unsafe { - let alloca = if name.is_empty() { - llvm::LLVMBuildAlloca(self.llbuilder, ty, UNNAMED) - } else { - let name = SmallCStr::new(name); - llvm::LLVMBuildAlloca(self.llbuilder, ty, - name.as_ptr()) - }; + let alloca = llvm::LLVMBuildAlloca(self.llbuilder, ty, UNNAMED); llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint); alloca } @@ -412,16 +406,9 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn array_alloca(&mut self, ty: &'ll Type, len: &'ll Value, - name: &str, align: Align) -> &'ll Value { unsafe { - let alloca = if name.is_empty() { - llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len, UNNAMED) - } else { - let name = SmallCStr::new(name); - llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len, - name.as_ptr()) - }; + let alloca = llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len, UNNAMED); llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint); alloca } @@ -561,7 +548,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size); cg_elem.val.store(&mut body_bx, - PlaceRef::new_sized(current, cg_elem.layout, align)); + PlaceRef::new_sized_aligned(current, cg_elem.layout, align)); let next = body_bx.inbounds_gep(current, &[self.const_usize(1)]); body_bx.br(header_bx.llbb()); @@ -1082,8 +1069,8 @@ impl StaticBuilderMethods for Builder<'a, 'll, 'tcx> { fn static_panic_msg( &mut self, - msg: Option, - filename: LocalInternedString, + msg: Option, + filename: Symbol, line: Self::Value, col: Self::Value, kind: &str, diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs index 2c0a6f631b739..35d5107842d5b 100644 --- a/src/librustc_codegen_llvm/callee.rs +++ b/src/librustc_codegen_llvm/callee.rs @@ -37,7 +37,7 @@ pub fn get_fn( return llfn; } - let sym = tcx.symbol_name(instance).as_str(); + let sym = tcx.symbol_name(instance).name.as_str(); debug!("get_fn({:?}: {:?}) => {}", instance, sig, sym); // Create a fn pointer with the substituted signature. diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs index b0c94a139be08..6fbea9646b8a9 100644 --- a/src/librustc_codegen_llvm/common.rs +++ b/src/librustc_codegen_llvm/common.rs @@ -17,7 +17,7 @@ use rustc_codegen_ssa::mir::place::PlaceRef; use libc::{c_uint, c_char}; -use syntax::symbol::LocalInternedString; +use syntax::symbol::Symbol; use syntax::ast::Mutability; pub use crate::context::CodegenCx; @@ -122,7 +122,7 @@ impl CodegenCx<'ll, 'tcx> { fn const_cstr( &self, - s: LocalInternedString, + s: Symbol, null_terminated: bool, ) -> &'ll Value { unsafe { @@ -130,9 +130,10 @@ impl CodegenCx<'ll, 'tcx> { return llval; } + let s_str = s.as_str(); let sc = llvm::LLVMConstStringInContext(self.llcx, - s.as_ptr() as *const c_char, - s.len() as c_uint, + s_str.as_ptr() as *const c_char, + s_str.len() as c_uint, !null_terminated as Bool); let sym = self.generate_local_symbol_name("str"); let g = self.define_global(&sym[..], self.val_ty(sc)).unwrap_or_else(||{ @@ -147,8 +148,8 @@ impl CodegenCx<'ll, 'tcx> { } } - pub fn const_str_slice(&self, s: LocalInternedString) -> &'ll Value { - let len = s.len(); + pub fn const_str_slice(&self, s: Symbol) -> &'ll Value { + let len = s.as_str().len(); let cs = consts::ptrcast(self.const_cstr(s, false), self.type_ptr_to(self.layout_of(self.tcx.mk_str()).llvm_type(self))); self.const_fat_ptr(cs, self.const_usize(len as u64)) @@ -333,16 +334,22 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { offset: Size, ) -> PlaceRef<'tcx, &'ll Value> { assert_eq!(alloc.align, layout.align.abi); - let init = const_alloc_to_llvm(self, alloc); - let base_addr = self.static_addr_of(init, alloc.align, None); - - let llval = unsafe { llvm::LLVMConstInBoundsGEP( - self.const_bitcast(base_addr, self.type_i8p()), - &self.const_usize(offset.bytes()), - 1, - )}; - let llval = self.const_bitcast(llval, self.type_ptr_to(layout.llvm_type(self))); - PlaceRef::new_sized(llval, layout, alloc.align) + let llty = self.type_ptr_to(layout.llvm_type(self)); + let llval = if layout.size == Size::ZERO { + let llval = self.const_usize(alloc.align.bytes()); + unsafe { llvm::LLVMConstIntToPtr(llval, llty) } + } else { + let init = const_alloc_to_llvm(self, alloc); + let base_addr = self.static_addr_of(init, alloc.align, None); + + let llval = unsafe { llvm::LLVMConstInBoundsGEP( + self.const_bitcast(base_addr, self.type_i8p()), + &self.const_usize(offset.bytes()), + 1, + )}; + self.const_bitcast(llval, llty) + }; + PlaceRef::new_sized(llval, layout) } fn const_ptrcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value { diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs index 0077df3cf5eea..d4df5b4a804ef 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/src/librustc_codegen_llvm/consts.rs @@ -11,12 +11,11 @@ use rustc::mir::interpret::{ConstValue, Allocation, read_target_uint, Pointer, ErrorHandled, GlobalId}; use rustc::mir::mono::MonoItem; use rustc::hir::Node; -use syntax_pos::Span; use rustc_target::abi::HasDataLayout; -use syntax::symbol::sym; -use syntax_pos::symbol::LocalInternedString; use rustc::ty::{self, Ty, Instance}; use rustc_codegen_ssa::traits::*; +use syntax::symbol::{Symbol, sym}; +use syntax_pos::Span; use rustc::ty::layout::{self, Size, Align, LayoutOf}; @@ -25,21 +24,31 @@ use rustc::hir::{self, CodegenFnAttrs, CodegenFnAttrFlags}; use std::ffi::{CStr, CString}; pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value { - let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1); + let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1); let dl = cx.data_layout(); let pointer_size = dl.pointer_size.bytes() as usize; let mut next_offset = 0; - for &(offset, ((), alloc_id)) in alloc.relocations.iter() { + for &(offset, ((), alloc_id)) in alloc.relocations().iter() { let offset = offset.bytes(); assert_eq!(offset as usize as u64, offset); let offset = offset as usize; if offset > next_offset { - llvals.push(cx.const_bytes(&alloc.bytes[next_offset..offset])); + // This `inspect` is okay since we have checked that it is not within a relocation, it + // is within the bounds of the allocation, and it doesn't affect interpreter execution + // (we inspect the result after interpreter execution). Any undef byte is replaced with + // some arbitrary byte value. + // + // FIXME: relay undef bytes to codegen as undef const bytes + let bytes = alloc.inspect_with_undef_and_ptr_outside_interpreter(next_offset..offset); + llvals.push(cx.const_bytes(bytes)); } let ptr_offset = read_target_uint( dl.endian, - &alloc.bytes[offset..(offset + pointer_size)], + // This `inspect` is okay since it is within the bounds of the allocation, it doesn't + // affect interpreter execution (we inspect the result after interpreter execution), + // and we properly interpret the relocation as a relocation pointer offset. + alloc.inspect_with_undef_and_ptr_outside_interpreter(offset..(offset + pointer_size)), ).expect("const_alloc_to_llvm: could not read relocation pointer") as u64; llvals.push(cx.scalar_to_backend( Pointer::new(alloc_id, Size::from_bytes(ptr_offset)).into(), @@ -51,8 +60,16 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll )); next_offset = offset + pointer_size; } - if alloc.bytes.len() >= next_offset { - llvals.push(cx.const_bytes(&alloc.bytes[next_offset ..])); + if alloc.len() >= next_offset { + let range = next_offset..alloc.len(); + // This `inspect` is okay since we have check that it is after all relocations, it is + // within the bounds of the allocation, and it doesn't affect interpreter execution (we + // inspect the result after interpreter execution). Any undef byte is replaced with some + // arbitrary byte value. + // + // FIXME: relay undef bytes to codegen as undef const bytes + let bytes = alloc.inspect_with_undef_and_ptr_outside_interpreter(range); + llvals.push(cx.const_bytes(bytes)); } cx.const_struct(&llvals, true) @@ -104,10 +121,11 @@ fn check_and_apply_linkage( cx: &CodegenCx<'ll, 'tcx>, attrs: &CodegenFnAttrs, ty: Ty<'tcx>, - sym: LocalInternedString, + sym: Symbol, span: Span ) -> &'ll Value { let llty = cx.layout_of(ty).llvm_type(cx); + let sym = sym.as_str(); if let Some(linkage) = attrs.linkage { debug!("get_static: sym={} linkage={:?}", sym, linkage); @@ -116,7 +134,7 @@ fn check_and_apply_linkage( // extern "C" fn() from being non-null, so we can't just declare a // static and call it a day. Some linkages (like weak) will make it such // that the static actually has a null value. - let llty2 = if let ty::RawPtr(ref mt) = ty.sty { + let llty2 = if let ty::RawPtr(ref mt) = ty.kind { cx.layout_of(mt.ty).llvm_type(cx) } else { cx.sess().span_fatal( @@ -203,7 +221,7 @@ impl CodegenCx<'ll, 'tcx> { def_id); let ty = instance.ty(self.tcx); - let sym = self.tcx.symbol_name(instance).as_str(); + let sym = self.tcx.symbol_name(instance).name.as_symbol(); debug!("get_static: sym={} instance={:?}", sym, instance); @@ -212,13 +230,14 @@ impl CodegenCx<'ll, 'tcx> { let llty = self.layout_of(ty).llvm_type(self); let (g, attrs) = match self.tcx.hir().get(id) { Node::Item(&hir::Item { - ref attrs, span, node: hir::ItemKind::Static(..), .. + ref attrs, span, kind: hir::ItemKind::Static(..), .. }) => { - if self.get_declared_value(&sym[..]).is_some() { + let sym_str = sym.as_str(); + if self.get_declared_value(&sym_str).is_some() { span_bug!(span, "Conflicting symbol names for static?"); } - let g = self.define_global(&sym[..], llty).unwrap(); + let g = self.define_global(&sym_str, llty).unwrap(); if !self.tcx.is_reachable_non_generic(def_id) { unsafe { @@ -230,7 +249,7 @@ impl CodegenCx<'ll, 'tcx> { } Node::ForeignItem(&hir::ForeignItem { - ref attrs, span, node: hir::ForeignItemKind::Static(..), .. + ref attrs, span, kind: hir::ForeignItemKind::Static(..), .. }) => { let fn_attrs = self.tcx.codegen_fn_attrs(def_id); (check_and_apply_linkage(&self, &fn_attrs, ty, sym, span), attrs) @@ -437,7 +456,23 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { // // We could remove this hack whenever we decide to drop macOS 10.10 support. if self.tcx.sess.target.target.options.is_like_osx { - let sect_name = if alloc.bytes.iter().all(|b| *b == 0) { + assert_eq!(alloc.relocations().len(), 0); + + let is_zeroed = { + // Treats undefined bytes as if they were defined with the byte value that + // happens to be currently assigned in mir. This is valid since reading + // undef bytes may yield arbitrary values. + // + // FIXME: ignore undef bytes even with representation `!= 0`. + // + // The `inspect` method is okay here because we checked relocations, and + // because we are doing this access to inspect the final interpreter state + // (not as part of the interpreter execution). + alloc.inspect_with_undef_and_ptr_outside_interpreter(0..alloc.len()) + .iter() + .all(|b| *b == 0) + }; + let sect_name = if is_zeroed { CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_bss\0") } else { CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_data\0") @@ -453,19 +488,26 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { if let Some(section) = attrs.link_section { let section = llvm::LLVMMDStringInContext( self.llcx, - section.as_str().as_ptr() as *const _, + section.as_str().as_ptr().cast(), section.as_str().len() as c_uint, ); + assert!(alloc.relocations().is_empty()); + + // The `inspect` method is okay here because we checked relocations, and + // because we are doing this access to inspect the final interpreter state (not + // as part of the interpreter execution). + let bytes = alloc.inspect_with_undef_and_ptr_outside_interpreter( + 0..alloc.len()); let alloc = llvm::LLVMMDStringInContext( self.llcx, - alloc.bytes.as_ptr() as *const _, - alloc.bytes.len() as c_uint, + bytes.as_ptr().cast(), + bytes.len() as c_uint, ); let data = [section, alloc]; let meta = llvm::LLVMMDNodeInContext(self.llcx, data.as_ptr(), 2); llvm::LLVMAddNamedMetadataOperand( self.llmod, - "wasm.custom_sections\0".as_ptr() as *const _, + "wasm.custom_sections\0".as_ptr().cast(), meta, ); } diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index a2aaaddf0931c..7ca226914a5a4 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -29,7 +29,7 @@ use std::cell::{Cell, RefCell}; use std::iter; use std::str; use std::sync::Arc; -use syntax::symbol::LocalInternedString; +use syntax::symbol::Symbol; use syntax::source_map::{DUMMY_SP, Span}; use crate::abi::Abi; @@ -52,7 +52,7 @@ pub struct CodegenCx<'ll, 'tcx> { pub vtables: RefCell, Option>), &'ll Value>>, /// Cache of constant strings, - pub const_cstr_cache: RefCell>, + pub const_cstr_cache: RefCell>, /// Reverse-direction for const ptrs cast from globals. /// Key is a Value holding a *T, @@ -211,7 +211,7 @@ pub unsafe fn create_module( // If skipping the PLT is enabled, we need to add some module metadata // to ensure intrinsic calls don't use it. if !sess.needs_plt() { - let avoid_plt = "RtLibUseGOT\0".as_ptr() as *const _; + let avoid_plt = "RtLibUseGOT\0".as_ptr().cast(); llvm::LLVMRustAddModuleFlag(llmod, avoid_plt, 1); } @@ -537,6 +537,7 @@ impl CodegenCx<'b, 'tcx> { ifn!("llvm.trap", fn() -> void); ifn!("llvm.debugtrap", fn() -> void); ifn!("llvm.frameaddress", fn(t_i32) -> i8p); + ifn!("llvm.sideeffect", fn() -> void); ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32); ifn!("llvm.powi.v2f32", fn(t_v2f32, t_i32) -> t_v2f32); diff --git a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs index 8b3ed5b0c623a..bdb7467a1010c 100644 --- a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs +++ b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs @@ -11,8 +11,8 @@ use libc::c_uint; use syntax_pos::Pos; -use rustc_data_structures::bit_set::BitSet; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::{Idx, IndexVec}; use syntax_pos::BytePos; diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/src/librustc_codegen_llvm/debuginfo/gdb.rs index 04c9e93c7a527..9ed1c1730a697 100644 --- a/src/librustc_codegen_llvm/debuginfo/gdb.rs +++ b/src/librustc_codegen_llvm/debuginfo/gdb.rs @@ -37,7 +37,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx<'ll, '_>) let section_var = unsafe { llvm::LLVMGetNamedGlobal(cx.llmod, - c_section_var_name.as_ptr() as *const _) + c_section_var_name.as_ptr().cast()) }; section_var.unwrap_or_else(|| { @@ -52,7 +52,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx<'ll, '_>) llvm_type).unwrap_or_else(||{ bug!("symbol `{}` is already defined", section_var_name) }); - llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _); + llvm::LLVMSetSection(section_var, section_name.as_ptr().cast()); llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); llvm::LLVMSetUnnamedAddr(section_var, llvm::True); diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 51e789b17880a..438a660b8a867 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -6,7 +6,7 @@ use super::utils::{debug_context, DIB, span_start, get_namespace_for_item, create_DIArray, is_node_local_to_unit}; use super::namespace::mangled_name_of_instance; use super::type_names::compute_debuginfo_type_name; -use super::{CrateDebugContext}; +use super::CrateDebugContext; use crate::abi; use crate::value::Value; use rustc_codegen_ssa::traits::*; @@ -30,7 +30,7 @@ use rustc::ty::Instance; use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; use rustc::ty::layout::{self, Align, Integer, IntegerExt, LayoutOf, PrimitiveExt, Size, TyLayout, VariantIdx}; -use rustc::ty::subst::UnpackedKind; +use rustc::ty::subst::{GenericArgKind, SubstsRef}; use rustc::session::config::{self, DebugInfo}; use rustc::util::nodemap::FxHashMap; use rustc_fs_util::path_to_c_string; @@ -187,7 +187,7 @@ impl TypeMap<'ll, 'tcx> { // The hasher we are using to generate the UniqueTypeId. We want // something that provides more than the 64 bits of the DefaultHasher. - let mut hasher = StableHasher::::new(); + let mut hasher = StableHasher::new(); let mut hcx = cx.tcx.create_stable_hashing_context(); let type_ = cx.tcx.erase_regions(&type_); hcx.while_hashing_spans(false, |hcx| { @@ -195,7 +195,7 @@ impl TypeMap<'ll, 'tcx> { type_.hash_stable(hcx, &mut hasher); }); }); - let unique_type_id = hasher.finish().to_hex(); + let unique_type_id = hasher.finish::().to_hex(); let key = self.unique_id_interner.intern(&unique_type_id); self.type_to_unique_id.insert(type_, UniqueTypeId(key)); @@ -340,7 +340,7 @@ fn fixed_vec_metadata( let (size, align) = cx.size_and_align_of(array_or_slice_type); - let upper_bound = match array_or_slice_type.sty { + let upper_bound = match array_or_slice_type.kind { ty::Array(_, len) => len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong, _ => -1 }; @@ -427,7 +427,7 @@ fn subroutine_type_metadata( let signature_metadata: Vec<_> = iter::once( // return type - match signature.output().sty { + match signature.output().kind { ty::Tuple(ref tys) if tys.is_empty() => None, _ => Some(type_metadata(cx, signature.output(), span)) } @@ -466,7 +466,7 @@ fn trait_pointer_metadata( // type is assigned the correct name, size, namespace, and source location. // However, it does not describe the trait's methods. - let containing_scope = match trait_type.sty { + let containing_scope = match trait_type.kind { ty::Dynamic(ref data, ..) => data.principal_def_id().map(|did| get_namespace_for_item(cx, did)), _ => { @@ -563,7 +563,7 @@ pub fn type_metadata( debug!("type_metadata: {:?}", t); let ptr_metadata = |ty: Ty<'tcx>| { - match ty.sty { + match ty.kind { ty::Slice(typ) => { Ok(vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span)) } @@ -591,7 +591,7 @@ pub fn type_metadata( } }; - let MetadataCreationResult { metadata, already_stored_in_typemap } = match t.sty { + let MetadataCreationResult { metadata, already_stored_in_typemap } = match t.kind { ty::Never | ty::Bool | ty::Char | @@ -682,17 +682,20 @@ pub fn type_metadata( } ty::Closure(def_id, substs) => { - let upvar_tys : Vec<_> = substs.upvar_tys(def_id, cx.tcx).collect(); + let upvar_tys : Vec<_> = substs.as_closure().upvar_tys(def_id, cx.tcx).collect(); + let containing_scope = get_namespace_for_item(cx, def_id); prepare_tuple_metadata(cx, t, &upvar_tys, unique_type_id, - usage_site_span).finalize(cx) + usage_site_span, + Some(containing_scope)).finalize(cx) } ty::Generator(def_id, substs, _) => { - let upvar_tys : Vec<_> = substs.prefix_tys(def_id, cx.tcx).map(|t| { - cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t) - }).collect(); + let upvar_tys : Vec<_> = substs + .as_generator().prefix_tys(def_id, cx.tcx).map(|t| { + cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t) + }).collect(); prepare_enum_metadata(cx, t, def_id, @@ -728,7 +731,8 @@ pub fn type_metadata( t, &tys, unique_type_id, - usage_site_span).finalize(cx) + usage_site_span, + NO_SCOPE_METADATA).finalize(cx) } _ => { bug!("debuginfo: unexpected type in type_metadata: {:?}", t) @@ -832,7 +836,7 @@ fn file_metadata_raw(cx: &CodegenCx<'ll, '_>, fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { debug!("basic_type_metadata: {:?}", t); - let (name, encoding) = match t.sty { + let (name, encoding) = match t.kind { ty::Never => ("!", DW_ATE_unsigned), ty::Tuple(ref elements) if elements.is_empty() => ("()", DW_ATE_unsigned), @@ -957,9 +961,9 @@ pub fn compile_unit_metadata( file_metadata, producer.as_ptr(), tcx.sess.opts.optimize != config::OptLevel::No, - flags.as_ptr() as *const _, + flags.as_ptr().cast(), 0, - split_name.as_ptr() as *const _, + split_name.as_ptr().cast(), kind); if tcx.sess.opts.debugging_opts.profile { @@ -988,7 +992,7 @@ pub fn compile_unit_metadata( if tcx.sess.opts.target_triple.triple().starts_with("wasm32") { let name_metadata = llvm::LLVMMDStringInContext( debug_context.llcontext, - rustc_producer.as_ptr() as *const _, + rustc_producer.as_ptr().cast(), rustc_producer.as_bytes().len() as c_uint, ); llvm::LLVMAddNamedMetadataOperand( @@ -1142,7 +1146,7 @@ fn prepare_struct_metadata( ) -> RecursiveTypeDescription<'ll, 'tcx> { let struct_name = compute_debuginfo_type_name(cx.tcx, struct_type, false); - let (struct_def_id, variant) = match struct_type.sty { + let (struct_def_id, variant) = match struct_type.kind { ty::Adt(def, _) => (def.did, def.non_enum_variant()), _ => bug!("prepare_struct_metadata on a non-ADT") }; @@ -1205,6 +1209,7 @@ fn prepare_tuple_metadata( component_types: &[Ty<'tcx>], unique_type_id: UniqueTypeId, span: Span, + containing_scope: Option<&'ll DIScope>, ) -> RecursiveTypeDescription<'ll, 'tcx> { let tuple_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false); @@ -1212,7 +1217,7 @@ fn prepare_tuple_metadata( tuple_type, &tuple_name[..], unique_type_id, - NO_SCOPE_METADATA); + containing_scope); create_and_register_recursive_type_forward_declaration( cx, @@ -1264,7 +1269,7 @@ fn prepare_union_metadata( ) -> RecursiveTypeDescription<'ll, 'tcx> { let union_name = compute_debuginfo_type_name(cx.tcx, union_type, false); - let (union_def_id, variant) = match union_type.sty { + let (union_def_id, variant) = match union_type.kind { ty::Adt(def, _) => (def.did, def.non_enum_variant()), _ => bug!("prepare_union_metadata on a non-ADT") }; @@ -1330,11 +1335,11 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec> { let variant_info_for = |index: VariantIdx| { - match &self.enum_type.sty { + match &self.enum_type.kind { ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index]), ty::Generator(def_id, substs, _) => { let generator_layout = cx.tcx.generator_layout(*def_id); - VariantInfo::Generator(*substs, generator_layout, index) + VariantInfo::Generator(substs, generator_layout, index) } _ => bug!(), } @@ -1350,7 +1355,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { match self.layout.variants { layout::Variants::Single { index } => { - if let ty::Adt(adt, _) = &self.enum_type.sty { + if let ty::Adt(adt, _) = &self.enum_type.kind { if adt.variants.is_empty() { return vec![]; } @@ -1607,7 +1612,7 @@ enum EnumDiscriminantInfo<'ll> { #[derive(Copy, Clone)] enum VariantInfo<'tcx> { Adt(&'tcx ty::VariantDef), - Generator(ty::GeneratorSubsts<'tcx>, &'tcx GeneratorLayout<'tcx>, VariantIdx), + Generator(SubstsRef<'tcx>, &'tcx GeneratorLayout<'tcx>, VariantIdx), } impl<'tcx> VariantInfo<'tcx> { @@ -1615,7 +1620,7 @@ impl<'tcx> VariantInfo<'tcx> { match self { VariantInfo::Adt(variant) => f(&variant.ident.as_str()), VariantInfo::Generator(substs, _, variant_index) => - f(&substs.variant_name(*variant_index)), + f(&substs.as_generator().variant_name(*variant_index)), } } @@ -1743,7 +1748,7 @@ fn prepare_enum_metadata( let file_metadata = unknown_file_metadata(cx); let discriminant_type_metadata = |discr: layout::Primitive| { - let enumerators_metadata: Vec<_> = match enum_type.sty { + let enumerators_metadata: Vec<_> = match enum_type.kind { ty::Adt(def, _) => def .discriminants(cx.tcx) .zip(&def.variants) @@ -1759,9 +1764,10 @@ fn prepare_enum_metadata( }) .collect(), ty::Generator(_, substs, _) => substs + .as_generator() .variant_range(enum_def_id, cx.tcx) .map(|variant_index| { - let name = SmallCStr::new(&substs.variant_name(variant_index)); + let name = SmallCStr::new(&substs.as_generator().variant_name(variant_index)); unsafe { Some(llvm::LLVMRustDIBuilderCreateEnumerator( DIB(cx), @@ -1786,7 +1792,7 @@ fn prepare_enum_metadata( let discriminant_base_type_metadata = type_metadata(cx, discr.to_ty(cx.tcx), syntax_pos::DUMMY_SP); - let discriminant_name = match enum_type.sty { + let discriminant_name = match enum_type.kind { ty::Adt(..) => SmallCStr::new(&cx.tcx.item_name(enum_def_id).as_str()), ty::Generator(..) => SmallCStr::new(&enum_name), _ => bug!(), @@ -1877,7 +1883,7 @@ fn prepare_enum_metadata( ); } - let discriminator_name = match &enum_type.sty { + let discriminator_name = match &enum_type.kind { ty::Generator(..) => Some(SmallCStr::new(&"__state")), _ => None, }; @@ -2087,12 +2093,12 @@ fn set_members_of_composite_type(cx: &CodegenCx<'ll, 'tcx>, // Compute the type parameters for a type, if any, for the given // metadata. fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> Option<&'ll DIArray> { - if let ty::Adt(def, substs) = ty.sty { + if let ty::Adt(def, substs) = ty.kind { if !substs.types().next().is_none() { let generics = cx.tcx.generics_of(def.did); let names = get_parameter_names(cx, generics); let template_params: Vec<_> = substs.iter().zip(names).filter_map(|(kind, name)| { - if let UnpackedKind::Type(ty) = kind.unpack() { + if let GenericArgKind::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); @@ -2247,7 +2253,7 @@ pub fn create_global_var_metadata( None } else { let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)); - Some(SmallCStr::new(&linkage_name.as_str())) + Some(SmallCStr::new(&linkage_name.name.as_str())) }; let global_align = cx.align_of(variable_type); diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index 548ea0b1036e0..6e4ed42c45e97 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -15,7 +15,7 @@ use crate::llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilder, DISubprogram, D DISPFlags, DILexicalBlock}; use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; -use rustc::ty::subst::{SubstsRef, UnpackedKind}; +use rustc::ty::subst::{SubstsRef, GenericArgKind}; use crate::abi::Abi; use crate::common::CodegenCx; @@ -26,13 +26,13 @@ use rustc::mir; use rustc::session::config::{self, DebugInfo}; use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet}; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::vec::IndexVec; use rustc_codegen_ssa::debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess, VariableKind, FunctionDebugContextData, type_names}; use libc::c_uint; use std::cell::RefCell; -use std::ffi::CString; +use std::ffi::{CStr, CString}; use syntax_pos::{self, Span, Pos}; use syntax::ast; @@ -127,20 +127,20 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) { if cx.sess().target.target.options.is_like_osx || cx.sess().target.target.options.is_like_android { llvm::LLVMRustAddModuleFlag(cx.llmod, - "Dwarf Version\0".as_ptr() as *const _, + "Dwarf Version\0".as_ptr().cast(), 2) } // Indicate that we want CodeView debug information on MSVC if cx.sess().target.target.options.is_like_msvc { llvm::LLVMRustAddModuleFlag(cx.llmod, - "CodeView\0".as_ptr() as *const _, + "CodeView\0".as_ptr().cast(), 1) } // Prevent bitcode readers from deleting the debug info. let ptr = "Debug Info Version\0".as_ptr(); - llvm::LLVMRustAddModuleFlag(cx.llmod, ptr as *const _, + llvm::LLVMRustAddModuleFlag(cx.llmod, ptr.cast(), llvm::LLVMRustDebugMetadataVersion()); }; } @@ -224,8 +224,37 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { gdb::insert_reference_to_gdb_debug_scripts_section_global(self) } - fn set_value_name(&mut self, value: &'ll Value, name: &str) { - let cname = SmallCStr::new(name); + fn set_var_name(&mut self, value: &'ll Value, name: impl ToString) { + // Avoid wasting time if LLVM value names aren't even enabled. + if self.sess().fewer_names() { + return; + } + + // Only function parameters and instructions are local to a function, + // don't change the name of anything else (e.g. globals). + let param_or_inst = unsafe { + llvm::LLVMIsAArgument(value).is_some() || + llvm::LLVMIsAInstruction(value).is_some() + }; + if !param_or_inst { + return; + } + + let old_name = unsafe { + CStr::from_ptr(llvm::LLVMGetValueName(value)) + }; + match old_name.to_str() { + Ok("") => {} + Ok(_) => { + // Avoid replacing the name if it already exists. + // While we could combine the names somehow, it'd + // get noisy quick, and the usefulness is dubious. + return; + } + Err(_) => return, + } + + let cname = CString::new(name.to_string()).unwrap(); unsafe { llvm::LLVMSetValueName(value, cname.as_ptr()); } @@ -290,7 +319,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let scope_line = span_start(self, span).line; let function_name = CString::new(name).unwrap(); - let linkage_name = SmallCStr::new(&linkage_name.as_str()); + let linkage_name = SmallCStr::new(&linkage_name.name.as_str()); let mut flags = DIFlags::FlagPrototyped; @@ -348,7 +377,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let mut signature = Vec::with_capacity(sig.inputs().len() + 1); // Return type -- llvm::DIBuilder wants this at index 0 - signature.push(match sig.output().sty { + signature.push(match sig.output().kind { ty::Tuple(ref tys) if tys.is_empty() => None, _ => Some(type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP)) }); @@ -372,7 +401,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { // This transformed type is wrong, but these function types are // already inaccurate due to ABI adjustments (see #42800). signature.extend(inputs.iter().map(|&t| { - let t = match t.sty { + let t = match t.kind { ty::Array(ct, _) if (ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() => { cx.tcx.mk_imm_ptr(ct) @@ -388,7 +417,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { } if sig.abi == Abi::RustCall && !sig.inputs().is_empty() { - if let ty::Tuple(args) = sig.inputs()[sig.inputs().len() - 1].sty { + if let ty::Tuple(args) = sig.inputs()[sig.inputs().len() - 1].kind { signature.extend( args.iter().map(|argument_type| { Some(type_metadata(cx, argument_type.expect_ty(), syntax_pos::DUMMY_SP)) @@ -431,7 +460,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full { let names = get_parameter_names(cx, generics); substs.iter().zip(names).filter_map(|(kind, name)| { - if let UnpackedKind::Type(ty) = kind.unpack() { + if let GenericArgKind::Type(ty) = kind.unpack() { let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); let actual_type_metadata = @@ -487,7 +516,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { // Only "class" methods are generally understood by LLVM, // so avoid methods on other types (e.g., `<*mut T>::null`). - match impl_self_ty.sty { + match impl_self_ty.kind { ty::Adt(def, ..) if !def.is_box() => { Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP)) } diff --git a/src/librustc_codegen_llvm/error_codes.rs b/src/librustc_codegen_llvm/error_codes.rs index c6b5dc03a6f0a..042e51ed2ba7a 100644 --- a/src/librustc_codegen_llvm/error_codes.rs +++ b/src/librustc_codegen_llvm/error_codes.rs @@ -1,4 +1,4 @@ -register_long_diagnostics! { +register_diagnostics! { E0511: r##" Invalid monomorphization of an intrinsic function was used. Erroneous code diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 199170182e4b4..68d9af09c42b1 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -15,6 +15,7 @@ use rustc_codegen_ssa::glue; use rustc_codegen_ssa::base::{to_immediate, wants_msvc_seh, compare_simd_types}; use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Primitive}; +use rustc::mir::interpret::GlobalId; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc::hir; use syntax::ast::{self, FloatTy}; @@ -81,15 +82,16 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Valu impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { fn codegen_intrinsic_call( &mut self, - callee_ty: Ty<'tcx>, + instance: ty::Instance<'tcx>, fn_ty: &FnType<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, &'ll Value>], llresult: &'ll Value, span: Span, ) { let tcx = self.tcx; + let callee_ty = instance.ty(tcx); - let (def_id, substs) = match callee_ty.sty { + let (def_id, substs) = match callee_ty.kind { ty::FnDef(def_id, substs) => (def_id, substs), _ => bug!("expected fn item type, found {}", callee_ty) }; @@ -101,7 +103,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { let name = &*tcx.item_name(def_id).as_str(); let llret_ty = self.layout_of(ret_ty).llvm_type(self); - let result = PlaceRef::new_sized(llresult, fn_ty.ret.layout, fn_ty.ret.layout.align.abi); + let result = PlaceRef::new_sized(llresult, fn_ty.ret.layout); let simple = get_simple_intrinsic(self, name); let llval = match name { @@ -133,10 +135,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { let llfn = self.get_intrinsic(&("llvm.debugtrap")); self.call(llfn, &[], None) } - "size_of" => { - let tp_ty = substs.type_at(0); - self.const_usize(self.size_of(tp_ty).bytes()) - } "va_start" => { self.va_start(args[0].immediate()) } @@ -188,10 +186,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { self.const_usize(self.size_of(tp_ty).bytes()) } } - "min_align_of" => { - let tp_ty = substs.type_at(0); - self.const_usize(self.align_of(tp_ty).bytes()) - } "min_align_of_val" => { let tp_ty = substs.type_at(0); if let OperandValue::Pair(_, meta) = args[0].val { @@ -201,18 +195,19 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { self.const_usize(self.align_of(tp_ty).bytes()) } } - "pref_align_of" => { - let tp_ty = substs.type_at(0); - self.const_usize(self.layout_of(tp_ty).align.pref.bytes()) - } + "size_of" | + "pref_align_of" | + "min_align_of" | + "needs_drop" | + "type_id" | "type_name" => { - let tp_ty = substs.type_at(0); - let ty_name = self.tcx.type_name(tp_ty); + let gid = GlobalId { + instance, + promoted: None, + }; + let ty_name = self.tcx.const_eval(ty::ParamEnv::reveal_all().and(gid)).unwrap(); OperandRef::from_const(self, ty_name).immediate_or_packed_pair(self) } - "type_id" => { - self.const_u64(self.tcx.type_id_hash(substs.type_at(0))) - } "init" => { let ty = substs.type_at(0); if !self.layout_of(ty).is_zst() { @@ -232,14 +227,9 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { return; } // Effectively no-ops - "forget" => { + "uninit" | "forget" => { return; } - "needs_drop" => { - let tp_ty = substs.type_at(0); - - self.const_bool(self.type_needs_drop(tp_ty)) - } "offset" => { let ptr = args[0].immediate(); let offset = args[1].immediate(); @@ -328,7 +318,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { }, "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" | "bitreverse" | "add_with_overflow" | "sub_with_overflow" | - "mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" | + "mul_with_overflow" | "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "unchecked_add" | "unchecked_sub" | "unchecked_mul" | "exact_div" | "rotate_left" | "rotate_right" | "saturating_add" | "saturating_sub" => { @@ -398,9 +388,9 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { return; }, - "overflowing_add" => self.add(args[0].immediate(), args[1].immediate()), - "overflowing_sub" => self.sub(args[0].immediate(), args[1].immediate()), - "overflowing_mul" => self.mul(args[0].immediate(), args[1].immediate()), + "wrapping_add" => self.add(args[0].immediate(), args[1].immediate()), + "wrapping_sub" => self.sub(args[0].immediate(), args[1].immediate()), + "wrapping_mul" => self.mul(args[0].immediate(), args[1].immediate()), "exact_div" => if signed { self.exactsdiv(args[0].immediate(), args[1].immediate()) @@ -734,6 +724,13 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { self.call(expect, &[cond, self.const_bool(expected)], None) } + fn sideeffect(&mut self) { + if self.tcx.sess.opts.debugging_opts.insert_sideeffect { + let fnname = self.get_intrinsic(&("llvm.sideeffect")); + self.call(fnname, &[], None); + } + } + fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value { let intrinsic = self.cx().get_intrinsic("llvm.va_start"); self.call(intrinsic, &[va_list], None) @@ -820,6 +817,7 @@ fn codegen_msvc_try( ) { let llfn = get_rust_try_fn(bx, &mut |mut bx| { bx.set_personality_fn(bx.eh_personality()); + bx.sideeffect(); let mut normal = bx.build_sibling_block("normal"); let mut catchswitch = bx.build_sibling_block("catchswitch"); @@ -871,7 +869,7 @@ fn codegen_msvc_try( // More information can be found in libstd's seh.rs implementation. let i64p = bx.type_ptr_to(bx.type_i64()); let ptr_align = bx.tcx().data_layout.pointer_align.abi; - let slot = bx.alloca(i64p, "slot", ptr_align); + let slot = bx.alloca(i64p, ptr_align); bx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(), None); normal.ret(bx.const_i32(0)); @@ -943,6 +941,8 @@ fn codegen_gnu_try( // expected to be `*mut *mut u8` for this to actually work, but that's // managed by the standard library. + bx.sideeffect(); + let mut then = bx.build_sibling_block("then"); let mut catch = bx.build_sibling_block("catch"); @@ -1084,7 +1084,7 @@ fn generic_simd_intrinsic( if name == "simd_select_bitmask" { let in_ty = arg_tys[0]; - let m_len = match in_ty.sty { + let m_len = match in_ty.kind { // Note that this `.unwrap()` crashes for isize/usize, that's sort // of intentional as there's not currently a use case for that. ty::Int(i) => i.bit_width().unwrap(), @@ -1213,7 +1213,7 @@ fn generic_simd_intrinsic( "mismatched lengths: mask length `{}` != other vector length `{}`", m_len, v_len ); - match m_elem_ty.sty { + match m_elem_ty.kind { ty::Int(_) => {}, _ => return_error!("mask element type is `{}`, expected `i_`", m_elem_ty) } @@ -1233,7 +1233,7 @@ fn generic_simd_intrinsic( // If the vector has less than 8 lanes, an u8 is returned with zeroed // trailing bits. let expected_int_bits = in_len.max(8); - match ret_ty.sty { + match ret_ty.kind { ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => (), _ => return_error!( "bitmask `{}`, expected `u{}`", @@ -1242,7 +1242,7 @@ fn generic_simd_intrinsic( } // Integer vector : - let (i_xn, in_elem_bitwidth) = match in_elem.sty { + let (i_xn, in_elem_bitwidth) = match in_elem.kind { ty::Int(i) => ( args[0].immediate(), i.bit_width().unwrap_or(bx.data_layout().pointer_size.bits() as _) @@ -1298,7 +1298,7 @@ fn generic_simd_intrinsic( } } } - let ety = match in_elem.sty { + let ety = match in_elem.kind { ty::Float(f) if f.bit_width() == 32 => { if in_len < 2 || in_len > 16 { return_error!( @@ -1385,7 +1385,7 @@ fn generic_simd_intrinsic( // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Intrinsics.h#L81 fn llvm_vector_str(elem_ty: Ty<'_>, vec_len: usize, no_pointers: usize) -> String { let p0s: String = "p0".repeat(no_pointers); - match elem_ty.sty { + match elem_ty.kind { ty::Int(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), ty::Uint(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), ty::Float(v) => format!("v{}{}f{}", vec_len, p0s, v.bit_width()), @@ -1396,7 +1396,7 @@ fn generic_simd_intrinsic( fn llvm_vector_ty(cx: &CodegenCx<'ll, '_>, elem_ty: Ty<'_>, vec_len: usize, mut no_pointers: usize) -> &'ll Type { // FIXME: use cx.layout_of(ty).llvm_type() ? - let mut elem_ty = match elem_ty.sty { + let mut elem_ty = match elem_ty.kind { ty::Int(v) => cx.type_int_from_ty( v), ty::Uint(v) => cx.type_uint_from_ty( v), ty::Float(v) => cx.type_float_from_ty( v), @@ -1440,7 +1440,7 @@ fn generic_simd_intrinsic( // This counts how many pointers fn ptr_count(t: Ty<'_>) -> usize { - match t.sty { + match t.kind { ty::RawPtr(p) => 1 + ptr_count(p.ty), _ => 0, } @@ -1448,7 +1448,7 @@ fn generic_simd_intrinsic( // Non-ptr type fn non_ptr(t: Ty<'_>) -> Ty<'_> { - match t.sty { + match t.kind { ty::RawPtr(p) => non_ptr(p.ty), _ => t, } @@ -1456,7 +1456,7 @@ fn generic_simd_intrinsic( // The second argument must be a simd vector with an element type that's a pointer // to the element type of the first argument - let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).sty { + let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind { ty::RawPtr(p) if p.ty == in_elem => (ptr_count(arg_tys[1].simd_type(tcx)), non_ptr(arg_tys[1].simd_type(tcx))), _ => { @@ -1473,7 +1473,7 @@ fn generic_simd_intrinsic( assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx))); // The element type of the third argument must be a signed integer type of any width: - match arg_tys[2].simd_type(tcx).sty { + match arg_tys[2].simd_type(tcx).kind { ty::Int(_) => (), _ => { require!(false, "expected element type `{}` of third argument `{}` \ @@ -1539,7 +1539,7 @@ fn generic_simd_intrinsic( // This counts how many pointers fn ptr_count(t: Ty<'_>) -> usize { - match t.sty { + match t.kind { ty::RawPtr(p) => 1 + ptr_count(p.ty), _ => 0, } @@ -1547,7 +1547,7 @@ fn generic_simd_intrinsic( // Non-ptr type fn non_ptr(t: Ty<'_>) -> Ty<'_> { - match t.sty { + match t.kind { ty::RawPtr(p) => non_ptr(p.ty), _ => t, } @@ -1555,7 +1555,7 @@ fn generic_simd_intrinsic( // The second argument must be a simd vector with an element type that's a pointer // to the element type of the first argument - let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).sty { + let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind { ty::RawPtr(p) if p.ty == in_elem && p.mutbl == hir::MutMutable => (ptr_count(arg_tys[1].simd_type(tcx)), non_ptr(arg_tys[1].simd_type(tcx))), @@ -1573,7 +1573,7 @@ fn generic_simd_intrinsic( assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx))); // The element type of the third argument must be a signed integer type of any width: - match arg_tys[2].simd_type(tcx).sty { + match arg_tys[2].simd_type(tcx).kind { ty::Int(_) => (), _ => { require!(false, "expected element type `{}` of third argument `{}` \ @@ -1622,7 +1622,7 @@ fn generic_simd_intrinsic( require!(ret_ty == in_elem, "expected return type `{}` (element of input `{}`), found `{}`", in_elem, in_ty, ret_ty); - return match in_elem.sty { + return match in_elem.kind { ty::Int(_) | ty::Uint(_) => { let r = bx.$integer_reduce(args[0].immediate()); if $ordered { @@ -1679,7 +1679,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, require!(ret_ty == in_elem, "expected return type `{}` (element of input `{}`), found `{}`", in_elem, in_ty, ret_ty); - return match in_elem.sty { + return match in_elem.kind { ty::Int(_i) => { Ok(bx.$int_red(args[0].immediate(), true)) }, @@ -1714,7 +1714,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, in_elem, in_ty, ret_ty); args[0].immediate() } else { - match in_elem.sty { + match in_elem.kind { ty::Int(_) | ty::Uint(_) => {}, _ => { return_error!("unsupported {} from `{}` with element `{}` to `{}`", @@ -1727,7 +1727,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, let i1xn = bx.type_vector(i1, in_len as u64); bx.trunc(args[0].immediate(), i1xn) }; - return match in_elem.sty { + return match in_elem.kind { ty::Int(_) | ty::Uint(_) => { let r = bx.$red(input); Ok( @@ -1768,7 +1768,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, enum Style { Float, Int(/* is signed? */ bool), Unsupported } - let (in_style, in_width) = match in_elem.sty { + let (in_style, in_width) = match in_elem.kind { // vectors of pointer-sized integers should've been // disallowed before here, so this unwrap is safe. ty::Int(i) => (Style::Int(true), i.bit_width().unwrap()), @@ -1776,7 +1776,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, ty::Float(f) => (Style::Float, f.bit_width()), _ => (Style::Unsupported, 0) }; - let (out_style, out_width) = match out_elem.sty { + let (out_style, out_width) = match out_elem.kind { ty::Int(i) => (Style::Int(true), i.bit_width().unwrap()), ty::Uint(u) => (Style::Int(false), u.bit_width().unwrap()), ty::Float(f) => (Style::Float, f.bit_width()), @@ -1826,7 +1826,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, macro_rules! arith { ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => { $(if name == stringify!($name) { - match in_elem.sty { + match in_elem.kind { $($(ty::$p(_))|* => { return Ok(bx.$call(args[0].immediate(), args[1].immediate())) })* @@ -1860,7 +1860,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, let rhs = args[1].immediate(); let is_add = name == "simd_saturating_add"; let ptr_bits = bx.tcx().data_layout.pointer_size.bits() as _; - let (signed, elem_width, elem_ty) = match in_elem.sty { + let (signed, elem_width, elem_ty) = match in_elem.kind { ty::Int(i) => ( true, @@ -1906,7 +1906,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, // FIXME: there’s multiple of this functions, investigate using some of the already existing // stuffs. fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_, '_>) -> Option<(u64, bool)> { - match ty.sty { + match ty.kind { ty::Int(t) => Some((match t { ast::IntTy::Isize => cx.tcx.sess.target.isize_ty.bit_width().unwrap() as u64, ast::IntTy::I8 => 8, @@ -1930,7 +1930,7 @@ fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_, '_>) -> Option<(u64, boo // Returns the width of a float Ty // Returns None if the type is not a float fn float_type_width(ty: Ty<'_>) -> Option { - match ty.sty { + match ty.kind { ty::Float(t) => Some(t.bit_width() as u64), _ => None, } diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 653dd8868f479..52797e64f7df9 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -14,13 +14,11 @@ #![feature(in_band_lifetimes)] #![feature(libc)] #![feature(nll)] -#![feature(rustc_diagnostic_macros)] #![feature(optin_builtin_traits)] #![feature(concat_idents)] #![feature(link_args)] #![feature(static_nobundle)] #![feature(trusted_len)] -#![feature(mem_take)] use back::write::{create_target_machine, create_informational_target_machine}; use syntax_pos::symbol::Symbol; @@ -32,6 +30,7 @@ extern crate libc; #[macro_use] extern crate rustc; extern crate rustc_target; #[macro_use] extern crate rustc_data_structures; +extern crate rustc_index; extern crate rustc_incremental; extern crate rustc_codegen_utils; extern crate rustc_codegen_ssa; @@ -53,7 +52,8 @@ use syntax::ext::allocator::AllocatorKind; use syntax_pos::symbol::InternedString; pub use llvm_util::target_features; use std::any::Any; -use std::sync::{mpsc, Arc}; +use std::sync::Arc; +use std::ffi::CStr; use rustc::dep_graph::DepGraph; use rustc::middle::cstore::{EncodedMetadata, MetadataLoader}; @@ -122,8 +122,12 @@ impl ExtraBackendMethods for LlvmCodegenBackend { ) { unsafe { allocator::codegen(tcx, mods, kind) } } - fn compile_codegen_unit(&self, tcx: TyCtxt<'_>, cgu_name: InternedString) { - base::compile_codegen_unit(tcx, cgu_name); + fn compile_codegen_unit( + &self, tcx: TyCtxt<'_>, + cgu_name: InternedString, + tx: &std::sync::mpsc::Sender>, + ) { + base::compile_codegen_unit(tcx, cgu_name, tx); } fn target_machine_factory( &self, @@ -226,21 +230,21 @@ impl CodegenBackend for LlvmCodegenBackend { for &(name, _) in back::write::RELOC_MODEL_ARGS.iter() { println!(" {}", name); } - println!(""); + println!(); } PrintRequest::CodeModels => { println!("Available code models:"); for &(name, _) in back::write::CODE_GEN_MODEL_ARGS.iter(){ println!(" {}", name); } - println!(""); + println!(); } PrintRequest::TlsModels => { println!("Available TLS models:"); for &(name, _) in back::write::TLS_MODEL_ARGS.iter(){ println!(" {}", name); } - println!(""); + println!(); } req => llvm_util::print(req, sess), } @@ -255,7 +259,7 @@ impl CodegenBackend for LlvmCodegenBackend { } fn diagnostics(&self) -> &[(&'static str, &'static str)] { - &DIAGNOSTICS + &error_codes::DIAGNOSTICS } fn target_features(&self, sess: &Session) -> Vec { @@ -284,10 +288,9 @@ impl CodegenBackend for LlvmCodegenBackend { tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, need_metadata_module: bool, - rx: mpsc::Receiver>, ) -> Box { box rustc_codegen_ssa::base::codegen_crate( - LlvmCodegenBackend(()), tcx, metadata, need_metadata_module, rx) + LlvmCodegenBackend(()), tcx, metadata, need_metadata_module) } fn join_codegen_and_link( @@ -320,8 +323,9 @@ impl CodegenBackend for LlvmCodegenBackend { // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. - sess.profiler(|p| p.start_activity("link_crate")); time(sess, "linking", || { + let _prof_timer = sess.prof.generic_activity("link_crate"); + use rustc_codegen_ssa::back::link::link_binary; use crate::back::archive::LlvmArchiveBuilder; @@ -334,7 +338,6 @@ impl CodegenBackend for LlvmCodegenBackend { target_cpu, ); }); - sess.profiler(|p| p.end_activity("link_crate")); // Now that we won't touch anything in the incremental compilation directory // any more, we can finalize it (which involves renaming it) @@ -386,13 +389,13 @@ impl ModuleLlvm { fn parse( cgcx: &CodegenContext, - name: &str, - buffer: &back::lto::ModuleBuffer, + name: &CStr, + buffer: &[u8], handler: &Handler, ) -> Result { unsafe { let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); - let llmod_raw = buffer.parse(name, llcx, handler)?; + let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?; let tm = match (cgcx.tm_factory.0)() { Ok(m) => m, Err(e) => { @@ -424,5 +427,3 @@ impl Drop for ModuleLlvm { } } } - -__build_diagnostic_array! { librustc_codegen_llvm, DIAGNOSTICS } diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 9f9410560e373..b07214fdc03f3 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -806,6 +806,7 @@ extern "C" { pub fn LLVMRustRemoveFunctionAttributes(Fn: &Value, index: c_uint, attr: Attribute); // Operations on parameters + pub fn LLVMIsAArgument(Val: &Value) -> Option<&Value>; pub fn LLVMCountParams(Fn: &Value) -> c_uint; pub fn LLVMGetParam(Fn: &Value, Index: c_uint) -> &Value; @@ -818,6 +819,7 @@ extern "C" { pub fn LLVMDeleteBasicBlock(BB: &BasicBlock); // Operations on instructions + pub fn LLVMIsAInstruction(Val: &Value) -> Option<&Value>; pub fn LLVMGetFirstBasicBlock(Fn: &Value) -> &BasicBlock; // Operations on call sites diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index 36a9ff0a2d2e5..d921bbc96adee 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -43,7 +43,7 @@ fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, layout::Abi::Aggregate { .. } => {} } - let name = match layout.ty.sty { + let name = match layout.ty.kind { ty::Closure(..) | ty::Generator(..) | ty::Adt(..) | @@ -56,16 +56,16 @@ fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let printer = DefPathBasedNames::new(cx.tcx, true, true); printer.push_type_name(layout.ty, &mut name, false); if let (&ty::Adt(def, _), &layout::Variants::Single { index }) - = (&layout.ty.sty, &layout.variants) + = (&layout.ty.kind, &layout.variants) { if def.is_enum() && !def.variants.is_empty() { write!(&mut name, "::{}", def.variants[index].ident).unwrap(); } } if let (&ty::Generator(_, substs, _), &layout::Variants::Single { index }) - = (&layout.ty.sty, &layout.variants) + = (&layout.ty.kind, &layout.variants) { - write!(&mut name, "::{}", substs.variant_name(index)).unwrap(); + write!(&mut name, "::{}", substs.as_generator().variant_name(index)).unwrap(); } Some(name) } @@ -226,7 +226,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) { return llty; } - let llty = match self.ty.sty { + let llty = match self.ty.kind { ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { cx.type_ptr_to(cx.layout_of(ty).llvm_type(cx)) @@ -318,7 +318,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { index: usize, immediate: bool) -> &'a Type { // HACK(eddyb) special-case fat pointers until LLVM removes // pointee types, to avoid bitcasting every `OperandRef::deref`. - match self.ty.sty { + match self.ty.kind { ty::Ref(..) | ty::RawPtr(_) => { return self.field(cx, index).llvm_type(cx); diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml index 89a6ec27fe595..c7d09a423d5e3 100644 --- a/src/librustc_codegen_ssa/Cargo.toml +++ b/src/librustc_codegen_ssa/Cargo.toml @@ -17,8 +17,7 @@ memmap = "0.6" log = "0.4.5" libc = "0.2.44" jobserver = "0.1.11" -parking_lot = "0.7" -tempfile = "3.0.5" +tempfile = "3.1" rustc_serialize = { path = "../libserialize", package = "serialize" } syntax = { path = "../libsyntax" } @@ -30,4 +29,5 @@ rustc_data_structures = { path = "../librustc_data_structures"} rustc_errors = { path = "../librustc_errors" } rustc_fs_util = { path = "../librustc_fs_util" } rustc_incremental = { path = "../librustc_incremental" } +rustc_index = { path = "../librustc_index" } rustc_target = { path = "../librustc_target" } diff --git a/src/librustc_codegen_ssa/back/archive.rs b/src/librustc_codegen_ssa/back/archive.rs index 23d580ef08b2d..8d2120a345a8d 100644 --- a/src/librustc_codegen_ssa/back/archive.rs +++ b/src/librustc_codegen_ssa/back/archive.rs @@ -1,9 +1,10 @@ use rustc::session::Session; +use syntax::symbol::Symbol; use std::io; use std::path::{Path, PathBuf}; -pub fn find_library(name: &str, search_paths: &[PathBuf], sess: &Session) +pub fn find_library(name: Symbol, search_paths: &[PathBuf], sess: &Session) -> PathBuf { // On Windows, static libraries sometimes show up as libfoo.a and other // times show up as foo.lib @@ -40,7 +41,7 @@ pub trait ArchiveBuilder<'a> { lto: bool, skip_objects: bool, ) -> io::Result<()>; - fn add_native_library(&mut self, name: &str); + fn add_native_library(&mut self, name: Symbol); fn update_symbols(&mut self); fn build(self); diff --git a/src/librustc_codegen_ssa/back/command.rs b/src/librustc_codegen_ssa/back/command.rs index d610805b5bbd0..2d84d67e3c85b 100644 --- a/src/librustc_codegen_ssa/back/command.rs +++ b/src/librustc_codegen_ssa/back/command.rs @@ -8,12 +8,14 @@ use std::mem; use std::process::{self, Output}; use rustc_target::spec::LldFlavor; +use syntax::symbol::Symbol; #[derive(Clone)] pub struct Command { program: Program, args: Vec, env: Vec<(OsString, OsString)>, + env_remove: Vec, } #[derive(Clone)] @@ -41,6 +43,7 @@ impl Command { program, args: Vec::new(), env: Vec::new(), + env_remove: Vec::new(), } } @@ -49,9 +52,14 @@ impl Command { self } + pub fn sym_arg(&mut self, arg: Symbol) -> &mut Command { + self.arg(&arg.as_str()); + self + } + pub fn args(&mut self, args: I) -> &mut Command - where I: IntoIterator, - I::Item: AsRef, + where + I: IntoIterator>, { for arg in args { self._arg(arg.as_ref()); @@ -75,6 +83,17 @@ impl Command { self.env.push((key.to_owned(), value.to_owned())); } + pub fn env_remove(&mut self, key: K) -> &mut Command + where K: AsRef, + { + self._env_remove(key.as_ref()); + self + } + + fn _env_remove(&mut self, key: &OsStr) { + self.env_remove.push(key.to_owned()); + } + pub fn output(&mut self) -> io::Result { self.command().output() } @@ -100,6 +119,9 @@ impl Command { }; ret.args(&self.args); ret.envs(self.env.clone()); + for k in &self.env_remove { + ret.env_remove(k); + } return ret } diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 8fb0828285c58..1c5d3b1a890ee 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -13,6 +13,7 @@ use rustc::hir::def_id::CrateNum; use rustc_data_structures::fx::FxHashSet; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_target::spec::{PanicStrategy, RelroLevel, LinkerFlavor}; +use syntax::symbol::Symbol; use crate::{METADATA_FILENAME, RLIB_BYTECODE_EXTENSION, CrateInfo, CodegenResults}; use super::archive::ArchiveBuilder; @@ -32,6 +33,7 @@ use std::path::{Path, PathBuf}; use std::process::{Output, Stdio, ExitStatus}; use std::str; use std::env; +use std::ffi::OsString; pub use rustc_codegen_utils::link::*; @@ -158,6 +160,36 @@ pub fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> (PathB } }; + // UWP apps have API restrictions enforced during Store submissions. + // To comply with the Windows App Certification Kit, + // MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc). + let t = &sess.target.target; + if flavor == LinkerFlavor::Msvc && t.target_vendor == "uwp" { + if let Some(ref tool) = msvc_tool { + let original_path = tool.path(); + if let Some(ref root_lib_path) = original_path.ancestors().skip(4).next() { + let arch = match t.arch.as_str() { + "x86_64" => Some("x64".to_string()), + "x86" => Some("x86".to_string()), + "aarch64" => Some("arm64".to_string()), + _ => None, + }; + if let Some(ref a) = arch { + let mut arg = OsString::from("/LIBPATH:"); + arg.push(format!("{}\\lib\\{}\\store", root_lib_path.display(), a.to_string())); + cmd.arg(&arg); + } + else { + warn!("arch is not supported"); + } + } else { + warn!("MSVC root path lib location not found"); + } + } else { + warn!("link.exe not found"); + } + } + // The compiler's sysroot often has some bundled tools, so add it to the // PATH for the child. let mut new_path = sess.host_filesearch(PathKind::All) @@ -187,15 +219,24 @@ pub fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> (PathB (linker.to_path_buf(), cmd) } -pub fn each_linked_rlib(sess: &Session, - info: &CrateInfo, - f: &mut dyn FnMut(CrateNum, &Path)) -> Result<(), String> { +pub fn each_linked_rlib( + info: &CrateInfo, + f: &mut dyn FnMut(CrateNum, &Path), +) -> Result<(), String> { let crates = info.used_crates_static.iter(); - let fmts = sess.dependency_formats.borrow(); - let fmts = fmts.get(&config::CrateType::Executable) - .or_else(|| fmts.get(&config::CrateType::Staticlib)) - .or_else(|| fmts.get(&config::CrateType::Cdylib)) - .or_else(|| fmts.get(&config::CrateType::ProcMacro)); + let mut fmts = None; + for (ty, list) in info.dependency_formats.iter() { + match ty { + config::CrateType::Executable | + config::CrateType::Staticlib | + config::CrateType::Cdylib | + config::CrateType::ProcMacro => { + fmts = Some(list); + break; + } + _ => {} + } + } let fmts = match fmts { Some(f) => f, None => return Err("could not find formats for rlibs".to_string()) @@ -282,10 +323,11 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, NativeLibraryKind::NativeStatic => {} NativeLibraryKind::NativeStaticNobundle | NativeLibraryKind::NativeFramework | + NativeLibraryKind::NativeRawDylib | NativeLibraryKind::NativeUnknown => continue, } if let Some(name) = lib.name { - ab.add_native_library(&name.as_str()); + ab.add_native_library(name); } } @@ -374,7 +416,7 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, tempdir); let mut all_native_libs = vec![]; - let res = each_linked_rlib(sess, &codegen_results.crate_info, &mut |cnum, path| { + let res = each_linked_rlib(&codegen_results.crate_info, &mut |cnum, path| { let name = &codegen_results.crate_info.crate_name[&cnum]; let native_libs = &codegen_results.crate_info.native_libraries[&cnum]; @@ -501,6 +543,9 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, for &(ref k, ref v) in &sess.target.target.options.link_env { cmd.env(k, v); } + for k in &sess.target.target.options.link_env_remove { + cmd.env_remove(k); + } if sess.opts.debugging_opts.print_link_args { println!("{:?}", &cmd); @@ -839,7 +884,8 @@ pub fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary Some(format!("-framework {}", name)) }, // These are included, no need to print them - NativeLibraryKind::NativeStatic => None, + NativeLibraryKind::NativeStatic | + NativeLibraryKind::NativeRawDylib => None, } }) .collect(); @@ -1027,6 +1073,7 @@ fn link_args<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker, let t = &sess.target.target; cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path)); + for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { cmd.add_object(obj); } @@ -1241,15 +1288,18 @@ pub fn add_local_native_libraries(cmd: &mut dyn Linker, let search_path = archive_search_paths(sess); for lib in relevant_libs { let name = match lib.name { - Some(ref l) => l, + Some(l) => l, None => continue, }; match lib.kind { - NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()), - NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()), - NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&name.as_str()), - NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&name.as_str(), - &search_path) + NativeLibraryKind::NativeUnknown => cmd.link_dylib(name), + NativeLibraryKind::NativeFramework => cmd.link_framework(name), + NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(name), + NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(name, &search_path), + NativeLibraryKind::NativeRawDylib => { + // FIXME(#58713): Proper handling for raw dylibs. + bug!("raw_dylib feature not yet implemented"); + }, } } } @@ -1259,11 +1309,13 @@ pub fn add_local_native_libraries(cmd: &mut dyn Linker, // Rust crates are not considered at all when creating an rlib output. All // dependencies will be linked when producing the final output (instead of // the intermediate rlib version) -fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker, - sess: &'a Session, - codegen_results: &CodegenResults, - crate_type: config::CrateType, - tmpdir: &Path) { +fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( + cmd: &mut dyn Linker, + sess: &'a Session, + codegen_results: &CodegenResults, + crate_type: config::CrateType, + tmpdir: &Path, +) { // All of the heavy lifting has previously been accomplished by the // dependency_format module of the compiler. This is just crawling the // output of that module, adding crates as necessary. @@ -1272,8 +1324,10 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker, // will slurp up the object files inside), and linking to a dynamic library // involves just passing the right -l flag. - let formats = sess.dependency_formats.borrow(); - let data = formats.get(&crate_type).unwrap(); + let (_, data) = codegen_results.crate_info.dependency_formats + .iter() + .find(|(ty, _)| *ty == crate_type) + .expect("failed to find crate type in dependency format list"); // Invoke get_used_crates to ensure that we get a topological sorting of // crates. @@ -1337,7 +1391,9 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker, _ if codegen_results.crate_info.profiler_runtime == Some(cnum) => { add_static_crate::(cmd, sess, codegen_results, tmpdir, crate_type, cnum); } - _ if codegen_results.crate_info.sanitizer_runtime == Some(cnum) => { + _ if codegen_results.crate_info.sanitizer_runtime == Some(cnum) && + crate_type == config::CrateType::Executable => { + // Link the sanitizer runtimes only if we are actually producing an executable link_sanitizer_runtime::(cmd, sess, codegen_results, tmpdir, cnum); } // compiler-builtins are always placed last to ensure that they're @@ -1479,7 +1535,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker, let name = cratepath.file_name().unwrap().to_str().unwrap(); let name = &name[3..name.len() - 5]; // chop off lib/.rlib - time_ext(sess.time_extended(), Some(sess), &format!("altering {}.rlib", name), || { + time_ext(sess.time_extended(), &format!("altering {}.rlib", name), || { let mut archive = ::new(sess, &dst, Some(cratepath)); archive.update_symbols(); @@ -1562,7 +1618,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker, cmd.include_path(&fix_windows_verbatim_for_gcc(dir)); } let filestem = cratepath.file_stem().unwrap().to_str().unwrap(); - cmd.link_rust_dylib(&unlib(&sess.target, filestem), + cmd.link_rust_dylib(Symbol::intern(&unlib(&sess.target, filestem)), parent.unwrap_or(Path::new(""))); } } @@ -1585,10 +1641,12 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker, // generic function calls a native function, then the generic function must // be instantiated in the target crate, meaning that the native symbol must // also be resolved in the target crate. -pub fn add_upstream_native_libraries(cmd: &mut dyn Linker, - sess: &Session, - codegen_results: &CodegenResults, - crate_type: config::CrateType) { +pub fn add_upstream_native_libraries( + cmd: &mut dyn Linker, + sess: &Session, + codegen_results: &CodegenResults, + crate_type: config::CrateType, +) { // Be sure to use a topological sorting of crates because there may be // interdependencies between native libraries. When passing -nodefaultlibs, // for example, almost all native libraries depend on libc, so we have to @@ -1598,35 +1656,41 @@ pub fn add_upstream_native_libraries(cmd: &mut dyn Linker, // This passes RequireStatic, but the actual requirement doesn't matter, // we're just getting an ordering of crate numbers, we're not worried about // the paths. - let formats = sess.dependency_formats.borrow(); - let data = formats.get(&crate_type).unwrap(); + let (_, data) = codegen_results.crate_info.dependency_formats + .iter() + .find(|(ty, _)| *ty == crate_type) + .expect("failed to find crate type in dependency format list"); let crates = &codegen_results.crate_info.used_crates_static; for &(cnum, _) in crates { for lib in codegen_results.crate_info.native_libraries[&cnum].iter() { let name = match lib.name { - Some(ref l) => l, + Some(l) => l, None => continue, }; if !relevant_lib(sess, &lib) { continue } match lib.kind { - NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()), - NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()), + NativeLibraryKind::NativeUnknown => cmd.link_dylib(name), + NativeLibraryKind::NativeFramework => cmd.link_framework(name), NativeLibraryKind::NativeStaticNobundle => { // Link "static-nobundle" native libs only if the crate they originate from // is being linked statically to the current crate. If it's linked dynamically // or is an rlib already included via some other dylib crate, the symbols from // native libs will have already been included in that dylib. if data[cnum.as_usize() - 1] == Linkage::Static { - cmd.link_staticlib(&name.as_str()) + cmd.link_staticlib(name) } }, // ignore statically included native libraries here as we've // already included them when we included the rust library // previously - NativeLibraryKind::NativeStatic => {} + NativeLibraryKind::NativeStatic => {}, + NativeLibraryKind::NativeRawDylib => { + // FIXME(#58713): Proper handling for raw dylibs. + bug!("raw_dylib feature not yet implemented"); + }, } } } diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index 26091005f25aa..ff87f0b1547ce 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -14,9 +14,11 @@ use rustc::middle::dependency_format::Linkage; use rustc::session::Session; use rustc::session::config::{self, CrateType, OptLevel, DebugInfo, LinkerPluginLto, Lto}; +use rustc::middle::exported_symbols::ExportedSymbol; use rustc::ty::TyCtxt; use rustc_target::spec::{LinkerFlavor, LldFlavor}; use rustc_serialize::{json, Encoder}; +use syntax::symbol::Symbol; /// For all the linkers we support, and information they might /// need out of the shared crate context before we get rid of it. @@ -99,13 +101,13 @@ impl LinkerInfo { /// used to dispatch on whether a GNU-like linker (generally `ld.exe`) or an /// MSVC linker (e.g., `link.exe`) is being used. pub trait Linker { - fn link_dylib(&mut self, lib: &str); - fn link_rust_dylib(&mut self, lib: &str, path: &Path); - fn link_framework(&mut self, framework: &str); - fn link_staticlib(&mut self, lib: &str); + fn link_dylib(&mut self, lib: Symbol); + fn link_rust_dylib(&mut self, lib: Symbol, path: &Path); + fn link_framework(&mut self, framework: Symbol); + fn link_staticlib(&mut self, lib: Symbol); fn link_rlib(&mut self, lib: &Path); fn link_whole_rlib(&mut self, lib: &Path); - fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]); + fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]); fn include_path(&mut self, path: &Path); fn framework_path(&mut self, path: &Path); fn output_filename(&mut self, path: &Path); @@ -215,9 +217,13 @@ impl<'a> GccLinker<'a> { } impl<'a> Linker for GccLinker<'a> { - fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg(format!("-l{}", lib)); } - fn link_staticlib(&mut self, lib: &str) { - self.hint_static(); self.cmd.arg(format!("-l{}", lib)); + fn link_dylib(&mut self, lib: Symbol) { + self.hint_dynamic(); + self.cmd.arg(format!("-l{}", lib)); + } + fn link_staticlib(&mut self, lib: Symbol) { + self.hint_static(); + self.cmd.arg(format!("-l{}", lib)); } fn link_rlib(&mut self, lib: &Path) { self.hint_static(); self.cmd.arg(lib); } fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); } @@ -232,14 +238,14 @@ impl<'a> Linker for GccLinker<'a> { fn build_static_executable(&mut self) { self.cmd.arg("-static"); } fn args(&mut self, args: &[String]) { self.cmd.args(args); } - fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { + fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { self.hint_dynamic(); self.cmd.arg(format!("-l{}", lib)); } - fn link_framework(&mut self, framework: &str) { + fn link_framework(&mut self, framework: Symbol) { self.hint_dynamic(); - self.cmd.arg("-framework").arg(framework); + self.cmd.arg("-framework").sym_arg(framework); } // Here we explicitly ask that the entire archive is included into the @@ -248,7 +254,7 @@ impl<'a> Linker for GccLinker<'a> { // don't otherwise explicitly reference them. This can occur for // libraries which are just providing bindings, libraries with generic // functions, etc. - fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]) { + fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]) { self.hint_static(); let target = &self.sess.target.target; if !target.options.is_like_osx { @@ -430,10 +436,13 @@ impl<'a> Linker for GccLinker<'a> { // Write an LD version script let res: io::Result<()> = try { let mut f = BufWriter::new(File::create(&path)?); - writeln!(f, "{{\n global:")?; - for sym in self.info.exports[&crate_type].iter() { - debug!(" {};", sym); - writeln!(f, " {};", sym)?; + writeln!(f, "{{")?; + if !self.info.exports[&crate_type].is_empty() { + writeln!(f, " global:")?; + for sym in self.info.exports[&crate_type].iter() { + debug!(" {};", sym); + writeln!(f, " {};", sym)?; + } } writeln!(f, "\n local:\n *;\n}};")?; }; @@ -536,11 +545,11 @@ impl<'a> Linker for MsvcLinker<'a> { } } - fn link_dylib(&mut self, lib: &str) { + fn link_dylib(&mut self, lib: Symbol) { self.cmd.arg(&format!("{}.lib", lib)); } - fn link_rust_dylib(&mut self, lib: &str, path: &Path) { + fn link_rust_dylib(&mut self, lib: Symbol, path: &Path) { // When producing a dll, the MSVC linker may not actually emit a // `foo.lib` file if the dll doesn't actually export any symbols, so we // check to see if the file is there and just omit linking to it if it's @@ -551,7 +560,7 @@ impl<'a> Linker for MsvcLinker<'a> { } } - fn link_staticlib(&mut self, lib: &str) { + fn link_staticlib(&mut self, lib: Symbol) { self.cmd.arg(&format!("{}.lib", lib)); } @@ -602,11 +611,11 @@ impl<'a> Linker for MsvcLinker<'a> { fn framework_path(&mut self, _path: &Path) { bug!("frameworks are not supported on windows") } - fn link_framework(&mut self, _framework: &str) { + fn link_framework(&mut self, _framework: Symbol) { bug!("frameworks are not supported on windows") } - fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) { + fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) { // not supported? self.link_staticlib(lib); } @@ -737,8 +746,8 @@ impl<'a> Linker for EmLinker<'a> { self.cmd.arg("-L").arg(path); } - fn link_staticlib(&mut self, lib: &str) { - self.cmd.arg("-l").arg(lib); + fn link_staticlib(&mut self, lib: Symbol) { + self.cmd.arg("-l").sym_arg(lib); } fn output_filename(&mut self, path: &Path) { @@ -749,12 +758,12 @@ impl<'a> Linker for EmLinker<'a> { self.cmd.arg(path); } - fn link_dylib(&mut self, lib: &str) { + fn link_dylib(&mut self, lib: Symbol) { // Emscripten always links statically self.link_staticlib(lib); } - fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) { + fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) { // not supported? self.link_staticlib(lib); } @@ -764,7 +773,7 @@ impl<'a> Linker for EmLinker<'a> { self.link_rlib(lib); } - fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { + fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { self.link_dylib(lib); } @@ -800,7 +809,7 @@ impl<'a> Linker for EmLinker<'a> { bug!("frameworks are not supported on Emscripten") } - fn link_framework(&mut self, _framework: &str) { + fn link_framework(&mut self, _framework: Symbol) { bug!("frameworks are not supported on Emscripten") } @@ -945,12 +954,12 @@ impl<'a> WasmLd<'a> { } impl<'a> Linker for WasmLd<'a> { - fn link_dylib(&mut self, lib: &str) { - self.cmd.arg("-l").arg(lib); + fn link_dylib(&mut self, lib: Symbol) { + self.cmd.arg("-l").sym_arg(lib); } - fn link_staticlib(&mut self, lib: &str) { - self.cmd.arg("-l").arg(lib); + fn link_staticlib(&mut self, lib: Symbol) { + self.cmd.arg("-l").sym_arg(lib); } fn link_rlib(&mut self, lib: &Path) { @@ -992,16 +1001,16 @@ impl<'a> Linker for WasmLd<'a> { self.cmd.args(args); } - fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { - self.cmd.arg("-l").arg(lib); + fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { + self.cmd.arg("-l").sym_arg(lib); } - fn link_framework(&mut self, _framework: &str) { + fn link_framework(&mut self, _framework: Symbol) { panic!("frameworks not supported") } - fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) { - self.cmd.arg("-l").arg(lib); + fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) { + self.cmd.arg("-l").sym_arg(lib); } fn link_whole_rlib(&mut self, lib: &Path) { @@ -1084,18 +1093,41 @@ fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec { } } - let formats = tcx.sess.dependency_formats.borrow(); - let deps = formats[&crate_type].iter(); + let formats = tcx.dependency_formats(LOCAL_CRATE); + let deps = formats.iter().filter_map(|(t, list)| { + if *t == crate_type { + Some(list) + } else { + None + } + }).next().unwrap(); - for (index, dep_format) in deps.enumerate() { + for (index, dep_format) in deps.iter().enumerate() { let cnum = CrateNum::new(index + 1); // For each dependency that we are linking to statically ... if *dep_format == Linkage::Static { // ... we add its symbol list to our export list. for &(symbol, level) in tcx.exported_symbols(cnum).iter() { - if level.is_below_threshold(export_threshold) { - symbols.push(symbol.symbol_name(tcx).to_string()); + if !level.is_below_threshold(export_threshold) { + continue; } + + // Do not export generic symbols from upstream crates in linked + // artifact (notably the `dylib` crate type). The main reason + // for this is that `symbol_name` is actually wrong for generic + // symbols because it guesses the name we'd give them locally + // rather than the name it has upstream (depending on + // `share_generics` settings and such). + // + // To fix that issue we just say that linked artifacts, aka + // `dylib`s, never export generic symbols and they aren't + // available to downstream crates. (the not available part is + // handled elsewhere). + if let ExportedSymbol::Generic(..) = symbol { + continue; + } + + symbols.push(symbol.symbol_name(tcx).to_string()); } } } @@ -1159,19 +1191,19 @@ impl<'a> Linker for PtxLinker<'a> { ::std::mem::replace(&mut self.cmd, Command::new("")) } - fn link_dylib(&mut self, _lib: &str) { + fn link_dylib(&mut self, _lib: Symbol) { panic!("external dylibs not supported") } - fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) { + fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) { panic!("external dylibs not supported") } - fn link_staticlib(&mut self, _lib: &str) { + fn link_staticlib(&mut self, _lib: Symbol) { panic!("staticlibs not supported") } - fn link_whole_staticlib(&mut self, _lib: &str, _search_path: &[PathBuf]) { + fn link_whole_staticlib(&mut self, _lib: Symbol, _search_path: &[PathBuf]) { panic!("staticlibs not supported") } @@ -1179,7 +1211,7 @@ impl<'a> Linker for PtxLinker<'a> { panic!("frameworks not supported") } - fn link_framework(&mut self, _framework: &str) { + fn link_framework(&mut self, _framework: Symbol) { panic!("frameworks not supported") } diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index 2d9220f897cff..9078f77f1f7a2 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -13,7 +13,7 @@ use rustc::ty::{TyCtxt, SymbolName}; use rustc::ty::query::Providers; use rustc::ty::subst::SubstsRef; use rustc::util::nodemap::{FxHashMap, DefIdMap}; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::vec::IndexVec; use syntax::ext::allocator::ALLOCATOR_METHODS; pub type ExportedSymbols = FxHashMap< @@ -94,14 +94,14 @@ fn reachable_non_generics_provider( // Only consider nodes that actually have exported symbols. Node::Item(&hir::Item { - node: hir::ItemKind::Static(..), + kind: hir::ItemKind::Static(..), .. }) | Node::Item(&hir::Item { - node: hir::ItemKind::Fn(..), .. + kind: hir::ItemKind::Fn(..), .. }) | Node::ImplItem(&hir::ImplItem { - node: hir::ImplItemKind::Method(..), + kind: hir::ImplItemKind::Method(..), .. }) => { let def_id = tcx.hir().local_def_id(hir_id); @@ -121,7 +121,7 @@ fn reachable_non_generics_provider( }) .map(|def_id| { let export_level = if special_runtime_crate { - let name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str(); + let name = tcx.symbol_name(Instance::mono(tcx, def_id)).name.as_str(); // We can probably do better here by just ensuring that // it has hidden visibility rather than public // visibility, as this is primarily here to ensure it's @@ -298,7 +298,7 @@ fn upstream_monomorphizations_provider( }; for &cnum in cnums.iter() { - for &(ref exported_symbol, _) in tcx.exported_symbols(cnum).iter() { + for (exported_symbol, _) in tcx.exported_symbols(cnum).iter() { if let &ExportedSymbol::Generic(def_id, substs) = exported_symbol { let substs_map = instances.entry(def_id).or_default(); @@ -367,7 +367,7 @@ fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel // Emscripten cannot export statics, so reduce their export level here if tcx.sess.target.target.options.is_like_emscripten { if let Some(Node::Item(&hir::Item { - node: hir::ItemKind::Static(..), + kind: hir::ItemKind::Static(..), .. })) = tcx.hir().get_if_local(sym_def_id) { return SymbolExportLevel::Rust; diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index c9e4663fdbddf..481db26e1a84d 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -19,20 +19,18 @@ use rustc::util::nodemap::FxHashMap; use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc::ty::TyCtxt; use rustc::util::common::{time_depth, set_time_depth, print_time_passes_entry}; -use rustc::util::profiling::SelfProfiler; +use rustc::util::profiling::SelfProfilerRef; use rustc_fs_util::link_or_copy; use rustc_data_structures::svh::Svh; -use rustc_errors::{Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId}; +use rustc_errors::{Handler, Level, FatalError, DiagnosticId}; use rustc_errors::emitter::{Emitter}; use rustc_target::spec::MergeFunctions; use syntax::attr; use syntax::ext::hygiene::ExpnId; -use syntax_pos::MultiSpan; use syntax_pos::symbol::{Symbol, sym}; use jobserver::{Client, Acquired}; use std::any::Any; -use std::borrow::Cow; use std::fs; use std::io; use std::mem; @@ -197,42 +195,13 @@ impl Clone for TargetMachineFactory { } } -pub struct ProfileGenericActivityTimer { - profiler: Option>, - label: Cow<'static, str>, -} - -impl ProfileGenericActivityTimer { - pub fn start( - profiler: Option>, - label: Cow<'static, str>, - ) -> ProfileGenericActivityTimer { - if let Some(profiler) = &profiler { - profiler.start_activity(label.clone()); - } - - ProfileGenericActivityTimer { - profiler, - label, - } - } -} - -impl Drop for ProfileGenericActivityTimer { - fn drop(&mut self) { - if let Some(profiler) = &self.profiler { - profiler.end_activity(self.label.clone()); - } - } -} - /// Additional resources used by optimize_and_codegen (not module specific) #[derive(Clone)] pub struct CodegenContext { // Resources needed when running LTO pub backend: B, pub time_passes: bool, - pub profiler: Option>, + pub prof: SelfProfilerRef, pub lto: Lto, pub no_landing_pads: bool, pub save_temps: bool, @@ -284,31 +253,6 @@ impl CodegenContext { ModuleKind::Allocator => &self.allocator_module_config, } } - - #[inline(never)] - #[cold] - fn profiler_active ()>(&self, f: F) { - match &self.profiler { - None => bug!("profiler_active() called but there was no profiler active"), - Some(profiler) => { - f(&*profiler); - } - } - } - - #[inline(always)] - pub fn profile ()>(&self, f: F) { - if unlikely!(self.profiler.is_some()) { - self.profiler_active(f) - } - } - - pub fn profile_activity( - &self, - label: impl Into>, - ) -> ProfileGenericActivityTimer { - ProfileGenericActivityTimer::start(self.profiler.clone(), label.into()) - } } fn generate_lto_work( @@ -317,7 +261,7 @@ fn generate_lto_work( needs_thin_lto: Vec<(String, B::ThinBuffer)>, import_only_modules: Vec<(SerializedModule, WorkProduct)> ) -> Vec<(WorkItem, u64)> { - cgcx.profile(|p| p.start_activity("codegen_run_lto")); + let _prof_timer = cgcx.prof.generic_activity("codegen_run_lto"); let (lto_modules, copy_jobs) = if !needs_fat_lto.is_empty() { assert!(needs_thin_lto.is_empty()); @@ -344,8 +288,6 @@ fn generate_lto_work( }), 0) })).collect(); - cgcx.profile(|p| p.end_activity("codegen_run_lto")); - result } @@ -377,10 +319,11 @@ pub fn start_async_codegen( backend: B, tcx: TyCtxt<'_>, metadata: EncodedMetadata, - coordinator_receive: Receiver>, total_cgus: usize, ) -> OngoingCodegen { + let (coordinator_send, coordinator_receive) = channel(); let sess = tcx.sess; + let crate_name = tcx.crate_name(LOCAL_CRATE); let crate_hash = tcx.crate_hash(LOCAL_CRATE); let no_builtins = attr::contains_name(&tcx.hir().krate().attrs, sym::no_builtins); @@ -501,7 +444,8 @@ pub fn start_async_codegen( sess.jobserver.clone(), Arc::new(modules_config), Arc::new(metadata_config), - Arc::new(allocator_config)); + Arc::new(allocator_config), + coordinator_send.clone()); OngoingCodegen { backend, @@ -512,7 +456,7 @@ pub fn start_async_codegen( linker_info, crate_info, - coordinator_send: tcx.tx_to_llvm_workers.lock().clone(), + coordinator_send, codegen_worker_receive, shared_emitter_main, future: coordinator_thread, @@ -1006,8 +950,9 @@ fn start_executing_work( modules_config: Arc, metadata_config: Arc, allocator_config: Arc, + tx_to_llvm_workers: Sender>, ) -> thread::JoinHandle> { - let coordinator_send = tcx.tx_to_llvm_workers.lock().clone(); + let coordinator_send = tx_to_llvm_workers; let sess = tcx.sess; // Compute the set of symbols we need to retain when doing LTO (if we need to) @@ -1049,7 +994,7 @@ fn start_executing_work( }).expect("failed to spawn helper thread"); let mut each_linked_rlib_for_lto = Vec::new(); - drop(link::each_linked_rlib(sess, crate_info, &mut |cnum, path| { + drop(link::each_linked_rlib(crate_info, &mut |cnum, path| { if link::ignored_for_lto(sess, crate_info, cnum) { return } @@ -1087,7 +1032,7 @@ fn start_executing_work( save_temps: sess.opts.cg.save_temps, opts: Arc::new(sess.opts.clone()), time_passes: sess.time_extended(), - profiler: sess.self_profiling.clone(), + prof: sess.prof.clone(), exported_symbols, plugin_passes: sess.plugin_llvm_passes.borrow().clone(), remark: sess.opts.cg.remark.clone(), @@ -1644,12 +1589,8 @@ fn spawn_work( // as a diagnostic was already sent off to the main thread - just // surface that there was an error in this worker. bomb.result = { - let label = work.name(); - cgcx.profile(|p| p.start_activity(label.clone())); - let result = execute_work_item(&cgcx, work).ok(); - cgcx.profile(|p| p.end_activity(label)); - - result + let _prof_timer = cgcx.prof.generic_activity(&work.name()); + execute_work_item(&cgcx, work).ok() }; }); } @@ -1725,7 +1666,7 @@ impl SharedEmitter { } impl Emitter for SharedEmitter { - fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) { + fn emit_diagnostic(&mut self, db: &rustc_errors::Diagnostic) { drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { msg: db.message(), code: db.code.clone(), @@ -1760,25 +1701,15 @@ impl SharedEmitterMain { match message { Ok(SharedEmitterMessage::Diagnostic(diag)) => { let handler = sess.diagnostic(); - match diag.code { - Some(ref code) => { - handler.emit_with_code(&MultiSpan::new(), - &diag.msg, - code.clone(), - diag.lvl); - } - None => { - handler.emit(&MultiSpan::new(), - &diag.msg, - diag.lvl); - } + let mut d = rustc_errors::Diagnostic::new(diag.lvl, &diag.msg); + if let Some(code) = diag.code { + d.code(code); } + handler.emit_diagnostic(&d); + handler.abort_if_errors_and_should_abort(); } Ok(SharedEmitterMessage::InlineAsmError(cookie, msg)) => { - match ExpnId::from_u32(cookie).expn_info() { - Some(ei) => sess.span_err(ei.call_site, &msg), - None => sess.err(&msg), - } + sess.span_err(ExpnId::from_u32(cookie).expn_data().call_site, &msg) } Ok(SharedEmitterMessage::AbortIfErrors) => { sess.abort_if_errors(); @@ -1868,7 +1799,7 @@ impl OngoingCodegen { // These are generally cheap and won't throw off scheduling. let cost = 0; - submit_codegened_module_to_llvm(&self.backend, tcx, module, cost); + submit_codegened_module_to_llvm(&self.backend, &self.coordinator_send, module, cost); } pub fn codegen_finished(&self, tcx: TyCtxt<'_>) { @@ -1910,12 +1841,12 @@ impl OngoingCodegen { pub fn submit_codegened_module_to_llvm( _backend: &B, - tcx: TyCtxt<'_>, + tx_to_llvm_workers: &Sender>, module: ModuleCodegen, cost: u64, ) { let llvm_work_item = WorkItem::Optimize(module); - drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::CodegenDone:: { + drop(tx_to_llvm_workers.send(Box::new(Message::CodegenDone:: { llvm_work_item, cost, }))); @@ -1923,11 +1854,11 @@ pub fn submit_codegened_module_to_llvm( pub fn submit_post_lto_module_to_llvm( _backend: &B, - tcx: TyCtxt<'_>, + tx_to_llvm_workers: &Sender>, module: CachedModuleCodegen, ) { let llvm_work_item = WorkItem::CopyPostLtoArtifacts(module); - drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::CodegenDone:: { + drop(tx_to_llvm_workers.send(Box::new(Message::CodegenDone:: { llvm_work_item, cost: 0, }))); @@ -1936,6 +1867,7 @@ pub fn submit_post_lto_module_to_llvm( pub fn submit_pre_lto_module_to_llvm( _backend: &B, tcx: TyCtxt<'_>, + tx_to_llvm_workers: &Sender>, module: CachedModuleCodegen, ) { let filename = pre_lto_bitcode_filename(&module.name); @@ -1950,7 +1882,7 @@ pub fn submit_pre_lto_module_to_llvm( }) }; // Schedule the module to be loaded - drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::AddImportOnlyModule:: { + drop(tx_to_llvm_workers.send(Box::new(Message::AddImportOnlyModule:: { module_data: SerializedModule::FromUncompressedFile(mmap), work_product: module.source, }))); diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index cdc54bb179ebf..935087714a7eb 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -29,7 +29,7 @@ use rustc::util::common::{time, print_time_passes_entry, set_time_depth, time_de use rustc::session::config::{self, EntryFnType, Lto}; use rustc::session::Session; use rustc::util::nodemap::FxHashMap; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use rustc_codegen_utils::{symbol_names_test, check_for_rustc_errors_attr}; use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; use crate::mir::place::PlaceRef; @@ -43,11 +43,9 @@ use crate::mir; use crate::traits::*; -use std::any::Any; use std::cmp; use std::ops::{Deref, DerefMut}; use std::time::{Instant, Duration}; -use std::sync::mpsc; use syntax_pos::Span; use syntax::attr; use rustc::hir; @@ -96,7 +94,7 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ret_ty: Bx::Type, op: hir::BinOpKind, ) -> Bx::Value { - let signed = match t.sty { + let signed = match t.kind { ty::Float(_) => { let cmp = bin_op_to_fcmp_predicate(op); let cmp = bx.fcmp(cmp, lhs, rhs); @@ -130,7 +128,7 @@ pub fn unsized_info<'tcx, Cx: CodegenMethods<'tcx>>( ) -> Cx::Value { let (source, target) = cx.tcx().struct_lockstep_tails_erasing_lifetimes(source, target, cx.param_env()); - match (&source.sty, &target.sty) { + match (&source.kind, &target.kind) { (&ty::Array(_, len), &ty::Slice(_)) => { cx.const_usize(len.eval_usize(cx.tcx(), ty::ParamEnv::reveal_all())) } @@ -160,7 +158,7 @@ pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( dst_ty: Ty<'tcx>, ) -> (Bx::Value, Bx::Value) { debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty); - match (&src_ty.sty, &dst_ty.sty) { + match (&src_ty.kind, &dst_ty.kind) { (&ty::Ref(_, a, _), &ty::Ref(_, b, _)) | (&ty::Ref(_, a, _), @@ -232,7 +230,7 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( }; OperandValue::Pair(base, info).store(bx, dst); }; - match (&src_ty.sty, &dst_ty.sty) { + match (&src_ty.kind, &dst_ty.kind) { (&ty::Ref(..), &ty::Ref(..)) | (&ty::Ref(..), &ty::RawPtr(..)) | (&ty::RawPtr(..), &ty::RawPtr(..)) => { @@ -456,7 +454,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &' let arg_argv = param_argv; let (start_fn, args) = if use_start_lang_item { - let start_def_id = cx.tcx().require_lang_item(StartFnLangItem); + let start_def_id = cx.tcx().require_lang_item(StartFnLangItem, None); let start_fn = callee::resolve_and_get_fn( cx, start_def_id, @@ -482,19 +480,13 @@ pub fn codegen_crate( tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, need_metadata_module: bool, - rx: mpsc::Receiver>, ) -> OngoingCodegen { check_for_rustc_errors_attr(tcx); // Skip crate items and just output metadata in -Z no-codegen mode. if tcx.sess.opts.debugging_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { - let ongoing_codegen = start_async_codegen( - backend, - tcx, - metadata, - rx, - 1); + let ongoing_codegen = start_async_codegen(backend, tcx, metadata, 1); ongoing_codegen.codegen_finished(tcx); @@ -523,12 +515,7 @@ pub fn codegen_crate( } } - let ongoing_codegen = start_async_codegen( - backend.clone(), - tcx, - metadata, - rx, - codegen_units.len()); + let ongoing_codegen = start_async_codegen(backend.clone(), tcx, metadata, codegen_units.len()); let ongoing_codegen = AbortCodegenOnDrop::(Some(ongoing_codegen)); // Codegen an allocator shim, if necessary. @@ -539,7 +526,7 @@ pub fn codegen_crate( // linkage, then it's already got an allocator shim and we'll be using that // one instead. If nothing exists then it's our job to generate the // allocator! - let any_dynamic_crate = tcx.sess.dependency_formats.borrow() + let any_dynamic_crate = tcx.dependency_formats(LOCAL_CRATE) .iter() .any(|(_, list)| { use rustc::middle::dependency_format::Linkage; @@ -572,7 +559,7 @@ pub fn codegen_crate( if need_metadata_module { // Codegen the encoded metadata. - tcx.sess.profiler(|p| p.start_activity("codegen crate metadata")); + let _prof_timer = tcx.prof.generic_activity("codegen_crate_metadata"); let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], @@ -583,7 +570,6 @@ pub fn codegen_crate( backend.write_compressed_metadata(tcx, &ongoing_codegen.metadata, &mut metadata_llvm_module); }); - tcx.sess.profiler(|p| p.end_activity("codegen crate metadata")); let metadata_module = ModuleCodegen { name: metadata_cgu_name, @@ -612,22 +598,22 @@ pub fn codegen_crate( match cgu_reuse { CguReuse::No => { - tcx.sess.profiler(|p| p.start_activity(format!("codegen {}", cgu.name()))); let start_time = Instant::now(); - backend.compile_codegen_unit(tcx, *cgu.name()); + backend.compile_codegen_unit(tcx, *cgu.name(), &ongoing_codegen.coordinator_send); total_codegen_time += start_time.elapsed(); - tcx.sess.profiler(|p| p.end_activity(format!("codegen {}", cgu.name()))); false } CguReuse::PreLto => { - submit_pre_lto_module_to_llvm(&backend, tcx, CachedModuleCodegen { + submit_pre_lto_module_to_llvm(&backend, tcx, &ongoing_codegen.coordinator_send, + CachedModuleCodegen { name: cgu.name().to_string(), source: cgu.work_product(tcx), }); true } CguReuse::PostLto => { - submit_post_lto_module_to_llvm(&backend, tcx, CachedModuleCodegen { + submit_post_lto_module_to_llvm(&backend, &ongoing_codegen.coordinator_send, + CachedModuleCodegen { name: cgu.name().to_string(), source: cgu.work_product(tcx), }); @@ -731,6 +717,7 @@ impl CrateInfo { used_crate_source: Default::default(), lang_item_to_crate: Default::default(), missing_lang_items: Default::default(), + dependency_formats: tcx.dependency_formats(LOCAL_CRATE), }; let lang_items = tcx.lang_items(); diff --git a/src/librustc_codegen_ssa/callee.rs b/src/librustc_codegen_ssa/callee.rs index 4744dd6302fb3..6ba6774cbf881 100644 --- a/src/librustc_codegen_ssa/callee.rs +++ b/src/librustc_codegen_ssa/callee.rs @@ -18,6 +18,23 @@ pub fn resolve_and_get_fn<'tcx, Cx: CodegenMethods<'tcx>>( ) } +pub fn resolve_and_get_fn_for_ptr<'tcx, + Cx: Backend<'tcx> + MiscMethods<'tcx> + TypeMethods<'tcx> +>( + cx: &Cx, + def_id: DefId, + substs: SubstsRef<'tcx>, +) -> Cx::Value { + cx.get_fn( + ty::Instance::resolve_for_fn_ptr( + cx.tcx(), + ty::ParamEnv::reveal_all(), + def_id, + substs + ).unwrap() + ) +} + pub fn resolve_and_get_fn_for_vtable<'tcx, Cx: Backend<'tcx> + MiscMethods<'tcx> + TypeMethods<'tcx> >( diff --git a/src/librustc_codegen_ssa/common.rs b/src/librustc_codegen_ssa/common.rs index 6376512ca4025..e3aa35ef4eb5e 100644 --- a/src/librustc_codegen_ssa/common.rs +++ b/src/librustc_codegen_ssa/common.rs @@ -109,14 +109,11 @@ pub enum TypeKind { // for now we content ourselves with providing a no-op HashStable // implementation for CGUs. mod temp_stable_hash_impls { - use rustc_data_structures::stable_hasher::{StableHasherResult, StableHasher, - HashStable}; + use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use crate::ModuleCodegen; impl HashStable for ModuleCodegen { - fn hash_stable(&self, - _: &mut HCX, - _: &mut StableHasher) { + fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) { // do nothing } } diff --git a/src/librustc_codegen_ssa/debuginfo/type_names.rs b/src/librustc_codegen_ssa/debuginfo/type_names.rs index ea39913d4b91b..d875c60959cba 100644 --- a/src/librustc_codegen_ssa/debuginfo/type_names.rs +++ b/src/librustc_codegen_ssa/debuginfo/type_names.rs @@ -32,7 +32,7 @@ pub fn push_debuginfo_type_name<'tcx>( // .natvis visualizers (and perhaps other existing native debuggers?) let cpp_like_names = tcx.sess.target.target.options.is_like_msvc; - match t.sty { + match t.kind { ty::Bool => output.push_str("bool"), ty::Char => output.push_str("char"), ty::Str => output.push_str("str"), @@ -190,11 +190,17 @@ pub fn push_debuginfo_type_name<'tcx>( // processing visited.remove(t); }, - ty::Closure(..) => { - output.push_str("closure"); + ty::Closure(def_id, ..) => { + output.push_str(&format!( + "closure-{}", + tcx.def_key(def_id).disambiguated_data.disambiguator + )); } - ty::Generator(..) => { - output.push_str("generator"); + ty::Generator(def_id, ..) => { + output.push_str(&format!( + "generator-{}", + tcx.def_key(def_id).disambiguated_data.disambiguator + )); } ty::Error | ty::Infer(_) | diff --git a/src/librustc_codegen_ssa/error_codes.rs b/src/librustc_codegen_ssa/error_codes.rs index 8d46dcb7c09c3..8ff41c275a8f4 100644 --- a/src/librustc_codegen_ssa/error_codes.rs +++ b/src/librustc_codegen_ssa/error_codes.rs @@ -1,4 +1,4 @@ -register_long_diagnostics! { +syntax::register_diagnostics! { E0668: r##" Malformed inline assembly rejected by LLVM. diff --git a/src/librustc_codegen_ssa/glue.rs b/src/librustc_codegen_ssa/glue.rs index 7fd9f67e2f45b..9818bb78e757b 100644 --- a/src/librustc_codegen_ssa/glue.rs +++ b/src/librustc_codegen_ssa/glue.rs @@ -20,7 +20,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let align = bx.const_usize(layout.align.abi.bytes()); return (size, align); } - match t.sty { + match t.kind { ty::Dynamic(..) => { // load size/align from vtable let vtable = info.unwrap(); @@ -64,7 +64,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let size = bx.add(sized_size, unsized_size); // Packed types ignore the alignment of their fields. - if let ty::Adt(def, _) = t.sty { + if let ty::Adt(def, _) = t.kind { if def.repr.packed() { unsized_align = sized_align; } diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index 73ef16e009146..d700001430e20 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -4,13 +4,13 @@ #![feature(box_syntax)] #![feature(core_intrinsics)] #![feature(libc)] -#![feature(rustc_diagnostic_macros)] +#![feature(slice_patterns)] #![feature(stmt_expr_attributes)] #![feature(try_blocks)] #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(trusted_len)] -#![feature(mem_take)] +#![feature(associated_type_bounds)] #![recursion_limit="256"] @@ -20,7 +20,6 @@ #[macro_use] extern crate log; #[macro_use] extern crate rustc; -#[macro_use] extern crate rustc_data_structures; #[macro_use] extern crate syntax; use std::path::PathBuf; @@ -32,10 +31,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::svh::Svh; use rustc::middle::cstore::{LibSource, CrateSource, NativeLibrary}; +use rustc::middle::dependency_format::Dependencies; use syntax_pos::symbol::Symbol; -// N.B., this module needs to be declared first so diagnostics are -// registered before they are used. mod error_codes; pub mod common; @@ -127,6 +125,7 @@ bitflags::bitflags! { } /// Misc info we load from metadata to persist beyond the tcx. +#[derive(Debug)] pub struct CrateInfo { pub panic_runtime: Option, pub compiler_builtins: Option, @@ -142,6 +141,7 @@ pub struct CrateInfo { pub used_crates_dynamic: Vec<(CrateNum, LibSource)>, pub lang_item_to_crate: FxHashMap, pub missing_lang_items: FxHashMap>, + pub dependency_formats: Lrc, } @@ -156,5 +156,3 @@ pub struct CodegenResults { pub linker_info: back::linker::LinkerInfo, pub crate_info: CrateInfo, } - -__build_diagnostic_array! { librustc_codegen_ssa, DIAGNOSTICS } diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index cc0c733c22410..ea1cf926fccf0 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -1,9 +1,9 @@ //! An analysis to determine which locals require allocas and //! which do not. -use rustc_data_structures::bit_set::BitSet; +use rustc_index::bit_set::BitSet; use rustc_data_structures::graph::dominators::Dominators; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_index::vec::{Idx, IndexVec}; use rustc::mir::{self, Location, TerminatorKind}; use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext}; use rustc::mir::traversal; @@ -105,7 +105,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { ) { let cx = self.fx.cx; - if let Some(proj) = place_ref.projection { + if let [proj_base @ .., elem] = place_ref.projection { // Allow uses of projections that are ZSTs or from scalar fields. let is_consume = match context { PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | @@ -114,12 +114,12 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { }; if is_consume { let base_ty = - mir::Place::ty_from(place_ref.base, &proj.base, self.fx.mir, cx.tcx()); + mir::Place::ty_from(place_ref.base, proj_base, self.fx.mir, cx.tcx()); let base_ty = self.fx.monomorphize(&base_ty); // ZSTs don't require any actual memory access. let elem_ty = base_ty - .projection_ty(cx.tcx(), &proj.elem) + .projection_ty(cx.tcx(), elem) .ty; let elem_ty = self.fx.monomorphize(&elem_ty); let span = if let mir::PlaceBase::Local(index) = place_ref.base { @@ -131,7 +131,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { return; } - if let mir::ProjectionElem::Field(..) = proj.elem { + if let mir::ProjectionElem::Field(..) = elem { let layout = cx.spanned_layout_of(base_ty.ty, span); if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) { // Recurse with the same context, instead of `Projection`, @@ -140,7 +140,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { self.process_place( &mir::PlaceRef { base: place_ref.base, - projection: &proj.base, + projection: proj_base, }, context, location, @@ -151,11 +151,11 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { } // A deref projection only reads the pointer, never needs the place. - if let mir::ProjectionElem::Deref = proj.elem { + if let mir::ProjectionElem::Deref = elem { self.process_place( &mir::PlaceRef { base: place_ref.base, - projection: &proj.base, + projection: proj_base, }, PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), location @@ -168,7 +168,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { // visit_place API let mut context = context; - if place_ref.projection.is_some() { + if !place_ref.projection.is_empty() { context = if context.is_mutating_use() { PlaceContext::MutatingUse(MutatingUseContext::Projection) } else { @@ -177,10 +177,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { } self.visit_place_base(place_ref.base, context, location); - - if let Some(box proj) = place_ref.projection { - self.visit_projection(place_ref.base, proj, context, location); - } + self.visit_projection(place_ref.base, place_ref.projection, context, location); } } @@ -196,7 +193,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> if let mir::Place { base: mir::PlaceBase::Local(index), - projection: None, + projection: box [], } = *place { self.assign(index, location); let decl_span = self.fx.mir.local_decls[index].source_info.span; @@ -221,7 +218,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> mir::TerminatorKind::Call { func: mir::Operand::Constant(ref c), ref args, .. - } => match c.ty.sty { + } => match c.literal.ty.kind { ty::FnDef(did, _) => Some((did, args)), _ => None, }, diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 006ebcbdec672..b0df81ba1abea 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -1,9 +1,10 @@ +use rustc_index::vec::Idx; use rustc::middle::lang_items; use rustc::ty::{self, Ty, TypeFoldable, Instance}; use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt}; use rustc::mir::{self, Place, PlaceBase, Static, StaticKind}; use rustc::mir::interpret::PanicInfo; -use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode}; +use rustc_target::abi::call::{ArgType, FnType, PassMode}; use rustc_target::spec::abi::Abi; use crate::base; use crate::MemFlags; @@ -14,7 +15,7 @@ use crate::traits::*; use std::borrow::Cow; -use syntax::symbol::LocalInternedString; +use syntax::symbol::Symbol; use syntax_pos::Pos; use super::{FunctionCx, LocalRef}; @@ -148,6 +149,26 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'a, 'tcx> { } } } + + // Generate sideeffect intrinsic if jumping to any of the targets can form + // a loop. + fn maybe_sideeffect<'b, 'tcx2: 'b, Bx: BuilderMethods<'b, 'tcx2>>( + &self, + mir: &'b mir::Body<'tcx>, + bx: &mut Bx, + targets: &[mir::BasicBlock], + ) { + if bx.tcx().sess.opts.debugging_opts.insert_sideeffect { + if targets.iter().any(|target| { + *target <= *self.bb + && target + .start_location() + .is_predecessor_of(self.bb.start_location(), mir) + }) { + bx.sideeffect(); + } + } + } } /// Codegen implementations for some terminator variants. @@ -196,6 +217,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let lltrue = helper.llblock(self, targets[0]); let llfalse = helper.llblock(self, targets[1]); if switch_ty == bx.tcx().types.bool { + helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice()); // Don't generate trivial icmps when switching on bool if let [0] = values[..] { bx.cond_br(discr.immediate(), llfalse, lltrue); @@ -209,9 +231,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ); let llval = bx.const_uint_big(switch_llty, values[0]); let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval); + helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice()); bx.cond_br(cmp, lltrue, llfalse); } } else { + helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice()); let (otherwise, targets) = targets.split_last().unwrap(); bx.switch( discr.immediate(), @@ -224,14 +248,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } fn codegen_return_terminator(&mut self, mut bx: Bx) { + // Call `va_end` if this is the definition of a C-variadic function. if self.fn_ty.c_variadic { - match self.va_list_ref { - Some(va_list) => { + // The `VaList` "spoofed" argument is just after all the real arguments. + let va_list_arg_idx = self.fn_ty.args.len(); + match self.locals[mir::Local::new(1 + va_list_arg_idx)] { + LocalRef::Place(va_list) => { bx.va_end(va_list.llval); } - None => { - bug!("C-variadic function must have a `va_list_ref`"); - } + _ => bug!("C-variadic function must have a `VaList` place"), } } if self.fn_ty.ret.layout.abi.is_uninhabited() { @@ -242,18 +267,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } let llval = match self.fn_ty.ret.mode { - PassMode::Ignore(IgnoreMode::Zst) | PassMode::Indirect(..) => { + PassMode::Ignore | PassMode::Indirect(..) => { bx.ret_void(); return; } - PassMode::Ignore(IgnoreMode::CVarArgs) => { - bug!("C-variadic arguments should never be the return type"); - } - PassMode::Direct(_) | PassMode::Pair(..) => { let op = - self.codegen_consume(&mut bx, &mir::Place::RETURN_PLACE.as_ref()); + self.codegen_consume(&mut bx, &mir::Place::return_place().as_ref()); if let Ref(llval, _, align) = op.val { bx.load(llval, align) } else { @@ -276,7 +297,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let llslot = match op.val { Immediate(_) | Pair(..) => { let scratch = - PlaceRef::alloca(&mut bx, self.fn_ty.ret.layout, "ret"); + PlaceRef::alloca(&mut bx, self.fn_ty.ret.layout); op.val.store(&mut bx, scratch); scratch.llval } @@ -310,6 +331,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def { // we don't actually need to drop anything. + helper.maybe_sideeffect(self.mir, &mut bx, &[target]); helper.funclet_br(self, &mut bx, target); return } @@ -323,7 +345,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { args1 = [place.llval]; &args1[..] }; - let (drop_fn, fn_ty) = match ty.sty { + let (drop_fn, fn_ty) = match ty.kind { ty::Dynamic(..) => { let sig = drop_fn.fn_sig(self.cx.tcx()); let sig = self.cx.tcx().normalize_erasing_late_bound_regions( @@ -337,9 +359,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } _ => { (bx.get_fn(drop_fn), - FnType::of_instance(&bx, &drop_fn)) + FnType::of_instance(&bx, drop_fn)) } }; + helper.maybe_sideeffect(self.mir, &mut bx, &[target]); helper.do_call(self, &mut bx, fn_ty, drop_fn, args, Some((ReturnDest::Nothing, target)), unwind); @@ -375,6 +398,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Don't codegen the panic block if success if known. if const_cond == Some(expected) { + helper.maybe_sideeffect(self.mir, &mut bx, &[target]); helper.funclet_br(self, &mut bx, target); return; } @@ -385,6 +409,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Create the failure block and the conditional branch to it. let lltarget = helper.llblock(self, target); let panic_block = self.new_block("panic"); + helper.maybe_sideeffect(self.mir, &mut bx, &[target]); if expected { bx.cond_br(cond, lltarget, panic_block.llbb()); } else { @@ -397,7 +422,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Get the location information. let loc = bx.sess().source_map().lookup_char_pos(span.lo()); - let filename = LocalInternedString::intern(&loc.file.name.to_string()); + let filename = Symbol::intern(&loc.file.name.to_string()); let line = bx.const_u32(loc.line as u32); let col = bx.const_u32(loc.col.to_usize() as u32 + 1); @@ -418,8 +443,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { vec![file_line_col, index, len]) } _ => { - let str = msg.description(); - let msg_str = LocalInternedString::intern(str); + let msg_str = Symbol::intern(msg.description()); let msg_file_line_col = bx.static_panic_msg( Some(msg_str), filename, @@ -435,7 +459,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Obtain the panic entry point. let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item); let instance = ty::Instance::mono(bx.tcx(), def_id); - let fn_ty = FnType::of_instance(&bx, &instance); + let fn_ty = FnType::of_instance(&bx, instance); let llfn = bx.get_fn(instance); // Codegen the actual panic invoke/call. @@ -456,7 +480,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. let callee = self.codegen_operand(&mut bx, func); - let (instance, mut llfn) = match callee.layout.ty.sty { + let (instance, mut llfn) = match callee.layout.ty.kind { ty::FnDef(def_id, substs) => { (Some(ty::Instance::resolve(bx.tcx(), ty::ParamEnv::reveal_all(), @@ -489,6 +513,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if let Some(destination_ref) = destination.as_ref() { let &(ref dest, target) = destination_ref; self.codegen_transmute(&mut bx, &args[0], dest); + helper.maybe_sideeffect(self.mir, &mut bx, &[target]); helper.funclet_br(self, &mut bx, target); } else { // If we are trying to transmute to an uninhabited type, @@ -503,10 +528,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - // The "spoofed" `VaListImpl` added to a C-variadic functions signature - // should not be included in the `extra_args` calculation. - let extra_args_start_idx = sig.inputs().len() - if sig.c_variadic { 1 } else { 0 }; - let extra_args = &args[extra_args_start_idx..]; + let extra_args = &args[sig.inputs().len()..]; let extra_args = extra_args.iter().map(|op_arg| { let op_ty = op_arg.ty(self.mir, bx.tcx()); self.monomorphize(&op_ty) @@ -519,6 +541,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Some(ty::InstanceDef::DropGlue(_, None)) => { // Empty drop glue; a no-op. let &(_, target) = destination.as_ref().unwrap(); + helper.maybe_sideeffect(self.mir, &mut bx, &[target]); helper.funclet_br(self, &mut bx, target); return; } @@ -531,7 +554,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let layout = bx.layout_of(ty); if layout.abi.is_uninhabited() { let loc = bx.sess().source_map().lookup_char_pos(span.lo()); - let filename = LocalInternedString::intern(&loc.file.name.to_string()); + let filename = Symbol::intern(&loc.file.name.to_string()); let line = bx.const_u32(loc.line as u32); let col = bx.const_u32(loc.col.to_usize() as u32 + 1); @@ -539,7 +562,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { "Attempted to instantiate uninhabited type {}", ty ); - let msg_str = LocalInternedString::intern(&str); + let msg_str = Symbol::intern(&str); let msg_file_line_col = bx.static_panic_msg( Some(msg_str), filename, @@ -552,9 +575,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let def_id = common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem); let instance = ty::Instance::mono(bx.tcx(), def_id); - let fn_ty = FnType::of_instance(&bx, &instance); + let fn_ty = FnType::of_instance(&bx, instance); let llfn = bx.get_fn(instance); + if let Some((_, target)) = destination.as_ref() { + helper.maybe_sideeffect(self.mir, &mut bx, &[*target]); + } // Codegen the actual panic invoke/call. helper.do_call( self, @@ -567,7 +593,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ); } else { // a NOP - helper.funclet_br(self, &mut bx, destination.as_ref().unwrap().1) + let target = destination.as_ref().unwrap().1; + helper.maybe_sideeffect(self.mir, &mut bx, &[target]); + helper.funclet_br(self, &mut bx, target); } return; } @@ -609,19 +637,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Operand::Copy( Place { base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(promoted), + kind: StaticKind::Promoted(promoted, _), ty, + def_id: _, }), - projection: None, + projection: box [], } ) | mir::Operand::Move( Place { base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(promoted), + kind: StaticKind::Promoted(promoted, _), ty, + def_id: _, }), - projection: None, + projection: box [], } ) => { let param_env = ty::ParamEnv::reveal_all(); @@ -651,7 +681,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (llval, ty) = self.simd_shuffle_indices( &bx, constant.span, - constant.ty, + constant.literal.ty, c, ); return OperandRef { @@ -666,8 +696,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }).collect(); - let callee_ty = instance.as_ref().unwrap().ty(bx.tcx()); - bx.codegen_intrinsic_call(callee_ty, &fn_ty, &args, dest, + bx.codegen_intrinsic_call(*instance.as_ref().unwrap(), &fn_ty, &args, dest, terminator.source_info.span); if let ReturnDest::IndirectOperand(dst, _) = ret_dest { @@ -675,6 +704,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } if let Some((_, target)) = *destination { + helper.maybe_sideeffect(self.mir, &mut bx, &[target]); helper.funclet_br(self, &mut bx, target); } else { bx.unreachable(); @@ -691,26 +721,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (&args[..], None) }; - // Useful determining if the current argument is the "spoofed" `VaListImpl` - let last_arg_idx = if sig.inputs().is_empty() { - None - } else { - Some(sig.inputs().len() - 1) - }; 'make_args: for (i, arg) in first_args.iter().enumerate() { - // If this is a C-variadic function the function signature contains - // an "spoofed" `VaListImpl`. This argument is ignored, but we need to - // populate it with a dummy operand so that the users real arguments - // are not overwritten. - let i = if sig.c_variadic && last_arg_idx.map(|x| i >= x).unwrap_or(false) { - if i + 1 < fn_ty.args.len() { - i + 1 - } else { - break 'make_args - } - } else { - i - }; let mut op = self.codegen_operand(&mut bx, arg); if let (0, Some(ty::InstanceDef::Virtual(_, idx))) = (i, def) { @@ -766,7 +777,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match (arg, op.val) { (&mir::Operand::Copy(_), Ref(_, None, _)) | (&mir::Operand::Constant(_), Ref(_, None, _)) => { - let tmp = PlaceRef::alloca(&mut bx, op.layout, "const"); + let tmp = PlaceRef::alloca(&mut bx, op.layout); op.val.store(&mut bx, tmp); op.val = Ref(tmp.llval, None, tmp.align); } @@ -786,6 +797,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => span_bug!(span, "no llfn for call"), }; + if let Some((_, target)) = destination.as_ref() { + helper.maybe_sideeffect(self.mir, &mut bx, &[*target]); + } helper.do_call(self, &mut bx, fn_ty, fn_ptr, &llargs, destination.as_ref().map(|&(_, target)| (ret_dest, target)), cleanup); @@ -835,6 +849,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::TerminatorKind::Goto { target } => { + helper.maybe_sideeffect(self.mir, &mut bx, &[target]); helper.funclet_br(self, &mut bx, target); } @@ -924,7 +939,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Immediate(_) | Pair(..) => { match arg.mode { PassMode::Indirect(..) | PassMode::Cast(_) => { - let scratch = PlaceRef::alloca(bx, arg.layout, "arg"); + let scratch = PlaceRef::alloca(bx, arg.layout); op.val.store(bx, scratch); (scratch.llval, scratch.align, true) } @@ -939,7 +954,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't // have scary latent bugs around. - let scratch = PlaceRef::alloca(bx, arg.layout, "arg"); + let scratch = PlaceRef::alloca(bx, arg.layout); base::memcpy_ty(bx, scratch.llval, scratch.align, llval, align, op.layout, MemFlags::empty()); (scratch.llval, scratch.align, true) @@ -987,7 +1002,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Handle both by-ref and immediate tuples. if let Ref(llval, None, align) = tuple.val { - let tuple_ptr = PlaceRef::new_sized(llval, tuple.layout, align); + let tuple_ptr = PlaceRef::new_sized_aligned(llval, tuple.layout, align); for i in 0..tuple.layout.fields.count() { let field_ptr = tuple_ptr.project_field(bx, i); let field = bx.load_operand(field_ptr); @@ -1016,7 +1031,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { cx.tcx().mk_mut_ptr(cx.tcx().types.u8), cx.tcx().types.i32 ])); - let slot = PlaceRef::alloca(bx, layout, "personalityslot"); + let slot = PlaceRef::alloca(bx, layout); self.personality_slot = Some(slot); slot } @@ -1104,7 +1119,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } let dest = if let mir::Place { base: mir::PlaceBase::Local(index), - projection: None, + projection: box [], } = *dest { match self.locals[index] { LocalRef::Place(dest) => dest, @@ -1115,7 +1130,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return if fn_ret.is_indirect() { // Odd, but possible, case, we have an operand temporary, // but the calling convention has an indirect return. - let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret"); + let tmp = PlaceRef::alloca(bx, fn_ret.layout); tmp.storage_live(bx); llargs.push(tmp.llval); ReturnDest::IndirectOperand(tmp, index) @@ -1123,7 +1138,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Currently, intrinsics always need a location to store // the result, so we create a temporary `alloca` for the // result. - let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret"); + let tmp = PlaceRef::alloca(bx, fn_ret.layout); tmp.storage_live(bx); ReturnDest::IndirectOperand(tmp, index) } else { @@ -1165,7 +1180,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) { if let mir::Place { base: mir::PlaceBase::Local(index), - projection: None, + projection: box [], } = *dst { match self.locals[index] { LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place), @@ -1173,7 +1188,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::Operand(None) => { let dst_layout = bx.layout_of(self.monomorphized_place_ty(&dst.as_ref())); assert!(!dst_layout.ty.has_erasable_regions()); - let place = PlaceRef::alloca(bx, dst_layout, "transmute_temp"); + let place = PlaceRef::alloca(bx, dst_layout); place.storage_live(bx); self.codegen_transmute_into(bx, src, place); let op = bx.load_operand(place); @@ -1201,7 +1216,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let llty = bx.backend_type(src.layout); let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty)); let align = src.layout.align.abi.min(dst.align); - src.val.store(bx, PlaceRef::new_sized(cast_ptr, src.layout, align)); + src.val.store(bx, PlaceRef::new_sized_aligned(cast_ptr, src.layout, align)); } @@ -1226,7 +1241,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { DirectOperand(index) => { // If there is a cast, we have to store and reload. let op = if let PassMode::Cast(_) = ret_ty.mode { - let tmp = PlaceRef::alloca(bx, ret_ty.layout, "tmp_ret"); + let tmp = PlaceRef::alloca(bx, ret_ty.layout); tmp.storage_live(bx); bx.store_arg_ty(&ret_ty, llval, tmp); let op = bx.load_operand(tmp); diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index 216e5a4645a46..d06359ab0ce89 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -1,6 +1,6 @@ use rustc::mir::interpret::ErrorHandled; use rustc::mir; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, HasTyCtxt}; use syntax::source_map::Span; @@ -40,7 +40,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { constant .map(|c| { let field_ty = c.ty.builtin_index().unwrap(); - let fields = match c.ty.sty { + let fields = match c.ty.kind { ty::Array(_, n) => n.eval_usize(bx.tcx(), ty::ParamEnv::reveal_all()), _ => bug!("invalid simd shuffle type: {}", c.ty), }; diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index e7517d6999195..d5612d7b072a6 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -2,19 +2,19 @@ use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts, Instance}; use rustc::ty::layout::{TyLayout, HasTyCtxt, FnTypeExt}; use rustc::mir::{self, Body}; use rustc::session::config::DebugInfo; -use rustc_target::abi::call::{FnType, PassMode, IgnoreMode}; +use rustc_target::abi::call::{FnType, PassMode}; use rustc_target::abi::{Variants, VariantIdx}; use crate::base; use crate::debuginfo::{self, VariableAccess, VariableKind, FunctionDebugContext}; use crate::traits::*; -use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span}; +use syntax_pos::{DUMMY_SP, BytePos, Span}; use syntax::symbol::kw; use std::iter; -use rustc_data_structures::bit_set::BitSet; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; use self::analyze::CleanupKind; use self::place::PlaceRef; @@ -81,10 +81,6 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { /// Debug information for MIR scopes. scopes: IndexVec>, - - /// If this function is a C-variadic function, this contains the `PlaceRef` of the - /// "spoofed" `VaListImpl`. - va_list_ref: Option>, } impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { @@ -120,7 +116,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // In order to have a good line stepping behavior in debugger, we overwrite debug // locations of macro expansions with that of the outermost expansion site // (unless the crate is being compiled with `-Z debug-macros`). - if source_info.span.ctxt() == NO_EXPANSION || + if !source_info.span.from_expansion() || self.cx.sess().opts.debugging_opts.debug_macros { let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo()); (scope, source_info.span) @@ -204,6 +200,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx.set_personality_fn(cx.eh_personality()); } + bx.sideeffect(); + let cleanup_kinds = analyze::cleanup_kinds(&mir); // Allocate a `Block` for every basic block, except // the start block, if nothing loops back to it. @@ -236,18 +234,13 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( scopes, locals: IndexVec::new(), debug_context, - va_list_ref: None, }; let memory_locals = analyze::non_ssa_locals(&fx); // Allocate variable and temp allocas fx.locals = { - // FIXME(dlrobertson): This is ugly. Find a better way of getting the `PlaceRef` or - // `LocalRef` from `arg_local_refs` - let mut va_list_ref = None; - let args = arg_local_refs(&mut bx, &fx, &memory_locals, &mut va_list_ref); - fx.va_list_ref = va_list_ref; + let args = arg_local_refs(&mut bx, &fx, &memory_locals); let mut allocate_local = |local| { let decl = &mir.local_decls[local]; @@ -268,11 +261,13 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( debug!("alloc: {:?} ({}) -> place", local, name); if layout.is_unsized() { let indirect_place = - PlaceRef::alloca_unsized_indirect(&mut bx, layout, &name.as_str()); + PlaceRef::alloca_unsized_indirect(&mut bx, layout); + bx.set_var_name(indirect_place.llval, name); // FIXME: add an appropriate debuginfo LocalRef::UnsizedPlace(indirect_place) } else { - let place = PlaceRef::alloca(&mut bx, layout, &name.as_str()); + let place = PlaceRef::alloca(&mut bx, layout); + bx.set_var_name(place.llval, name); if dbg { let (scope, span) = fx.debug_loc(mir::SourceInfo { span: decl.source_info.span, @@ -289,18 +284,17 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( if local == mir::RETURN_PLACE && fx.fn_ty.ret.is_indirect() { debug!("alloc: {:?} (return place) -> place", local); let llretptr = bx.get_param(0); - LocalRef::Place(PlaceRef::new_sized(llretptr, layout, layout.align.abi)) + LocalRef::Place(PlaceRef::new_sized(llretptr, layout)) } else if memory_locals.contains(local) { debug!("alloc: {:?} -> place", local); if layout.is_unsized() { - let indirect_place = PlaceRef::alloca_unsized_indirect( - &mut bx, - layout, - &format!("{:?}", local), - ); + let indirect_place = PlaceRef::alloca_unsized_indirect(&mut bx, layout); + bx.set_var_name(indirect_place.llval, format_args!("{:?}", local)); LocalRef::UnsizedPlace(indirect_place) } else { - LocalRef::Place(PlaceRef::alloca(&mut bx, layout, &format!("{:?}", local))) + let place = PlaceRef::alloca(&mut bx, layout); + bx.set_var_name(place.llval, format_args!("{:?}", local)); + LocalRef::Place(place) } } else { // If this is an immediate local, we do not create an @@ -425,7 +419,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, fx: &FunctionCx<'a, 'tcx, Bx>, memory_locals: &BitSet, - va_list_ref: &mut Option>, ) -> Vec> { let mir = fx.mir; let tcx = fx.cx.tcx(); @@ -440,22 +433,14 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( None }; - // Store the index of the last argument. This is used to - // call va_start on the va_list instead of attempting - // to store_fn_arg. - let last_arg_idx = if fx.fn_ty.args.is_empty() { - None - } else { - Some(fx.fn_ty.args.len() - 1) - }; - mir.args_iter().enumerate().map(|(arg_index, local)| { let arg_decl = &mir.local_decls[local]; + // FIXME(eddyb) don't allocate a `String` unless it gets used. let name = if let Some(name) = arg_decl.name { name.as_str().to_string() } else { - format!("arg{}", arg_index) + format!("{:?}", local) }; if Some(local) == mir.spread_arg { @@ -465,12 +450,13 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // individual LLVM function arguments. let arg_ty = fx.monomorphize(&arg_decl.ty); - let tupled_arg_tys = match arg_ty.sty { + let tupled_arg_tys = match arg_ty.kind { ty::Tuple(ref tys) => tys, _ => bug!("spread argument isn't a tuple?!") }; - let place = PlaceRef::alloca(bx, bx.layout_of(arg_ty), &name); + let place = PlaceRef::alloca(bx, bx.layout_of(arg_ty)); + bx.set_var_name(place.llval, name); for i in 0..tupled_arg_tys.len() { let arg = &fx.fn_ty.args[idx]; idx += 1; @@ -500,6 +486,31 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( return LocalRef::Place(place); } + if fx.fn_ty.c_variadic && arg_index == fx.fn_ty.args.len() { + let arg_ty = fx.monomorphize(&arg_decl.ty); + + let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty)); + bx.set_var_name(va_list.llval, name); + bx.va_start(va_list.llval); + + arg_scope.map(|scope| { + let variable_access = VariableAccess::DirectVariable { + alloca: va_list.llval + }; + bx.declare_local( + &fx.debug_context, + arg_decl.name.unwrap_or(kw::Invalid), + va_list.layout.ty, + scope, + variable_access, + VariableKind::ArgumentVariable(arg_index + 1), + DUMMY_SP + ); + }); + + return LocalRef::Place(va_list); + } + let arg = &fx.fn_ty.args[idx]; idx += 1; if arg.pad.is_some() { @@ -512,25 +523,24 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // of putting everything in allocas just so we can use llvm.dbg.declare. let local = |op| LocalRef::Operand(Some(op)); match arg.mode { - PassMode::Ignore(IgnoreMode::Zst) => { + PassMode::Ignore => { return local(OperandRef::new_zst(bx, arg.layout)); } - PassMode::Ignore(IgnoreMode::CVarArgs) => {} PassMode::Direct(_) => { let llarg = bx.get_param(llarg_idx); - bx.set_value_name(llarg, &name); + bx.set_var_name(llarg, &name); llarg_idx += 1; return local( OperandRef::from_immediate_or_packed_pair(bx, llarg, arg.layout)); } PassMode::Pair(..) => { - let a = bx.get_param(llarg_idx); - bx.set_value_name(a, &(name.clone() + ".0")); - llarg_idx += 1; + let (a, b) = (bx.get_param(llarg_idx), bx.get_param(llarg_idx + 1)); + llarg_idx += 2; - let b = bx.get_param(llarg_idx); - bx.set_value_name(b, &(name + ".1")); - llarg_idx += 1; + // FIXME(eddyb) these are scalar components, + // maybe extract the high-level fields? + bx.set_var_name(a, format_args!("{}.0", name)); + bx.set_var_name(b, format_args!("{}.1", name)); return local(OperandRef { val: OperandValue::Pair(a, b), @@ -546,9 +556,9 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // already put it in a temporary alloca and gave it up. // FIXME: lifetimes let llarg = bx.get_param(llarg_idx); - bx.set_value_name(llarg, &name); + bx.set_var_name(llarg, &name); llarg_idx += 1; - PlaceRef::new_sized(llarg, arg.layout, arg.layout.align.abi) + PlaceRef::new_sized(llarg, arg.layout) } else if arg.is_unsized_indirect() { // As the storage for the indirect argument lives during // the whole function call, we just copy the fat pointer. @@ -558,27 +568,14 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( llarg_idx += 1; let indirect_operand = OperandValue::Pair(llarg, llextra); - let tmp = PlaceRef::alloca_unsized_indirect(bx, arg.layout, &name); + let tmp = PlaceRef::alloca_unsized_indirect(bx, arg.layout); + bx.set_var_name(tmp.llval, name); indirect_operand.store(bx, tmp); tmp } else { - let tmp = PlaceRef::alloca(bx, arg.layout, &name); - if fx.fn_ty.c_variadic && last_arg_idx.map(|idx| arg_index == idx).unwrap_or(false) { - let va_list_did = match tcx.lang_items().va_list() { - Some(did) => did, - None => bug!("`va_list` lang item required for C-variadic functions"), - }; - match arg_decl.ty.sty { - ty::Adt(def, _) if def.did == va_list_did => { - // Call `va_start` on the spoofed `VaListImpl`. - bx.va_start(tmp.llval); - *va_list_ref = Some(tmp); - }, - _ => bug!("last argument of variadic function is not a `va_list`") - } - } else { - bx.store_fn_arg(arg, &mut llarg_idx, tmp); - } + let tmp = PlaceRef::alloca(bx, arg.layout); + bx.set_var_name(tmp.llval, name); + bx.store_fn_arg(arg, &mut llarg_idx, tmp); tmp }; let upvar_debuginfo = &mir.__upvar_debuginfo_codegen_only_do_not_use; @@ -607,11 +604,11 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let pin_did = tcx.lang_items().pin_type(); // Or is it the closure environment? - let (closure_layout, env_ref) = match arg.layout.ty.sty { + let (closure_layout, env_ref) = match arg.layout.ty.kind { ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => (bx.layout_of(ty), true), ty::Adt(def, substs) if Some(def.did) == pin_did => { - match substs.type_at(0).sty { + match substs.type_at(0).kind { ty::Ref(_, ty, _) => (bx.layout_of(ty), true), _ => (arg.layout, false), } @@ -619,8 +616,9 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( _ => (arg.layout, false) }; - let (def_id, upvar_substs) = match closure_layout.ty.sty { - ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)), + let (def_id, upvar_substs) = match closure_layout.ty.kind { + ty::Closure(def_id, substs) => (def_id, + UpvarSubsts::Closure(substs)), ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)), _ => bug!("upvar debuginfo with non-closure arg0 type `{}`", closure_layout.ty) }; @@ -636,11 +634,11 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( }); let generator_fields = mir.generator_layout.as_ref().map(|generator_layout| { - let (def_id, gen_substs) = match closure_layout.ty.sty { + let (def_id, gen_substs) = match closure_layout.ty.kind { ty::Generator(def_id, substs, _) => (def_id, substs), _ => bug!("generator layout without generator substs"), }; - let state_tys = gen_substs.state_tys(def_id, tcx); + let state_tys = gen_substs.as_generator().state_tys(def_id, tcx); generator_layout.variant_fields.iter() .zip(state_tys) @@ -690,7 +688,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // The environment and the capture can each be indirect. let mut ops = if env_ref { &ops[..] } else { &ops[1..] }; - let ty = if let (true, &ty::Ref(_, ty, _)) = (by_ref, &ty.sty) { + let ty = if let (true, &ty::Ref(_, ty, _)) = (by_ref, &ty.kind) { ty } else { ops = &ops[..ops.len() - 1]; diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index 5e5804b72657b..daa25b2ea0591 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -367,7 +367,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { // Allocate an appropriate region on the stack, and copy the value into it let (llsize, _) = glue::size_and_align_of_dst(bx, unsized_ty, Some(llextra)); - let lldst = bx.array_alloca(bx.cx().type_i8(), llsize, "unsized_tmp", max_align); + let lldst = bx.array_alloca(bx.cx().type_i8(), llsize, max_align); bx.memcpy(lldst, max_align, llptr, min_align, llsize, flags); // Store the allocated region and the extra to the indirect place. @@ -384,47 +384,45 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> Option> { debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref); - place_ref.iterate(|place_base, place_projection| { - if let mir::PlaceBase::Local(index) = place_base { - match self.locals[*index] { - LocalRef::Operand(Some(mut o)) => { - // Moves out of scalar and scalar pair fields are trivial. - for proj in place_projection { - match proj.elem { - mir::ProjectionElem::Field(ref f, _) => { - o = o.extract_field(bx, f.index()); - } - mir::ProjectionElem::Index(_) | - mir::ProjectionElem::ConstantIndex { .. } => { - // ZSTs don't require any actual memory access. - // FIXME(eddyb) deduplicate this with the identical - // checks in `codegen_consume` and `extract_field`. - let elem = o.layout.field(bx.cx(), 0); - if elem.is_zst() { - o = OperandRef::new_zst(bx, elem); - } else { - return None; - } + if let mir::PlaceBase::Local(index) = place_ref.base { + match self.locals[*index] { + LocalRef::Operand(Some(mut o)) => { + // Moves out of scalar and scalar pair fields are trivial. + for elem in place_ref.projection.iter() { + match elem { + mir::ProjectionElem::Field(ref f, _) => { + o = o.extract_field(bx, f.index()); + } + mir::ProjectionElem::Index(_) | + mir::ProjectionElem::ConstantIndex { .. } => { + // ZSTs don't require any actual memory access. + // FIXME(eddyb) deduplicate this with the identical + // checks in `codegen_consume` and `extract_field`. + let elem = o.layout.field(bx.cx(), 0); + if elem.is_zst() { + o = OperandRef::new_zst(bx, elem); + } else { + return None; } - _ => return None, } + _ => return None, } - - Some(o) - } - LocalRef::Operand(None) => { - bug!("use of {:?} before def", place_ref); - } - LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => { - // watch out for locals that do not have an - // alloca; they are handled somewhat differently - None } + + Some(o) + } + LocalRef::Operand(None) => { + bug!("use of {:?} before def", place_ref); + } + LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => { + // watch out for locals that do not have an + // alloca; they are handled somewhat differently + None } - } else { - None } - }) + } else { + None + } } pub fn codegen_consume( @@ -466,7 +464,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::Operand::Constant(ref constant) => { - let ty = self.monomorphize(&constant.ty); self.eval_mir_constant(constant) .map(|c| OperandRef::from_const(bx, c)) .unwrap_or_else(|err| { @@ -481,11 +478,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // the above error (or silence it under some conditions) will not cause UB bx.abort(); // We've errored, so we don't have to produce working code. + let ty = self.monomorphize(&constant.literal.ty); let layout = bx.cx().layout_of(ty); bx.load_operand(PlaceRef::new_sized( bx.cx().const_undef(bx.cx().type_ptr_to(bx.cx().backend_type(layout))), layout, - layout.align.abi, )) }) } diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index a632838ba2442..2d97f828f073d 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -1,4 +1,4 @@ -use rustc::ty::{self, Ty}; +use rustc::ty::{self, Instance, Ty}; use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx, HasTyCtxt}; use rustc::mir; use rustc::mir::tcx::PlaceTy; @@ -30,6 +30,19 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { pub fn new_sized( llval: V, layout: TyLayout<'tcx>, + ) -> PlaceRef<'tcx, V> { + assert!(!layout.is_unsized()); + PlaceRef { + llval, + llextra: None, + layout, + align: layout.align.abi + } + } + + pub fn new_sized_aligned( + llval: V, + layout: TyLayout<'tcx>, align: Align, ) -> PlaceRef<'tcx, V> { assert!(!layout.is_unsized()); @@ -45,39 +58,34 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bx: &mut Bx, llval: V, layout: TyLayout<'tcx>, - align: Align, ) -> PlaceRef<'tcx, V> { assert!(!bx.cx().type_has_metadata(layout.ty)); PlaceRef { llval, llextra: None, layout, - align + align: layout.align.abi } } pub fn alloca>( bx: &mut Bx, layout: TyLayout<'tcx>, - name: &str ) -> Self { - debug!("alloca({:?}: {:?})", name, layout); assert!(!layout.is_unsized(), "tried to statically allocate unsized place"); - let tmp = bx.alloca(bx.cx().backend_type(layout), name, layout.align.abi); - Self::new_sized(tmp, layout, layout.align.abi) + let tmp = bx.alloca(bx.cx().backend_type(layout), layout.align.abi); + Self::new_sized(tmp, layout) } /// Returns a place for an indirect reference to an unsized place. pub fn alloca_unsized_indirect>( bx: &mut Bx, layout: TyLayout<'tcx>, - name: &str, ) -> Self { - debug!("alloca_unsized_indirect({:?}: {:?})", name, layout); assert!(layout.is_unsized(), "tried to allocate indirect place for sized values"); let ptr_ty = bx.cx().tcx().mk_mut_ptr(layout.ty); let ptr_layout = bx.cx().layout_of(ptr_ty); - Self::alloca(bx, ptr_layout, name) + Self::alloca(bx, ptr_layout) } pub fn len>( @@ -136,7 +144,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { // * no metadata available - just log the case // * known alignment - sized types, `[T]`, `str` or a foreign type // * packed struct - there is no alignment padding - match field.ty.sty { + match field.ty.kind { _ if self.llextra.is_none() => { debug!("unsized field `{}`, of `{:?}` has no metadata for adjustment", ix, self.llval); @@ -437,7 +445,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let result = match &place_ref { mir::PlaceRef { base: mir::PlaceBase::Local(index), - projection: None, + projection: [], } => { match self.locals[*index] { LocalRef::Place(place) => { @@ -454,13 +462,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::PlaceRef { base: mir::PlaceBase::Static(box mir::Static { ty, - kind: mir::StaticKind::Promoted(promoted), + kind: mir::StaticKind::Promoted(promoted, substs), + def_id, }), - projection: None, + projection: [], } => { let param_env = ty::ParamEnv::reveal_all(); + let instance = Instance::new(*def_id, self.monomorphize(substs)); let cid = mir::interpret::GlobalId { - instance: self.instance, + instance: instance, promoted: Some(*promoted), }; let layout = cx.layout_of(self.monomorphize(&ty)); @@ -480,29 +490,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let llval = bx.cx().const_undef( bx.cx().type_ptr_to(bx.cx().backend_type(layout)) ); - PlaceRef::new_sized(llval, layout, layout.align.abi) + PlaceRef::new_sized(llval, layout) } } } mir::PlaceRef { base: mir::PlaceBase::Static(box mir::Static { ty, - kind: mir::StaticKind::Static(def_id), + kind: mir::StaticKind::Static, + def_id, }), - projection: None, + projection: [], } => { // NB: The layout of a static may be unsized as is the case when working // with a static that is an extern_type. let layout = cx.layout_of(self.monomorphize(&ty)); let static_ = bx.get_static(*def_id); - PlaceRef::new_thin_place(bx, static_, layout, layout.align.abi) + PlaceRef::new_thin_place(bx, static_, layout) }, mir::PlaceRef { base, - projection: Some(box mir::Projection { - base: proj_base, - elem: mir::ProjectionElem::Deref, - }), + projection: [proj_base @ .., mir::ProjectionElem::Deref], } => { // Load the pointer from its location. self.codegen_consume(bx, &mir::PlaceRef { @@ -512,22 +520,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::PlaceRef { base, - projection: Some(projection), + projection: [proj_base @ .., elem], } => { // FIXME turn this recursion into iteration let cg_base = self.codegen_place(bx, &mir::PlaceRef { base, - projection: &projection.base, + projection: proj_base, }); - match projection.elem { + match elem { mir::ProjectionElem::Deref => bug!(), mir::ProjectionElem::Field(ref field, _) => { cg_base.project_field(bx, field.index()) } mir::ProjectionElem::Index(index) => { let index = &mir::Operand::Copy( - mir::Place::from(index) + mir::Place::from(*index) ); let index = self.codegen_operand(bx, index); let llindex = index.immediate(); @@ -536,27 +544,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::ProjectionElem::ConstantIndex { offset, from_end: false, min_length: _ } => { - let lloffset = bx.cx().const_usize(offset as u64); + let lloffset = bx.cx().const_usize(*offset as u64); cg_base.project_index(bx, lloffset) } mir::ProjectionElem::ConstantIndex { offset, from_end: true, min_length: _ } => { - let lloffset = bx.cx().const_usize(offset as u64); + let lloffset = bx.cx().const_usize(*offset as u64); let lllen = cg_base.len(bx.cx()); let llindex = bx.sub(lllen, lloffset); cg_base.project_index(bx, llindex) } mir::ProjectionElem::Subslice { from, to } => { let mut subslice = cg_base.project_index(bx, - bx.cx().const_usize(from as u64)); + bx.cx().const_usize(*from as u64)); let projected_ty = PlaceTy::from_ty(cg_base.layout.ty) - .projection_ty(tcx, &projection.elem).ty; + .projection_ty(tcx, elem).ty; subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty)); if subslice.layout.is_unsized() { subslice.llextra = Some(bx.sub(cg_base.llextra.unwrap(), - bx.cx().const_usize((from as u64) + (to as u64)))); + bx.cx().const_usize((*from as u64) + (*to as u64)))); } // Cast the place pointer type to the new @@ -567,7 +575,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { subslice } mir::ProjectionElem::Downcast(_, v) => { - cg_base.project_downcast(bx, v) + cg_base.project_downcast(bx, *v) } } } diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 9da1e5024ba3a..978e7218aa745 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -64,14 +64,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // index into the struct, and this case isn't // important enough for it. debug!("codegen_rvalue: creating ugly alloca"); - let scratch = PlaceRef::alloca(&mut bx, operand.layout, "__unsize_temp"); + let scratch = PlaceRef::alloca(&mut bx, operand.layout); scratch.storage_live(&mut bx); operand.val.store(&mut bx, scratch); base::coerce_unsized_into(&mut bx, scratch, dest); scratch.storage_dead(&mut bx); } OperandValue::Ref(llref, None, align) => { - let source = PlaceRef::new_sized(llref, operand.layout, align); + let source = PlaceRef::new_sized_aligned(llref, operand.layout, align); base::coerce_unsized_into(&mut bx, source, dest); } OperandValue::Ref(_, Some(_), _) => { @@ -184,13 +184,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let val = match *kind { mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => { - match operand.layout.ty.sty { + match operand.layout.ty.kind { ty::FnDef(def_id, substs) => { if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) { bug!("reifying a fn ptr that requires const arguments"); } OperandValue::Immediate( - callee::resolve_and_get_fn(bx.cx(), def_id, substs)) + callee::resolve_and_get_fn_for_ptr(bx.cx(), def_id, substs)) } _ => { bug!("{} cannot be reified to a fn ptr", operand.layout.ty) @@ -198,10 +198,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)) => { - match operand.layout.ty.sty { + match operand.layout.ty.kind { ty::Closure(def_id, substs) => { let instance = Instance::resolve_closure( - bx.cx().tcx(), def_id, substs, ty::ClosureKind::FnOnce); + bx.cx().tcx(), + def_id, + substs, + ty::ClosureKind::FnOnce); OperandValue::Immediate(bx.cx().get_fn(instance)) } _ => { @@ -522,10 +525,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // because codegen_place() panics if Local is operand. if let mir::Place { base: mir::PlaceBase::Local(index), - projection: None, + projection: box [], } = *place { if let LocalRef::Operand(Some(op)) = self.locals[index] { - if let ty::Array(_, n) = op.layout.ty.sty { + if let ty::Array(_, n) = op.layout.ty.kind { let n = n.eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all()); return bx.cx().const_usize(n); } diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs index 3717be4b41753..dab7dfc041751 100644 --- a/src/librustc_codegen_ssa/mir/statement.rs +++ b/src/librustc_codegen_ssa/mir/statement.rs @@ -16,12 +16,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.set_debug_loc(&mut bx, statement.source_info); match statement.kind { - mir::StatementKind::Assign(ref place, ref rvalue) => { + mir::StatementKind::Assign(box(ref place, ref rvalue)) => { if let mir::Place { base: mir::PlaceBase::Local(index), - projection: None, - } = *place { - match self.locals[index] { + projection: box [], + } = place { + match self.locals[*index] { LocalRef::Place(cg_dest) => { self.codegen_rvalue(bx, cg_dest, rvalue) } @@ -29,8 +29,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_rvalue_unsized(bx, cg_indirect_dest, rvalue) } LocalRef::Operand(None) => { - let (bx, operand) = self.codegen_rvalue_operand(bx, rvalue); - self.locals[index] = LocalRef::Operand(Some(operand)); + let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue); + if let Some(name) = self.mir.local_decls[*index].name { + match operand.val { + OperandValue::Ref(x, ..) | + OperandValue::Immediate(x) => { + bx.set_var_name(x, name); + } + OperandValue::Pair(a, b) => { + // FIXME(eddyb) these are scalar components, + // maybe extract the high-level fields? + bx.set_var_name(a, format_args!("{}.0", name)); + bx.set_var_name(b, format_args!("{}.1", name)); + } + } + } + self.locals[*index] = LocalRef::Operand(Some(operand)); bx } LocalRef::Operand(Some(op)) => { @@ -50,7 +64,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_rvalue(bx, cg_dest, rvalue) } } - mir::StatementKind::SetDiscriminant{ref place, variant_index} => { + mir::StatementKind::SetDiscriminant{box ref place, variant_index} => { self.codegen_place(&mut bx, &place.as_ref()) .codegen_set_discr(&mut bx, variant_index); bx @@ -89,7 +103,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }); if input_vals.len() == asm.inputs.len() { - let res = bx.codegen_inline_asm(&asm.asm, outputs, input_vals); + let res = bx.codegen_inline_asm( + &asm.asm, + outputs, + input_vals, + statement.source_info.span, + ); if !res { span_err!(bx.sess(), statement.source_info.span, E0668, "malformed inline assembly"); diff --git a/src/librustc_codegen_ssa/mono_item.rs b/src/librustc_codegen_ssa/mono_item.rs index 4446f1a3a5ce2..10177d2997a76 100644 --- a/src/librustc_codegen_ssa/mono_item.rs +++ b/src/librustc_codegen_ssa/mono_item.rs @@ -30,7 +30,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { } MonoItem::GlobalAsm(hir_id) => { let item = cx.tcx().hir().expect_item(hir_id); - if let hir::ItemKind::GlobalAsm(ref ga) = item.node { + if let hir::ItemKind::GlobalAsm(ref ga) = item.kind { cx.codegen_global_asm(ga); } else { span_bug!(item.span, "Mismatch between hir::Item type and MonoItem type") @@ -58,7 +58,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { self.to_raw_string(), cx.codegen_unit().name()); - let symbol_name = self.symbol_name(cx.tcx()).as_str(); + let symbol_name = self.symbol_name(cx.tcx()).name.as_str(); debug!("symbol {}", &symbol_name); diff --git a/src/librustc_codegen_ssa/traits/asm.rs b/src/librustc_codegen_ssa/traits/asm.rs index fd3c868bbc507..c9e1ed86e97e0 100644 --- a/src/librustc_codegen_ssa/traits/asm.rs +++ b/src/librustc_codegen_ssa/traits/asm.rs @@ -1,6 +1,7 @@ use super::BackendTypes; use crate::mir::place::PlaceRef; use rustc::hir::{GlobalAsm, InlineAsm}; +use syntax_pos::Span; pub trait AsmBuilderMethods<'tcx>: BackendTypes { /// Take an inline assembly expression and splat it out via LLVM @@ -9,6 +10,7 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes { ia: &InlineAsm, outputs: Vec>, inputs: Vec, + span: Span, ) -> bool; } diff --git a/src/librustc_codegen_ssa/traits/backend.rs b/src/librustc_codegen_ssa/traits/backend.rs index 9fbb44dcc9959..cb197f51460a1 100644 --- a/src/librustc_codegen_ssa/traits/backend.rs +++ b/src/librustc_codegen_ssa/traits/backend.rs @@ -8,6 +8,7 @@ use rustc::session::{Session, config}; use rustc::ty::TyCtxt; use rustc_codegen_utils::codegen_backend::CodegenBackend; use std::sync::Arc; +use std::sync::mpsc; use syntax::ext::allocator::AllocatorKind; use syntax_pos::symbol::InternedString; @@ -44,7 +45,12 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se mods: &mut Self::Module, kind: AllocatorKind, ); - fn compile_codegen_unit(&self, tcx: TyCtxt<'_>, cgu_name: InternedString); + fn compile_codegen_unit( + &self, + tcx: TyCtxt<'_>, + cgu_name: InternedString, + tx_to_llvm_workers: &mpsc::Sender>, + ); // If find_features is true this won't access `sess.crate_types` by assuming // that `is_pie_binary` is false. When we discover LLVM target features // `sess.crate_types` is uninitialized so we cannot access it. diff --git a/src/librustc_codegen_ssa/traits/builder.rs b/src/librustc_codegen_ssa/traits/builder.rs index 3a144f0b0e0aa..1886701fb3a88 100644 --- a/src/librustc_codegen_ssa/traits/builder.rs +++ b/src/librustc_codegen_ssa/traits/builder.rs @@ -109,13 +109,12 @@ pub trait BuilderMethods<'a, 'tcx>: rhs: Self::Value, ) -> (Self::Value, Self::Value); - fn alloca(&mut self, ty: Self::Type, name: &str, align: Align) -> Self::Value; - fn dynamic_alloca(&mut self, ty: Self::Type, name: &str, align: Align) -> Self::Value; + fn alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value; + fn dynamic_alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value; fn array_alloca( &mut self, ty: Self::Type, len: Self::Value, - name: &str, align: Align, ) -> Self::Value; diff --git a/src/librustc_codegen_ssa/traits/debuginfo.rs b/src/librustc_codegen_ssa/traits/debuginfo.rs index be2fa7279aa7c..e75f247da9613 100644 --- a/src/librustc_codegen_ssa/traits/debuginfo.rs +++ b/src/librustc_codegen_ssa/traits/debuginfo.rs @@ -3,7 +3,7 @@ use crate::debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess, Vari use rustc::hir::def_id::CrateNum; use rustc::mir; use rustc::ty::{self, Ty, Instance}; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::vec::IndexVec; use syntax::ast::Name; use syntax_pos::{SourceFile, Span}; @@ -57,5 +57,5 @@ pub trait DebugInfoBuilderMethods<'tcx>: BackendTypes { span: Span, ); fn insert_reference_to_gdb_debug_scripts_section_global(&mut self); - fn set_value_name(&mut self, value: Self::Value, name: &str); + fn set_var_name(&mut self, value: Self::Value, name: impl ToString); } diff --git a/src/librustc_codegen_ssa/traits/intrinsic.rs b/src/librustc_codegen_ssa/traits/intrinsic.rs index ede30a0bed756..2c484084c4a20 100644 --- a/src/librustc_codegen_ssa/traits/intrinsic.rs +++ b/src/librustc_codegen_ssa/traits/intrinsic.rs @@ -1,6 +1,6 @@ use super::BackendTypes; use crate::mir::operand::OperandRef; -use rustc::ty::Ty; +use rustc::ty::{self, Ty}; use rustc_target::abi::call::FnType; use syntax_pos::Span; @@ -10,7 +10,7 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes { /// add them to librustc_codegen_llvm/context.rs fn codegen_intrinsic_call( &mut self, - callee_ty: Ty<'tcx>, + instance: ty::Instance<'tcx>, fn_ty: &FnType<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, Self::Value>], llresult: Self::Value, @@ -20,6 +20,7 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes { fn abort(&mut self); fn assume(&mut self, val: Self::Value); fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value; + fn sideeffect(&mut self); /// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in /// Rust defined C-variadic functions. fn va_start(&mut self, val: Self::Value) -> Self::Value; diff --git a/src/librustc_codegen_ssa/traits/statics.rs b/src/librustc_codegen_ssa/traits/statics.rs index 6983311d797dc..73c4c05397917 100644 --- a/src/librustc_codegen_ssa/traits/statics.rs +++ b/src/librustc_codegen_ssa/traits/statics.rs @@ -1,5 +1,5 @@ use super::BackendTypes; -use syntax_pos::symbol::LocalInternedString; +use syntax_pos::symbol::Symbol; use rustc::hir::def_id::DefId; use rustc::ty::layout::Align; @@ -12,8 +12,8 @@ pub trait StaticBuilderMethods: BackendTypes { fn get_static(&mut self, def_id: DefId) -> Self::Value; fn static_panic_msg( &mut self, - msg: Option, - filename: LocalInternedString, + msg: Option, + filename: Symbol, line: Self::Value, col: Self::Value, kind: &str, diff --git a/src/librustc_codegen_ssa/traits/type_.rs b/src/librustc_codegen_ssa/traits/type_.rs index 13f72e23819a1..19d41c6b37cbb 100644 --- a/src/librustc_codegen_ssa/traits/type_.rs +++ b/src/librustc_codegen_ssa/traits/type_.rs @@ -83,7 +83,7 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { } let tail = self.tcx().struct_tail_erasing_lifetimes(ty, param_env); - match tail.sty { + match tail.kind { ty::Foreign(..) => false, ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, _ => bug!("unexpected unsized tail: {:?}", tail), diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml index d93589ea84be0..c8c219d039a73 100644 --- a/src/librustc_codegen_utils/Cargo.toml +++ b/src/librustc_codegen_utils/Cargo.toml @@ -10,10 +10,9 @@ path = "lib.rs" test = false [dependencies] -flate2 = "1.0" log = "0.4" punycode = "0.4.0" -rustc-demangle = "0.1.15" +rustc-demangle = "0.1.16" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_codegen_utils/codegen_backend.rs b/src/librustc_codegen_utils/codegen_backend.rs index 262cfb1658ef9..2e3af8431eed0 100644 --- a/src/librustc_codegen_utils/codegen_backend.rs +++ b/src/librustc_codegen_utils/codegen_backend.rs @@ -7,7 +7,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] use std::any::Any; -use std::sync::mpsc; use syntax::symbol::Symbol; use rustc::session::Session; @@ -36,7 +35,6 @@ pub trait CodegenBackend { tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, need_metadata_module: bool, - rx: mpsc::Receiver>, ) -> Box; /// This is called on the returned `Box` from `codegen_backend` diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs index 4ea375b59b2c0..1201446afb531 100644 --- a/src/librustc_codegen_utils/lib.rs +++ b/src/librustc_codegen_utils/lib.rs @@ -10,7 +10,6 @@ #![feature(core_intrinsics)] #![feature(never_type)] #![feature(nll)] -#![feature(rustc_diagnostic_macros)] #![feature(in_band_lifetimes)] #![recursion_limit="256"] diff --git a/src/librustc_codegen_utils/symbol_names/legacy.rs b/src/librustc_codegen_utils/symbol_names/legacy.rs index 22b7e0a2fb0c9..cf575c54293c7 100644 --- a/src/librustc_codegen_utils/symbol_names/legacy.rs +++ b/src/librustc_codegen_utils/symbol_names/legacy.rs @@ -3,7 +3,7 @@ use rustc::hir::map::{DefPathData, DisambiguatedDefPathData}; use rustc::ich::NodeIdHashingMode; use rustc::mir::interpret::{ConstValue, Scalar}; use rustc::ty::print::{PrettyPrinter, Printer, Print}; -use rustc::ty::subst::{Kind, UnpackedKind}; +use rustc::ty::subst::{GenericArg, GenericArgKind}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Instance}; use rustc::util::common::record_time; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -89,7 +89,7 @@ fn get_symbol_hash<'tcx>( def_id, substs ); - let mut hasher = StableHasher::::new(); + let mut hasher = StableHasher::new(); let mut hcx = tcx.create_stable_hashing_context(); record_time(&tcx.sess.perf_stats.symbol_hash_time, || { @@ -111,7 +111,7 @@ fn get_symbol_hash<'tcx>( // If this is a function, we hash the signature as well. // This is not *strictly* needed, but it may help in some // situations, see the `run-make/a-b-a-linker-guard` test. - if let ty::FnDef(..) = item_type.sty { + if let ty::FnDef(..) = item_type.kind { item_type.fn_sig(tcx).hash_stable(&mut hcx, &mut hasher); } @@ -132,7 +132,7 @@ fn get_symbol_hash<'tcx>( }); // 64 bits should be enough to avoid collisions. - hasher.finish() + hasher.finish::() } // Follow C++ namespace-mangling style, see @@ -218,14 +218,14 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { self, ty: Ty<'tcx>, ) -> Result { - match ty.sty { + match ty.kind { // Print all nominal types as paths (unlike `pretty_print_type`). ty::FnDef(def_id, substs) | ty::Opaque(def_id, substs) | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) | ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs }) | - ty::Closure(def_id, ty::ClosureSubsts { substs }) | - ty::Generator(def_id, ty::GeneratorSubsts { substs }, _) => { + ty::Closure(def_id, substs) | + ty::Generator(def_id, substs, _) => { self.print_def_path(def_id, substs) } _ => self.pretty_print_type(ty), @@ -275,7 +275,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { ) -> Result { // Similar to `pretty_path_qualified`, but for the other // types that are printed as paths (see `print_type` above). - match self_ty.sty { + match self_ty.kind { ty::FnDef(..) | ty::Opaque(..) | ty::Projection(_) | @@ -341,13 +341,13 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { fn path_generic_args( mut self, print_prefix: impl FnOnce(Self) -> Result, - args: &[Kind<'tcx>], + args: &[GenericArg<'tcx>], ) -> Result { self = print_prefix(self)?; let args = args.iter().cloned().filter(|arg| { match arg.unpack() { - UnpackedKind::Lifetime(_) => false, + GenericArgKind::Lifetime(_) => false, _ => true, } }); diff --git a/src/librustc_codegen_utils/symbol_names/v0.rs b/src/librustc_codegen_utils/symbol_names/v0.rs index 47601da8b7b23..55b148fceb217 100644 --- a/src/librustc_codegen_utils/symbol_names/v0.rs +++ b/src/librustc_codegen_utils/symbol_names/v0.rs @@ -3,7 +3,7 @@ use rustc::hir::def_id::{CrateNum, DefId}; use rustc::hir::map::{DefPathData, DisambiguatedDefPathData}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Instance}; use rustc::ty::print::{Printer, Print}; -use rustc::ty::subst::{Kind, Subst, UnpackedKind}; +use rustc::ty::subst::{GenericArg, Subst, GenericArgKind}; use rustc_data_structures::base_n; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_target::spec::abi::Abi; @@ -56,7 +56,7 @@ struct CompressionCaches<'tcx> { start_offset: usize, // The values are start positions in `out`, in bytes. - paths: FxHashMap<(DefId, &'tcx [Kind<'tcx>]), usize>, + paths: FxHashMap<(DefId, &'tcx [GenericArg<'tcx>]), usize>, types: FxHashMap, usize>, consts: FxHashMap<&'tcx ty::Const<'tcx>, usize>, } @@ -198,10 +198,14 @@ impl SymbolMangler<'tcx> { let lifetimes = regions.into_iter().map(|br| { match br { - ty::BrAnon(i) => i + 1, + ty::BrAnon(i) => { + // FIXME(eddyb) for some reason, `anonymize_late_bound_regions` starts at `1`. + assert_ne!(i, 0); + i - 1 + }, _ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value), } - }).max().unwrap_or(0); + }).max().map_or(0, |max| max + 1); self.push_opt_integer_62("G", lifetimes as u64); lifetime_depths.end += lifetimes; @@ -230,7 +234,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { fn print_def_path( mut self, def_id: DefId, - substs: &'tcx [Kind<'tcx>], + substs: &'tcx [GenericArg<'tcx>], ) -> Result { if let Some(&i) = self.compress.as_ref().and_then(|c| c.paths.get(&(def_id, substs))) { return self.print_backref(i); @@ -252,7 +256,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { fn print_impl_path( self, impl_def_id: DefId, - substs: &'tcx [Kind<'tcx>], + substs: &'tcx [GenericArg<'tcx>], mut self_ty: Ty<'tcx>, mut impl_trait_ref: Option>, ) -> Result { @@ -297,6 +301,10 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { // Late-bound lifetimes use indices starting at 1, // see `BinderLevel` for more details. ty::ReLateBound(debruijn, ty::BrAnon(i)) => { + // FIXME(eddyb) for some reason, `anonymize_late_bound_regions` starts at `1`. + assert_ne!(i, 0); + let i = i - 1; + let binder = &self.binders[self.binders.len() - 1 - debruijn.index()]; let depth = binder.lifetime_depths.start + i; @@ -315,7 +323,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { ty: Ty<'tcx>, ) -> Result { // Basic types, never cached (single-character). - let basic_type = match ty.sty { + let basic_type = match ty.kind { ty::Bool => "b", ty::Char => "c", ty::Str => "e", @@ -352,7 +360,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { } let start = self.out.len(); - match ty.sty { + match ty.kind { // Basic types, handled above. ty::Bool | ty::Char | ty::Str | ty::Int(_) | ty::Uint(_) | ty::Float(_) | @@ -406,8 +414,8 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { ty::Opaque(def_id, substs) | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) | ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs }) | - ty::Closure(def_id, ty::ClosureSubsts { substs }) | - ty::Generator(def_id, ty::GeneratorSubsts { substs }, _) => { + ty::Closure(def_id, substs) | + ty::Generator(def_id, substs, _) => { self = self.print_def_path(def_id, substs)?; } ty::Foreign(def_id) => { @@ -503,7 +511,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { } let start = self.out.len(); - match ct.ty.sty { + match ct.ty.kind { ty::Uint(_) => {} _ => { bug!("symbol_names: unsupported constant of type `{}` ({:?})", @@ -611,18 +619,18 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { fn path_generic_args( mut self, print_prefix: impl FnOnce(Self) -> Result, - args: &[Kind<'tcx>], + args: &[GenericArg<'tcx>], ) -> Result { // Don't print any regions if they're all erased. let print_regions = args.iter().any(|arg| { match arg.unpack() { - UnpackedKind::Lifetime(r) => *r != ty::ReErased, + GenericArgKind::Lifetime(r) => *r != ty::ReErased, _ => false, } }); let args = args.iter().cloned().filter(|arg| { match arg.unpack() { - UnpackedKind::Lifetime(_) => print_regions, + GenericArgKind::Lifetime(_) => print_regions, _ => true, } }); @@ -635,13 +643,13 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { self = print_prefix(self)?; for arg in args { match arg.unpack() { - UnpackedKind::Lifetime(lt) => { + GenericArgKind::Lifetime(lt) => { self = lt.print(self)?; } - UnpackedKind::Type(ty) => { + GenericArgKind::Type(ty) => { self = ty.print(self)?; } - UnpackedKind::Const(c) => { + GenericArgKind::Const(c) => { self.push("K"); // FIXME(const_generics) implement `ty::print::Print` on `ty::Const`. // self = c.print(self)?; diff --git a/src/librustc_codegen_utils/symbol_names_test.rs b/src/librustc_codegen_utils/symbol_names_test.rs index f562744dbe753..51269be4e9f40 100644 --- a/src/librustc_codegen_utils/symbol_names_test.rs +++ b/src/librustc_codegen_utils/symbol_names_test.rs @@ -40,7 +40,7 @@ impl SymbolNamesTest<'tcx> { let instance = Instance::mono(tcx, def_id); let mangled = self.tcx.symbol_name(instance); tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled)); - if let Ok(demangling) = rustc_demangle::try_demangle(&mangled.as_str()) { + if let Ok(demangling) = rustc_demangle::try_demangle(&mangled.name.as_str()) { tcx.sess.span_err(attr.span, &format!("demangling({})", demangling)); tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling)); } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 288676ce3ff67..065c8436ae06a 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -ena = "0.13" +ena = "0.13.1" indexmap = "1" log = "0.4" jobserver_crate = { version = "0.1.13", package = "jobserver" } @@ -20,11 +20,12 @@ graphviz = { path = "../libgraphviz" } cfg-if = "0.1.2" crossbeam-utils = { version = "0.6.5", features = ["nightly"] } stable_deref_trait = "1.0.0" -rayon = { version = "0.2.0", package = "rustc-rayon" } -rayon-core = { version = "0.2.0", package = "rustc-rayon-core" } +rayon = { version = "0.3.0", package = "rustc-rayon" } +rayon-core = { version = "0.3.0", package = "rustc-rayon-core" } rustc-hash = "1.0.1" smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } +rustc_index = { path = "../librustc_index", package = "rustc_index" } [dependencies.parking_lot] -version = "0.7" +version = "0.9" features = ["nightly"] diff --git a/src/librustc_data_structures/fingerprint.rs b/src/librustc_data_structures/fingerprint.rs index c8012bb942461..b43df6045d6aa 100644 --- a/src/librustc_data_structures/fingerprint.rs +++ b/src/librustc_data_structures/fingerprint.rs @@ -76,7 +76,7 @@ impl ::std::fmt::Display for Fingerprint { impl stable_hasher::StableHasherResult for Fingerprint { #[inline] - fn finish(hasher: stable_hasher::StableHasher) -> Self { + fn finish(hasher: stable_hasher::StableHasher) -> Self { let (_0, _1) = hasher.finalize(); Fingerprint(_0, _1) } diff --git a/src/librustc_data_structures/graph/dominators/mod.rs b/src/librustc_data_structures/graph/dominators/mod.rs index 41e6b72953e83..29a8a98d229cc 100644 --- a/src/librustc_data_structures/graph/dominators/mod.rs +++ b/src/librustc_data_structures/graph/dominators/mod.rs @@ -4,7 +4,7 @@ //! Rice Computer Science TS-06-33870 //! -use super::super::indexed_vec::{Idx, IndexVec}; +use rustc_index::vec::{Idx, IndexVec}; use super::iterate::reverse_post_order; use super::ControlFlowGraph; diff --git a/src/librustc_data_structures/graph/implementation/mod.rs b/src/librustc_data_structures/graph/implementation/mod.rs index d2699004c81d8..c438a8558a704 100644 --- a/src/librustc_data_structures/graph/implementation/mod.rs +++ b/src/librustc_data_structures/graph/implementation/mod.rs @@ -20,7 +20,7 @@ //! the field `next_edge`). Each of those fields is an array that should //! be indexed by the direction (see the type `Direction`). -use crate::bit_set::BitSet; +use rustc_index::bit_set::BitSet; use crate::snapshot_vec::{SnapshotVec, SnapshotVecDelegate}; use std::fmt::Debug; use std::usize; @@ -303,11 +303,11 @@ pub struct AdjacentEdges<'g, N, E> { impl<'g, N: Debug, E: Debug> AdjacentEdges<'g, N, E> { fn targets(self) -> impl Iterator + 'g { - self.into_iter().map(|(_, edge)| edge.target) + self.map(|(_, edge)| edge.target) } fn sources(self) -> impl Iterator + 'g { - self.into_iter().map(|(_, edge)| edge.source) + self.map(|(_, edge)| edge.source) } } diff --git a/src/librustc_data_structures/graph/iterate/mod.rs b/src/librustc_data_structures/graph/iterate/mod.rs index c4185fc7cd9c3..e268b28174474 100644 --- a/src/librustc_data_structures/graph/iterate/mod.rs +++ b/src/librustc_data_structures/graph/iterate/mod.rs @@ -1,6 +1,6 @@ -use super::super::indexed_vec::IndexVec; -use super::{DirectedGraph, WithNumNodes, WithSuccessors}; -use crate::bit_set::BitSet; +use rustc_index::vec::IndexVec; +use super::{DirectedGraph, WithNumNodes, WithSuccessors, WithStartNode}; +use rustc_index::bit_set::BitSet; #[cfg(test)] mod tests; @@ -85,3 +85,205 @@ where Some(n) } } + +/// Allows searches to terminate early with a value. +#[derive(Clone, Copy, Debug)] +pub enum ControlFlow { + Break(T), + Continue, +} + +/// The status of a node in the depth-first search. +/// +/// See the documentation of `TriColorDepthFirstSearch` to see how a node's status is updated +/// during DFS. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum NodeStatus { + /// This node has been examined by the depth-first search but is not yet `Settled`. + /// + /// Also referred to as "gray" or "discovered" nodes in [CLR][]. + /// + /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms + Visited, + + /// This node and all nodes reachable from it have been examined by the depth-first search. + /// + /// Also referred to as "black" or "finished" nodes in [CLR][]. + /// + /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms + Settled, +} + +struct Event { + node: N, + becomes: NodeStatus, +} + +/// A depth-first search that also tracks when all successors of a node have been examined. +/// +/// This is based on the DFS described in [Introduction to Algorithms (1st ed.)][CLR], hereby +/// referred to as **CLR**. However, we use the terminology in [`NodeStatus`][] above instead of +/// "discovered"/"finished" or "white"/"grey"/"black". Each node begins the search with no status, +/// becomes `Visited` when it is first examined by the DFS and is `Settled` when all nodes +/// reachable from it have been examined. This allows us to differentiate between "tree", "back" +/// and "forward" edges (see [`TriColorVisitor::node_examined`]). +/// +/// Unlike the pseudocode in [CLR][], this implementation is iterative and does not use timestamps. +/// We accomplish this by storing `Event`s on the stack that result in a (possible) state change +/// for each node. A `Visited` event signifies that we should examine this node if it has not yet +/// been `Visited` or `Settled`. When a node is examined for the first time, we mark it as +/// `Visited` and push a `Settled` event for it on stack followed by `Visited` events for all of +/// its predecessors, scheduling them for examination. Multiple `Visited` events for a single node +/// may exist on the stack simultaneously if a node has multiple predecessors, but only one +/// `Settled` event will ever be created for each node. After all `Visited` events for a node's +/// successors have been popped off the stack (as well as any new events triggered by visiting +/// those successors), we will pop off that node's `Settled` event. +/// +/// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms +/// [`NodeStatus`]: ./enum.NodeStatus.html +/// [`TriColorVisitor::node_examined`]: ./trait.TriColorVisitor.html#method.node_examined +pub struct TriColorDepthFirstSearch<'graph, G> +where + G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, +{ + graph: &'graph G, + stack: Vec>, + visited: BitSet, + settled: BitSet, +} + +impl TriColorDepthFirstSearch<'graph, G> +where + G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, +{ + pub fn new(graph: &'graph G) -> Self { + TriColorDepthFirstSearch { + graph, + stack: vec![], + visited: BitSet::new_empty(graph.num_nodes()), + settled: BitSet::new_empty(graph.num_nodes()), + } + } + + /// Performs a depth-first search, starting from the given `root`. + /// + /// This won't visit nodes that are not reachable from `root`. + pub fn run_from(mut self, root: G::Node, visitor: &mut V) -> Option + where + V: TriColorVisitor, + { + use NodeStatus::{Visited, Settled}; + + self.stack.push(Event { node: root, becomes: Visited }); + + loop { + match self.stack.pop()? { + Event { node, becomes: Settled } => { + let not_previously_settled = self.settled.insert(node); + assert!(not_previously_settled, "A node should be settled exactly once"); + if let ControlFlow::Break(val) = visitor.node_settled(node) { + return Some(val); + } + } + + Event { node, becomes: Visited } => { + let not_previously_visited = self.visited.insert(node); + let prior_status = if not_previously_visited { + None + } else if self.settled.contains(node) { + Some(Settled) + } else { + Some(Visited) + }; + + if let ControlFlow::Break(val) = visitor.node_examined(node, prior_status) { + return Some(val); + } + + // If this node has already been examined, we are done. + if prior_status.is_some() { + continue; + } + + // Otherwise, push a `Settled` event for this node onto the stack, then + // schedule its successors for examination. + self.stack.push(Event { node, becomes: Settled }); + for succ in self.graph.successors(node) { + self.stack.push(Event { node: succ, becomes: Visited }); + } + } + } + } + } +} + +impl TriColorDepthFirstSearch<'graph, G> +where + G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors + WithStartNode, +{ + /// Performs a depth-first search, starting from `G::start_node()`. + /// + /// This won't visit nodes that are not reachable from the start node. + pub fn run_from_start(self, visitor: &mut V) -> Option + where + V: TriColorVisitor, + { + let root = self.graph.start_node(); + self.run_from(root, visitor) + } +} + +/// What to do when a node is examined or becomes `Settled` during DFS. +pub trait TriColorVisitor +where + G: ?Sized + DirectedGraph, +{ + /// The value returned by this search. + type BreakVal; + + /// Called when a node is examined by the depth-first search. + /// + /// By checking the value of `prior_status`, this visitor can determine whether the edge + /// leading to this node was a tree edge (`None`), forward edge (`Some(Settled)`) or back edge + /// (`Some(Visited)`). For a full explanation of each edge type, see the "Depth-first Search" + /// chapter in [CLR][] or [wikipedia][]. + /// + /// If you want to know *both* nodes linked by each edge, you'll need to modify + /// `TriColorDepthFirstSearch` to store a `source` node for each `Visited` event. + /// + /// [wikipedia]: https://en.wikipedia.org/wiki/Depth-first_search#Output_of_a_depth-first_search + /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms + fn node_examined( + &mut self, + _target: G::Node, + _prior_status: Option, + ) -> ControlFlow { + ControlFlow::Continue + } + + /// Called after all nodes reachable from this one have been examined. + fn node_settled(&mut self, _target: G::Node) -> ControlFlow { + ControlFlow::Continue + } +} + +/// This `TriColorVisitor` looks for back edges in a graph, which indicate that a cycle exists. +pub struct CycleDetector; + +impl TriColorVisitor for CycleDetector +where + G: ?Sized + DirectedGraph, +{ + type BreakVal = (); + + fn node_examined( + &mut self, + _node: G::Node, + prior_status: Option, + ) -> ControlFlow { + match prior_status { + Some(NodeStatus::Visited) => ControlFlow::Break(()), + _ => ControlFlow::Continue, + } + } +} diff --git a/src/librustc_data_structures/graph/iterate/tests.rs b/src/librustc_data_structures/graph/iterate/tests.rs index 6c7cfd6d8a777..0e038e88b221d 100644 --- a/src/librustc_data_structures/graph/iterate/tests.rs +++ b/src/librustc_data_structures/graph/iterate/tests.rs @@ -9,3 +9,14 @@ fn diamond_post_order() { let result = post_order_from(&graph, 0); assert_eq!(result, vec![3, 1, 2, 0]); } + +#[test] +fn is_cyclic() { + use super::super::is_cyclic; + + let diamond_acyclic = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]); + let diamond_cyclic = TestGraph::new(0, &[(0, 1), (1, 2), (2, 3), (3, 0)]); + + assert!(!is_cyclic(&diamond_acyclic)); + assert!(is_cyclic(&diamond_cyclic)); +} diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index 662581ca1e498..37335799d19af 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -1,4 +1,4 @@ -use super::indexed_vec::Idx; +use rustc_index::vec::Idx; pub mod dominators; pub mod implementation; @@ -81,3 +81,13 @@ where + WithNumNodes, { } + +/// Returns `true` if the graph has a cycle that is reachable from the start node. +pub fn is_cyclic(graph: &G) -> bool +where + G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes, +{ + iterate::TriColorDepthFirstSearch::new(graph) + .run_from_start(&mut iterate::CycleDetector) + .is_some() +} diff --git a/src/librustc_data_structures/graph/scc/mod.rs b/src/librustc_data_structures/graph/scc/mod.rs index 23a1a2a90a4d5..c214f66cd15cd 100644 --- a/src/librustc_data_structures/graph/scc/mod.rs +++ b/src/librustc_data_structures/graph/scc/mod.rs @@ -6,7 +6,7 @@ use crate::fx::FxHashSet; use crate::graph::{DirectedGraph, WithNumNodes, WithNumEdges, WithSuccessors, GraphSuccessors}; use crate::graph::vec_graph::VecGraph; -use crate::indexed_vec::{Idx, IndexVec}; +use rustc_index::vec::{Idx, IndexVec}; use std::ops::Range; #[cfg(test)] diff --git a/src/librustc_data_structures/graph/vec_graph/mod.rs b/src/librustc_data_structures/graph/vec_graph/mod.rs index 19c61f2680d1d..aad5944dcd0be 100644 --- a/src/librustc_data_structures/graph/vec_graph/mod.rs +++ b/src/librustc_data_structures/graph/vec_graph/mod.rs @@ -1,4 +1,4 @@ -use crate::indexed_vec::{Idx, IndexVec}; +use rustc_index::vec::{Idx, IndexVec}; use crate::graph::{DirectedGraph, WithNumNodes, WithNumEdges, WithSuccessors, GraphSuccessors}; #[cfg(test)] diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 8fb0ea0271b97..474a42644d915 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -23,10 +23,11 @@ #![feature(core_intrinsics)] #![feature(integer_atomics)] #![feature(test)] +#![feature(associated_type_bounds)] #![cfg_attr(unix, feature(libc))] -#![cfg_attr(not(bootstrap), allow(rustc::default_hash_types))] +#![allow(rustc::default_hash_types)] #[macro_use] extern crate log; @@ -67,13 +68,12 @@ pub mod macros; pub mod svh; pub mod base_n; pub mod binary_search_util; -pub mod bit_set; pub mod box_region; pub mod const_cstr; pub mod flock; pub mod fx; +pub mod stable_map; pub mod graph; -pub mod indexed_vec; pub mod jobserver; pub mod obligation_forest; pub mod owning_ref; @@ -83,6 +83,7 @@ pub mod small_c_str; pub mod snapshot_map; pub use ena::snapshot_vec; pub mod sorted_map; +pub mod stable_set; #[macro_use] pub mod stable_hasher; pub mod sync; pub mod sharded; diff --git a/src/librustc_data_structures/obligation_forest/graphviz.rs b/src/librustc_data_structures/obligation_forest/graphviz.rs index a0363e165e049..ddf89d99621ca 100644 --- a/src/librustc_data_structures/obligation_forest/graphviz.rs +++ b/src/librustc_data_structures/obligation_forest/graphviz.rs @@ -74,9 +74,7 @@ impl<'a, O: ForestObligation + 'a> dot::GraphWalk<'a> for &'a ObligationForest ambiguous result. Obligation was neither a success +//! - `Unchanged` -> ambiguous result. Obligation was neither a success //! nor a failure. It is assumed that further attempts to process the //! obligation will yield the same result unless something in the //! surrounding environment changes. -//! - `Ok(Some(C))` - the obligation was *shallowly successful*. The +//! - `Changed(C)` - the obligation was *shallowly successful*. The //! vector `C` is a list of subobligations. The meaning of this is that //! `O` was successful on the assumption that all the obligations in `C` //! are also successful. Therefore, `O` is only considered a "true" @@ -34,7 +34,7 @@ //! state and the obligations in `C` become the new pending //! obligations. They will be processed the next time you call //! `process_obligations`. -//! - `Err(E)` -> obligation failed with error `E`. We will collect this +//! - `Error(E)` -> obligation failed with error `E`. We will collect this //! error and return it from `process_obligations`, along with the //! "backtrace" of obligations (that is, the list of obligations up to //! and including the root of the failed obligation). No further @@ -47,50 +47,39 @@ //! - `completed`: a list of obligations where processing was fully //! completed without error (meaning that all transitive subobligations //! have also been completed). So, for example, if the callback from -//! `process_obligations` returns `Ok(Some(C))` for some obligation `O`, +//! `process_obligations` returns `Changed(C)` for some obligation `O`, //! then `O` will be considered completed right away if `C` is the //! empty vector. Otherwise it will only be considered completed once //! all the obligations in `C` have been found completed. //! - `errors`: a list of errors that occurred and associated backtraces //! at the time of error, which can be used to give context to the user. //! - `stalled`: if true, then none of the existing obligations were -//! *shallowly successful* (that is, no callback returned `Ok(Some(_))`). +//! *shallowly successful* (that is, no callback returned `Changed(_)`). //! This implies that all obligations were either errors or returned an //! ambiguous result, which means that any further calls to //! `process_obligations` would simply yield back further ambiguous //! results. This is used by the `FulfillmentContext` to decide when it //! has reached a steady state. //! -//! #### Snapshots -//! -//! The `ObligationForest` supports a limited form of snapshots; see -//! `start_snapshot`, `commit_snapshot`, and `rollback_snapshot`. In -//! particular, you can use a snapshot to roll back new root -//! obligations. However, it is an error to attempt to -//! `process_obligations` during a snapshot. -//! //! ### Implementation details //! //! For the most part, comments specific to the implementation are in the //! code. This file only contains a very high-level overview. Basically, //! the forest is stored in a vector. Each element of the vector is a node -//! in some tree. Each node in the vector has the index of an (optional) -//! parent and (for convenience) its root (which may be itself). It also -//! has a current state, described by `NodeState`. After each -//! processing step, we compress the vector to remove completed and error -//! nodes, which aren't needed anymore. +//! in some tree. Each node in the vector has the index of its dependents, +//! including the first dependent which is known as the parent. It also +//! has a current state, described by `NodeState`. After each processing +//! step, we compress the vector to remove completed and error nodes, which +//! aren't needed anymore. use crate::fx::{FxHashMap, FxHashSet}; -use std::cell::Cell; +use std::cell::{Cell, RefCell}; use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash; use std::marker::PhantomData; -mod node_index; -use self::node_index::NodeIndex; - mod graphviz; #[cfg(test)] @@ -148,18 +137,22 @@ pub struct ObligationForest { /// At the end of processing, those nodes will be removed by a /// call to `compress`. /// - /// At all times we maintain the invariant that every node appears - /// at a higher index than its parent. This is needed by the - /// backtrace iterator (which uses `split_at`). + /// `usize` indices are used here and throughout this module, rather than + /// `rustc_index::newtype_index!` indices, because this code is hot enough that the + /// `u32`-to-`usize` conversions that would be required are significant, + /// and space considerations are not important. nodes: Vec>, /// A cache of predicates that have been successfully completed. done_cache: FxHashSet, - /// An cache of the nodes in `nodes`, indexed by predicate. - waiting_cache: FxHashMap, + /// A cache of the nodes in `nodes`, indexed by predicate. Unfortunately, + /// its contents are not guaranteed to match those of `nodes`. See the + /// comments in `process_obligation` for details. + active_cache: FxHashMap, - scratch: Option>, + /// A vector reused in compress(), to avoid allocating new vectors. + node_rewrites: RefCell>, obligation_tree_id_generator: ObligationTreeIdGenerator, @@ -178,19 +171,42 @@ struct Node { obligation: O, state: Cell, - /// The parent of a node - the original obligation of - /// which it is a subobligation. Except for error reporting, - /// it is just like any member of `dependents`. - parent: Option, + /// Obligations that depend on this obligation for their completion. They + /// must all be in a non-pending state. + dependents: Vec, - /// Obligations that depend on this obligation for their - /// completion. They must all be in a non-pending state. - dependents: Vec, + /// If true, dependents[0] points to a "parent" node, which requires + /// special treatment upon error but is otherwise treated the same. + /// (It would be more idiomatic to store the parent node in a separate + /// `Option` field, but that slows down the common case of + /// iterating over the parent and other descendants together.) + has_parent: bool, /// Identifier of the obligation tree to which this node belongs. obligation_tree_id: ObligationTreeId, } +impl Node { + fn new( + parent: Option, + obligation: O, + obligation_tree_id: ObligationTreeId + ) -> Node { + Node { + obligation, + state: Cell::new(NodeState::Pending), + dependents: + if let Some(parent_index) = parent { + vec![parent_index] + } else { + vec![] + }, + has_parent: parent.is_some(), + obligation_tree_id, + } + } +} + /// The state of one node in some tree within the forest. This /// represents the current state of processing for the obligation (of /// type `O`) associated with this node. @@ -218,10 +234,6 @@ enum NodeState { /// This obligation was resolved to an error. Error nodes are /// removed from the vector by the compression step. Error, - - /// This is a temporary state used in DFS loops to detect cycles, - /// it should not exist outside of these DFSes. - OnDfsStack, } #[derive(Debug)] @@ -261,8 +273,8 @@ impl ObligationForest { ObligationForest { nodes: vec![], done_cache: Default::default(), - waiting_cache: Default::default(), - scratch: Some(vec![]), + active_cache: Default::default(), + node_rewrites: RefCell::new(vec![]), obligation_tree_id_generator: (0..).map(ObligationTreeId), error_cache: Default::default(), } @@ -275,34 +287,30 @@ impl ObligationForest { } /// Registers an obligation. - /// - /// This CAN be done in a snapshot pub fn register_obligation(&mut self, obligation: O) { // Ignore errors here - there is no guarantee of success. let _ = self.register_obligation_at(obligation, None); } - // returns Err(()) if we already know this obligation failed. - fn register_obligation_at(&mut self, obligation: O, parent: Option) - -> Result<(), ()> - { + // Returns Err(()) if we already know this obligation failed. + fn register_obligation_at(&mut self, obligation: O, parent: Option) -> Result<(), ()> { if self.done_cache.contains(obligation.as_predicate()) { return Ok(()); } - match self.waiting_cache.entry(obligation.as_predicate().clone()) { + match self.active_cache.entry(obligation.as_predicate().clone()) { Entry::Occupied(o) => { + let index = *o.get(); debug!("register_obligation_at({:?}, {:?}) - duplicate of {:?}!", - obligation, parent, o.get()); - let node = &mut self.nodes[o.get().get()]; - if let Some(parent) = parent { - // If the node is already in `waiting_cache`, it's already - // been marked with a parent. (It's possible that parent - // has been cleared by `apply_rewrites`, though.) So just - // dump `parent` into `node.dependents`... unless it's - // already in `node.dependents` or `node.parent`. - if !node.dependents.contains(&parent) && Some(parent) != node.parent { - node.dependents.push(parent); + obligation, parent, index); + let node = &mut self.nodes[index]; + if let Some(parent_index) = parent { + // If the node is already in `active_cache`, it has already + // had its chance to be marked with a parent. So if it's + // not already present, just dump `parent` into the + // dependents as a non-parent. + if !node.dependents.contains(&parent_index) { + node.dependents.push(parent_index); } } if let NodeState::Error = node.state.get() { @@ -316,11 +324,8 @@ impl ObligationForest { obligation, parent, self.nodes.len()); let obligation_tree_id = match parent { - Some(p) => { - let parent_node = &self.nodes[p.get()]; - parent_node.obligation_tree_id - } - None => self.obligation_tree_id_generator.next().unwrap() + Some(parent_index) => self.nodes[parent_index].obligation_tree_id, + None => self.obligation_tree_id_generator.next().unwrap(), }; let already_failed = @@ -333,7 +338,8 @@ impl ObligationForest { if already_failed { Err(()) } else { - v.insert(NodeIndex::new(self.nodes.len())); + let new_index = self.nodes.len(); + v.insert(new_index); self.nodes.push(Node::new(parent, obligation, obligation_tree_id)); Ok(()) } @@ -342,19 +348,17 @@ impl ObligationForest { } /// Converts all remaining obligations to the given error. - /// - /// This cannot be done during a snapshot. pub fn to_errors(&mut self, error: E) -> Vec> { - let mut errors = vec![]; - for index in 0..self.nodes.len() { - if let NodeState::Pending = self.nodes[index].state.get() { - let backtrace = self.error_at(index); - errors.push(Error { + let errors = self.nodes.iter().enumerate() + .filter(|(_index, node)| node.state.get() == NodeState::Pending) + .map(|(index, _node)| { + Error { error: error.clone(), - backtrace, - }); - } - } + backtrace: self.error_at(index), + } + }) + .collect(); + let successful_obligations = self.compress(DoCompleted::Yes); assert!(successful_obligations.unwrap().is_empty()); errors @@ -364,16 +368,14 @@ impl ObligationForest { pub fn map_pending_obligations(&self, f: F) -> Vec

where F: Fn(&O) -> P { - self.nodes - .iter() - .filter(|n| n.state.get() == NodeState::Pending) - .map(|n| f(&n.obligation)) + self.nodes.iter() + .filter(|node| node.state.get() == NodeState::Pending) + .map(|node| f(&node.obligation)) .collect() } - fn insert_into_error_cache(&mut self, node_index: usize) { - let node = &self.nodes[node_index]; - + fn insert_into_error_cache(&mut self, index: usize) { + let node = &self.nodes[index]; self.error_cache .entry(node.obligation_tree_id) .or_default() @@ -394,13 +396,19 @@ impl ObligationForest { let mut stalled = true; for index in 0..self.nodes.len() { - debug!("process_obligations: node {} == {:?}", index, self.nodes[index]); + let node = &mut self.nodes[index]; - let result = match self.nodes[index] { - Node { ref state, ref mut obligation, .. } if state.get() == NodeState::Pending => - processor.process_obligation(obligation), - _ => continue - }; + debug!("process_obligations: node {} == {:?}", index, node); + + // `processor.process_obligation` can modify the predicate within + // `node.obligation`, and that predicate is the key used for + // `self.active_cache`. This means that `self.active_cache` can get + // out of sync with `nodes`. It's not very common, but it does + // happen, and code in `compress` has to allow for it. + if node.state.get() != NodeState::Pending { + continue; + } + let result = processor.process_obligation(&mut node.obligation); debug!("process_obligations: node {} got result {:?}", index, result); @@ -411,15 +419,15 @@ impl ObligationForest { ProcessResult::Changed(children) => { // We are not (yet) stalled. stalled = false; - self.nodes[index].state.set(NodeState::Success); + node.state.set(NodeState::Success); for child in children { let st = self.register_obligation_at( child, - Some(NodeIndex::new(index)) + Some(index) ); if let Err(()) = st { - // error already reported - propagate it + // Error already reported - propagate it // to our node. self.error_at(index); } @@ -427,10 +435,9 @@ impl ObligationForest { } ProcessResult::Error(err) => { stalled = false; - let backtrace = self.error_at(index); errors.push(Error { error: err, - backtrace, + backtrace: self.error_at(index), }); } } @@ -448,8 +455,6 @@ impl ObligationForest { self.mark_as_waiting(); self.process_cycles(processor); - - // Now we have to compress the result let completed = self.compress(do_completed); debug!("process_obligations: complete"); @@ -465,107 +470,111 @@ impl ObligationForest { /// report all cycles between them. This should be called /// after `mark_as_waiting` marks all nodes with pending /// subobligations as NodeState::Waiting. - fn process_cycles

(&mut self, processor: &mut P) + fn process_cycles

(&self, processor: &mut P) where P: ObligationProcessor { - let mut stack = self.scratch.take().unwrap(); - debug_assert!(stack.is_empty()); + let mut stack = vec![]; debug!("process_cycles()"); - for index in 0..self.nodes.len() { - // For rustc-benchmarks/inflate-0.1.0 this state test is extremely - // hot and the state is almost always `Pending` or `Waiting`. It's - // a win to handle the no-op cases immediately to avoid the cost of - // the function call. - let state = self.nodes[index].state.get(); - match state { - NodeState::Waiting | NodeState::Pending | NodeState::Done | NodeState::Error => {}, - _ => self.find_cycles_from_node(&mut stack, processor, index), + for (index, node) in self.nodes.iter().enumerate() { + // For some benchmarks this state test is extremely + // hot. It's a win to handle the no-op cases immediately to avoid + // the cost of the function call. + if node.state.get() == NodeState::Success { + self.find_cycles_from_node(&mut stack, processor, index); } } debug!("process_cycles: complete"); debug_assert!(stack.is_empty()); - self.scratch = Some(stack); } - fn find_cycles_from_node

(&self, stack: &mut Vec, - processor: &mut P, index: usize) + fn find_cycles_from_node

(&self, stack: &mut Vec, processor: &mut P, index: usize) where P: ObligationProcessor { let node = &self.nodes[index]; - let state = node.state.get(); - match state { - NodeState::OnDfsStack => { - let index = - stack.iter().rposition(|n| *n == index).unwrap(); - processor.process_backedge(stack[index..].iter().map(GetObligation(&self.nodes)), - PhantomData); - } - NodeState::Success => { - node.state.set(NodeState::OnDfsStack); - stack.push(index); - for dependent in node.parent.iter().chain(node.dependents.iter()) { - self.find_cycles_from_node(stack, processor, dependent.get()); + if node.state.get() == NodeState::Success { + match stack.iter().rposition(|&n| n == index) { + None => { + stack.push(index); + for &index in node.dependents.iter() { + self.find_cycles_from_node(stack, processor, index); + } + stack.pop(); + node.state.set(NodeState::Done); + } + Some(rpos) => { + // Cycle detected. + processor.process_backedge( + stack[rpos..].iter().map(GetObligation(&self.nodes)), + PhantomData + ); } - stack.pop(); - node.state.set(NodeState::Done); - }, - NodeState::Waiting | NodeState::Pending => { - // this node is still reachable from some pending node. We - // will get to it when they are all processed. - } - NodeState::Done | NodeState::Error => { - // already processed that node } - }; + } } /// Returns a vector of obligations for `p` and all of its /// ancestors, putting them into the error state in the process. - fn error_at(&mut self, p: usize) -> Vec { - let mut error_stack = self.scratch.take().unwrap(); + fn error_at(&self, mut index: usize) -> Vec { + let mut error_stack: Vec = vec![]; let mut trace = vec![]; - let mut n = p; loop { - self.nodes[n].state.set(NodeState::Error); - trace.push(self.nodes[n].obligation.clone()); - error_stack.extend(self.nodes[n].dependents.iter().map(|x| x.get())); - - // loop to the parent - match self.nodes[n].parent { - Some(q) => n = q.get(), - None => break + let node = &self.nodes[index]; + node.state.set(NodeState::Error); + trace.push(node.obligation.clone()); + if node.has_parent { + // The first dependent is the parent, which is treated + // specially. + error_stack.extend(node.dependents.iter().skip(1)); + index = node.dependents[0]; + } else { + // No parent; treat all dependents non-specially. + error_stack.extend(node.dependents.iter()); + break; } } - while let Some(i) = error_stack.pop() { - match self.nodes[i].state.get() { - NodeState::Error => continue, - _ => self.nodes[i].state.set(NodeState::Error), + while let Some(index) = error_stack.pop() { + let node = &self.nodes[index]; + if node.state.get() != NodeState::Error { + node.state.set(NodeState::Error); + error_stack.extend(node.dependents.iter()); } - - let node = &self.nodes[i]; - - error_stack.extend( - node.parent.iter().chain(node.dependents.iter()).map(|x| x.get()) - ); } - self.scratch = Some(error_stack); trace } - #[inline] - fn mark_neighbors_as_waiting_from(&self, node: &Node) { - for dependent in node.parent.iter().chain(node.dependents.iter()) { - self.mark_as_waiting_from(&self.nodes[dependent.get()]); + // This always-inlined function is for the hot call site. + #[inline(always)] + fn inlined_mark_neighbors_as_waiting_from(&self, node: &Node) { + for &index in node.dependents.iter() { + let node = &self.nodes[index]; + match node.state.get() { + NodeState::Waiting | NodeState::Error => {} + NodeState::Success => { + node.state.set(NodeState::Waiting); + // This call site is cold. + self.uninlined_mark_neighbors_as_waiting_from(node); + } + NodeState::Pending | NodeState::Done => { + // This call site is cold. + self.uninlined_mark_neighbors_as_waiting_from(node); + } + } } } + // This never-inlined function is for the cold call site. + #[inline(never)] + fn uninlined_mark_neighbors_as_waiting_from(&self, node: &Node) { + self.inlined_mark_neighbors_as_waiting_from(node) + } + /// Marks all nodes that depend on a pending node as `NodeState::Waiting`. fn mark_as_waiting(&self) { for node in &self.nodes { @@ -576,162 +585,125 @@ impl ObligationForest { for node in &self.nodes { if node.state.get() == NodeState::Pending { - self.mark_neighbors_as_waiting_from(node); + // This call site is hot. + self.inlined_mark_neighbors_as_waiting_from(node); } } } - fn mark_as_waiting_from(&self, node: &Node) { - match node.state.get() { - NodeState::Waiting | NodeState::Error | NodeState::OnDfsStack => return, - NodeState::Success => node.state.set(NodeState::Waiting), - NodeState::Pending | NodeState::Done => {}, - } - - self.mark_neighbors_as_waiting_from(node); - } - - /// Compresses the vector, removing all popped nodes. This adjusts - /// the indices and hence invalidates any outstanding - /// indices. Cannot be used during a transaction. + /// Compresses the vector, removing all popped nodes. This adjusts the + /// indices and hence invalidates any outstanding indices. /// /// Beforehand, all nodes must be marked as `Done` and no cycles /// on these nodes may be present. This is done by e.g., `process_cycles`. #[inline(never)] fn compress(&mut self, do_completed: DoCompleted) -> Option> { - let nodes_len = self.nodes.len(); - let mut node_rewrites: Vec<_> = self.scratch.take().unwrap(); - node_rewrites.extend(0..nodes_len); + let orig_nodes_len = self.nodes.len(); + let mut node_rewrites: Vec<_> = self.node_rewrites.replace(vec![]); + debug_assert!(node_rewrites.is_empty()); + node_rewrites.extend(0..orig_nodes_len); let mut dead_nodes = 0; + let mut removed_done_obligations: Vec = vec![]; - // Now move all popped nodes to the end. Try to keep the order. + // Now move all Done/Error nodes to the end, preserving the order of + // the Pending/Waiting nodes. // // LOOP INVARIANT: - // self.nodes[0..i - dead_nodes] are the first remaining nodes - // self.nodes[i - dead_nodes..i] are all dead - // self.nodes[i..] are unchanged - for i in 0..self.nodes.len() { - match self.nodes[i].state.get() { + // self.nodes[0..index - dead_nodes] are the first remaining nodes + // self.nodes[index - dead_nodes..index] are all dead + // self.nodes[index..] are unchanged + for index in 0..orig_nodes_len { + let node = &self.nodes[index]; + match node.state.get() { NodeState::Pending | NodeState::Waiting => { if dead_nodes > 0 { - self.nodes.swap(i, i - dead_nodes); - node_rewrites[i] -= dead_nodes; + self.nodes.swap(index, index - dead_nodes); + node_rewrites[index] -= dead_nodes; } } NodeState::Done => { - // Avoid cloning the key (predicate) in case it exists in the waiting cache - if let Some((predicate, _)) = self.waiting_cache - .remove_entry(self.nodes[i].obligation.as_predicate()) + // This lookup can fail because the contents of + // `self.active_cache` are not guaranteed to match those of + // `self.nodes`. See the comment in `process_obligation` + // for more details. + if let Some((predicate, _)) = + self.active_cache.remove_entry(node.obligation.as_predicate()) { self.done_cache.insert(predicate); } else { - self.done_cache.insert(self.nodes[i].obligation.as_predicate().clone()); + self.done_cache.insert(node.obligation.as_predicate().clone()); + } + if do_completed == DoCompleted::Yes { + // Extract the success stories. + removed_done_obligations.push(node.obligation.clone()); } - node_rewrites[i] = nodes_len; + node_rewrites[index] = orig_nodes_len; dead_nodes += 1; } NodeState::Error => { // We *intentionally* remove the node from the cache at this point. Otherwise // tests must come up with a different type on every type error they // check against. - self.waiting_cache.remove(self.nodes[i].obligation.as_predicate()); - node_rewrites[i] = nodes_len; + self.active_cache.remove(node.obligation.as_predicate()); + self.insert_into_error_cache(index); + node_rewrites[index] = orig_nodes_len; dead_nodes += 1; - self.insert_into_error_cache(i); } - NodeState::OnDfsStack | NodeState::Success => unreachable!() + NodeState::Success => unreachable!() } } - // No compression needed. - if dead_nodes == 0 { - node_rewrites.truncate(0); - self.scratch = Some(node_rewrites); - return if do_completed == DoCompleted::Yes { Some(vec![]) } else { None }; + if dead_nodes > 0 { + // Remove the dead nodes and rewrite indices. + self.nodes.truncate(orig_nodes_len - dead_nodes); + self.apply_rewrites(&node_rewrites); } - // Pop off all the nodes we killed and extract the success - // stories. - let successful = if do_completed == DoCompleted::Yes { - Some((0..dead_nodes) - .map(|_| self.nodes.pop().unwrap()) - .flat_map(|node| { - match node.state.get() { - NodeState::Error => None, - NodeState::Done => Some(node.obligation), - _ => unreachable!() - } - }) - .collect()) - } else { - self.nodes.truncate(self.nodes.len() - dead_nodes); - None - }; - self.apply_rewrites(&node_rewrites); - node_rewrites.truncate(0); - self.scratch = Some(node_rewrites); + self.node_rewrites.replace(node_rewrites); - successful + if do_completed == DoCompleted::Yes { + Some(removed_done_obligations) + } else { + None + } } fn apply_rewrites(&mut self, node_rewrites: &[usize]) { - let nodes_len = node_rewrites.len(); + let orig_nodes_len = node_rewrites.len(); for node in &mut self.nodes { - if let Some(index) = node.parent { - let new_index = node_rewrites[index.get()]; - if new_index >= nodes_len { - // parent dead due to error - node.parent = None; - } else { - node.parent = Some(NodeIndex::new(new_index)); - } - } - let mut i = 0; while i < node.dependents.len() { - let new_index = node_rewrites[node.dependents[i].get()]; - if new_index >= nodes_len { + let new_index = node_rewrites[node.dependents[i]]; + if new_index >= orig_nodes_len { node.dependents.swap_remove(i); + if i == 0 && node.has_parent { + // We just removed the parent. + node.has_parent = false; + } } else { - node.dependents[i] = NodeIndex::new(new_index); + node.dependents[i] = new_index; i += 1; } } } - let mut kill_list = vec![]; - for (predicate, index) in &mut self.waiting_cache { - let new_index = node_rewrites[index.get()]; - if new_index >= nodes_len { - kill_list.push(predicate.clone()); + // This updating of `self.active_cache` is necessary because the + // removal of nodes within `compress` can fail. See above. + self.active_cache.retain(|_predicate, index| { + let new_index = node_rewrites[*index]; + if new_index >= orig_nodes_len { + false } else { - *index = NodeIndex::new(new_index); + *index = new_index; + true } - } - - for predicate in kill_list { self.waiting_cache.remove(&predicate); } - } -} - -impl Node { - fn new( - parent: Option, - obligation: O, - obligation_tree_id: ObligationTreeId - ) -> Node { - Node { - obligation, - state: Cell::new(NodeState::Pending), - parent, - dependents: vec![], - obligation_tree_id, - } + }); } } -// I need a Clone closure +// I need a Clone closure. #[derive(Clone)] struct GetObligation<'a, O>(&'a [Node]); diff --git a/src/librustc_data_structures/obligation_forest/node_index.rs b/src/librustc_data_structures/obligation_forest/node_index.rs deleted file mode 100644 index 69ea473e05461..0000000000000 --- a/src/librustc_data_structures/obligation_forest/node_index.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::num::NonZeroU32; -use std::u32; - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct NodeIndex { - index: NonZeroU32, -} - -impl NodeIndex { - #[inline] - pub fn new(value: usize) -> NodeIndex { - assert!(value < (u32::MAX as usize)); - NodeIndex { index: NonZeroU32::new((value as u32) + 1).unwrap() } - } - - #[inline] - pub fn get(self) -> usize { - (self.index.get() - 1) as usize - } -} diff --git a/src/librustc_data_structures/obligation_forest/tests.rs b/src/librustc_data_structures/obligation_forest/tests.rs index e20466572a26f..54b6f6d0adc6c 100644 --- a/src/librustc_data_structures/obligation_forest/tests.rs +++ b/src/librustc_data_structures/obligation_forest/tests.rs @@ -116,7 +116,9 @@ fn push_pop() { _ => unreachable!(), } }, |_| {}), DoCompleted::Yes); - assert_eq!(ok.unwrap(), vec!["A.3", "A.1", "A.3.i"]); + let mut ok = ok.unwrap(); + ok.sort(); + assert_eq!(ok, vec!["A.1", "A.3", "A.3.i"]); assert_eq!(err, vec![Error { error: "A is for apple", @@ -132,7 +134,9 @@ fn push_pop() { _ => panic!("unexpected obligation {:?}", obligation), } }, |_| {}), DoCompleted::Yes); - assert_eq!(ok.unwrap(), vec!["D.2.i", "D.2"]); + let mut ok = ok.unwrap(); + ok.sort(); + assert_eq!(ok, vec!["D.2", "D.2.i"]); assert_eq!(err, vec![Error { error: "D is for dumb", @@ -172,7 +176,9 @@ fn success_in_grandchildren() { _ => unreachable!(), } }, |_| {}), DoCompleted::Yes); - assert_eq!(ok.unwrap(), vec!["A.3", "A.1"]); + let mut ok = ok.unwrap(); + ok.sort(); + assert_eq!(ok, vec!["A.1", "A.3"]); assert!(err.is_empty()); let Outcome { completed: ok, errors: err, .. } = @@ -193,7 +199,9 @@ fn success_in_grandchildren() { _ => unreachable!(), } }, |_| {}), DoCompleted::Yes); - assert_eq!(ok.unwrap(), vec!["A.2.i.a", "A.2.i", "A.2", "A"]); + let mut ok = ok.unwrap(); + ok.sort(); + assert_eq!(ok, vec!["A", "A.2", "A.2.i", "A.2.i.a"]); assert!(err.is_empty()); let Outcome { completed: ok, errors: err, .. } = @@ -261,7 +269,9 @@ fn diamond() { } }, |_|{}), DoCompleted::Yes); assert_eq!(d_count, 1); - assert_eq!(ok.unwrap(), vec!["D", "A.2", "A.1", "A"]); + let mut ok = ok.unwrap(); + ok.sort(); + assert_eq!(ok, vec!["A", "A.1", "A.2", "D"]); assert_eq!(err.len(), 0); let errors = forest.to_errors(()); @@ -323,7 +333,9 @@ fn done_dependency() { _ => unreachable!(), } }, |_|{}), DoCompleted::Yes); - assert_eq!(ok.unwrap(), vec!["C: Sized", "B: Sized", "A: Sized"]); + let mut ok = ok.unwrap(); + ok.sort(); + assert_eq!(ok, vec!["A: Sized", "B: Sized", "C: Sized"]); assert_eq!(err.len(), 0); forest.register_obligation("(A,B,C): Sized"); @@ -361,7 +373,9 @@ fn orphan() { _ => unreachable!(), } }, |_|{}), DoCompleted::Yes); - assert_eq!(ok.unwrap(), vec!["C2", "C1"]); + let mut ok = ok.unwrap(); + ok.sort(); + assert_eq!(ok, vec!["C1", "C2"]); assert_eq!(err.len(), 0); let Outcome { completed: ok, errors: err, .. } = diff --git a/src/librustc_data_structures/owning_ref/mod.rs b/src/librustc_data_structures/owning_ref/mod.rs index ea9c5283aee7d..b835b1706b85f 100644 --- a/src/librustc_data_structures/owning_ref/mod.rs +++ b/src/librustc_data_structures/owning_ref/mod.rs @@ -847,7 +847,9 @@ pub trait ToHandleMut { } impl OwningHandle - where O: StableAddress, O::Target: ToHandle, H: Deref, +where + O: StableAddress>, + H: Deref, { /// Creates a new `OwningHandle` for a type that implements `ToHandle`. For types /// that don't implement `ToHandle`, callers may invoke `new_with_fn`, which accepts @@ -858,7 +860,9 @@ impl OwningHandle } impl OwningHandle - where O: StableAddress, O::Target: ToHandleMut, H: DerefMut, +where + O: StableAddress>, + H: DerefMut, { /// Creates a new mutable `OwningHandle` for a type that implements `ToHandleMut`. pub fn new_mut(o: O) -> Self { diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index 47dfc1d1688d0..ee4f6a5e785e4 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -1,10 +1,9 @@ use std::hash::{Hash, Hasher, BuildHasher}; -use std::marker::PhantomData; use std::mem; use smallvec::SmallVec; use crate::sip128::SipHasher128; -use crate::indexed_vec; -use crate::bit_set; +use rustc_index::vec; +use rustc_index::bit_set; /// When hashing something that ends up affecting properties like symbol names, /// we want these symbol names to be calculated independently of other factors @@ -13,55 +12,53 @@ use crate::bit_set; /// To that end we always convert integers to little-endian format before /// hashing and the architecture dependent `isize` and `usize` types are /// extended to 64 bits if needed. -pub struct StableHasher { +pub struct StableHasher { state: SipHasher128, - width: PhantomData, } -impl ::std::fmt::Debug for StableHasher { +impl ::std::fmt::Debug for StableHasher { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "{:?}", self.state) } } pub trait StableHasherResult: Sized { - fn finish(hasher: StableHasher) -> Self; + fn finish(hasher: StableHasher) -> Self; } -impl StableHasher { +impl StableHasher { pub fn new() -> Self { StableHasher { state: SipHasher128::new_with_keys(0, 0), - width: PhantomData, } } - pub fn finish(self) -> W { + pub fn finish(self) -> W { W::finish(self) } } impl StableHasherResult for u128 { - fn finish(hasher: StableHasher) -> Self { + fn finish(hasher: StableHasher) -> Self { let (_0, _1) = hasher.finalize(); u128::from(_0) | (u128::from(_1) << 64) } } impl StableHasherResult for u64 { - fn finish(hasher: StableHasher) -> Self { + fn finish(hasher: StableHasher) -> Self { hasher.finalize().0 } } -impl StableHasher { +impl StableHasher { #[inline] pub fn finalize(self) -> (u64, u64) { self.state.finish128() } } -impl Hasher for StableHasher { +impl Hasher for StableHasher { fn finish(&self) -> u64 { panic!("use StableHasher::finalize instead"); } @@ -165,9 +162,7 @@ impl Hasher for StableHasher { /// `StableHasher` takes care of endianness and `isize`/`usize` platform /// differences. pub trait HashStable { - fn hash_stable(&self, - hcx: &mut CTX, - hasher: &mut StableHasher); + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher); } /// Implement this for types that can be turned into stable keys like, for @@ -185,10 +180,10 @@ macro_rules! impl_stable_hash_via_hash { ($t:ty) => ( impl $crate::stable_hasher::HashStable for $t { #[inline] - fn hash_stable( + fn hash_stable( &self, _: &mut CTX, - hasher: &mut $crate::stable_hasher::StableHasher + hasher: &mut $crate::stable_hasher::StableHasher ) { ::std::hash::Hash::hash(self, hasher); } @@ -215,17 +210,13 @@ impl_stable_hash_via_hash!(char); impl_stable_hash_via_hash!(()); impl HashStable for ::std::num::NonZeroU32 { - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { self.get().hash_stable(ctx, hasher) } } impl HashStable for f32 { - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { let val: u32 = unsafe { ::std::mem::transmute(*self) }; @@ -234,9 +225,7 @@ impl HashStable for f32 { } impl HashStable for f64 { - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { let val: u64 = unsafe { ::std::mem::transmute(*self) }; @@ -245,26 +234,20 @@ impl HashStable for f64 { } impl HashStable for ::std::cmp::Ordering { - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { (*self as i8).hash_stable(ctx, hasher); } } impl, CTX> HashStable for (T1,) { - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { let (ref _0,) = *self; _0.hash_stable(ctx, hasher); } } impl, T2: HashStable, CTX> HashStable for (T1, T2) { - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { let (ref _0, ref _1) = *self; _0.hash_stable(ctx, hasher); _1.hash_stable(ctx, hasher); @@ -276,9 +259,7 @@ impl HashStable for (T1, T2, T3) T2: HashStable, T3: HashStable, { - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { let (ref _0, ref _1, ref _2) = *self; _0.hash_stable(ctx, hasher); _1.hash_stable(ctx, hasher); @@ -292,9 +273,7 @@ impl HashStable for (T1, T2, T3, T4) T3: HashStable, T4: HashStable, { - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { let (ref _0, ref _1, ref _2, ref _3) = *self; _0.hash_stable(ctx, hasher); _1.hash_stable(ctx, hasher); @@ -304,9 +283,7 @@ impl HashStable for (T1, T2, T3, T4) } impl, CTX> HashStable for [T] { - default fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + default fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { self.len().hash_stable(ctx, hasher); for item in self { item.hash_stable(ctx, hasher); @@ -316,9 +293,7 @@ impl, CTX> HashStable for [T] { impl, CTX> HashStable for Vec { #[inline] - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { (&self[..]).hash_stable(ctx, hasher); } } @@ -329,9 +304,7 @@ impl HashStable for indexmap::IndexMap R: BuildHasher, { #[inline] - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { self.len().hash_stable(ctx, hasher); for kv in self { kv.hash_stable(ctx, hasher); @@ -344,9 +317,7 @@ impl HashStable for indexmap::IndexSet R: BuildHasher, { #[inline] - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { self.len().hash_stable(ctx, hasher); for key in self { key.hash_stable(ctx, hasher); @@ -356,45 +327,35 @@ impl HashStable for indexmap::IndexSet impl HashStable for SmallVec<[A; 1]> where A: HashStable { #[inline] - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { (&self[..]).hash_stable(ctx, hasher); } } impl, CTX> HashStable for Box { #[inline] - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { (**self).hash_stable(ctx, hasher); } } impl, CTX> HashStable for ::std::rc::Rc { #[inline] - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { (**self).hash_stable(ctx, hasher); } } impl, CTX> HashStable for ::std::sync::Arc { #[inline] - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { (**self).hash_stable(ctx, hasher); } } impl HashStable for str { #[inline] - fn hash_stable(&self, - _: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) { self.len().hash(hasher); self.as_bytes().hash(hasher); } @@ -403,9 +364,7 @@ impl HashStable for str { impl HashStable for String { #[inline] - fn hash_stable(&self, - hcx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { (&self[..]).hash_stable(hcx, hasher); } } @@ -420,9 +379,7 @@ impl ToStableHashKey for String { impl HashStable for bool { #[inline] - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { (if *self { 1u8 } else { 0u8 }).hash_stable(ctx, hasher); } } @@ -432,9 +389,7 @@ impl HashStable for Option where T: HashStable { #[inline] - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { if let Some(ref value) = *self { 1u8.hash_stable(ctx, hasher); value.hash_stable(ctx, hasher); @@ -449,9 +404,7 @@ impl HashStable for Result T2: HashStable, { #[inline] - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(ctx, hasher); match *self { Ok(ref x) => x.hash_stable(ctx, hasher), @@ -464,28 +417,22 @@ impl<'a, T, CTX> HashStable for &'a T where T: HashStable + ?Sized { #[inline] - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { (**self).hash_stable(ctx, hasher); } } impl HashStable for ::std::mem::Discriminant { #[inline] - fn hash_stable(&self, - _: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) { ::std::hash::Hash::hash(self, hasher); } } -impl HashStable for indexed_vec::IndexVec +impl HashStable for vec::IndexVec where T: HashStable, { - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { self.len().hash_stable(ctx, hasher); for v in &self.raw { v.hash_stable(ctx, hasher); @@ -494,21 +441,17 @@ impl HashStable for indexed_vec::IndexVec HashStable for bit_set::BitSet +impl HashStable for bit_set::BitSet { - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { self.words().hash_stable(ctx, hasher); } } -impl HashStable +impl HashStable for bit_set::BitMatrix { - fn hash_stable(&self, - ctx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { self.words().hash_stable(ctx, hasher); } } @@ -522,9 +465,7 @@ impl HashStable for ::std::collections::HashMap R: BuildHasher, { #[inline] - fn hash_stable(&self, - hcx: &mut HCX, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { hash_stable_hashmap(hcx, hasher, self, ToStableHashKey::to_stable_hash_key); } } @@ -533,9 +474,7 @@ impl HashStable for ::std::collections::HashSet where K: ToStableHashKey + Eq + Hash, R: BuildHasher, { - fn hash_stable(&self, - hcx: &mut HCX, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { let mut keys: Vec<_> = self.iter() .map(|k| k.to_stable_hash_key(hcx)) .collect(); @@ -548,9 +487,7 @@ impl HashStable for ::std::collections::BTreeMap where K: ToStableHashKey, V: HashStable, { - fn hash_stable(&self, - hcx: &mut HCX, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { let mut entries: Vec<_> = self.iter() .map(|(k, v)| (k.to_stable_hash_key(hcx), v)) .collect(); @@ -562,9 +499,7 @@ impl HashStable for ::std::collections::BTreeMap impl HashStable for ::std::collections::BTreeSet where K: ToStableHashKey, { - fn hash_stable(&self, - hcx: &mut HCX, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { let mut keys: Vec<_> = self.iter() .map(|k| k.to_stable_hash_key(hcx)) .collect(); @@ -573,9 +508,9 @@ impl HashStable for ::std::collections::BTreeSet } } -pub fn hash_stable_hashmap( +pub fn hash_stable_hashmap( hcx: &mut HCX, - hasher: &mut StableHasher, + hasher: &mut StableHasher, map: &::std::collections::HashMap, to_stable_hash_key: F) where K: Eq + Hash, @@ -583,7 +518,6 @@ pub fn hash_stable_hashmap( R: BuildHasher, SK: HashStable + Ord + Clone, F: Fn(&K, &HCX) -> SK, - W: StableHasherResult, { let mut entries: Vec<_> = map.iter() .map(|(k, v)| (to_stable_hash_key(k, hcx), v)) @@ -614,9 +548,7 @@ impl ::std::ops::Deref for StableVec { impl HashStable for StableVec where T: HashStable + ToStableHashKey { - fn hash_stable(&self, - hcx: &mut HCX, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { let StableVec(ref v) = *self; let mut sorted: Vec<_> = v.iter() diff --git a/src/librustc_data_structures/stable_map.rs b/src/librustc_data_structures/stable_map.rs new file mode 100644 index 0000000000000..f69f28e14b2a1 --- /dev/null +++ b/src/librustc_data_structures/stable_map.rs @@ -0,0 +1,99 @@ +pub use rustc_hash::FxHashMap; +use std::borrow::Borrow; +use std::collections::hash_map::Entry; +use std::fmt; +use std::hash::Hash; + +/// A deterministic wrapper around FxHashMap that does not provide iteration support. +/// +/// It supports insert, remove, get and get_mut functions from FxHashMap. +/// It also allows to convert hashmap to a sorted vector with the method `into_sorted_vector()`. +#[derive(Clone)] +pub struct StableMap { + base: FxHashMap, +} + +impl Default for StableMap +where + K: Eq + Hash, +{ + fn default() -> StableMap { + StableMap::new() + } +} + +impl fmt::Debug for StableMap +where + K: Eq + Hash + fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.base) + } +} + +impl PartialEq for StableMap +where + K: Eq + Hash, + V: PartialEq, +{ + fn eq(&self, other: &StableMap) -> bool { + self.base == other.base + } +} + +impl Eq for StableMap +where + K: Eq + Hash, + V: Eq, +{} + +impl StableMap +where + K: Eq + Hash, +{ + pub fn new() -> StableMap { + StableMap { base: FxHashMap::default() } + } + + pub fn into_sorted_vector(self) -> Vec<(K, V)> + where + K: Ord + Copy, + { + let mut vector = self.base.into_iter().collect::>(); + vector.sort_unstable_by_key(|pair| pair.0); + vector + } + + pub fn entry(&mut self, k: K) -> Entry<'_, K, V> { + self.base.entry(k) + } + + pub fn get(&self, k: &Q) -> Option<&V> + where + K: Borrow, + Q: Hash + Eq, + { + self.base.get(k) + } + + pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> + where + K: Borrow, + Q: Hash + Eq, + { + self.base.get_mut(k) + } + + pub fn insert(&mut self, k: K, v: V) -> Option { + self.base.insert(k, v) + } + + pub fn remove(&mut self, k: &Q) -> Option + where + K: Borrow, + Q: Hash + Eq, + { + self.base.remove(k) + } +} diff --git a/src/librustc_data_structures/stable_set.rs b/src/librustc_data_structures/stable_set.rs new file mode 100644 index 0000000000000..c7ca74f5fbd9d --- /dev/null +++ b/src/librustc_data_structures/stable_set.rs @@ -0,0 +1,77 @@ +pub use rustc_hash::FxHashSet; +use std::borrow::Borrow; +use std::fmt; +use std::hash::Hash; + +/// A deterministic wrapper around FxHashSet that does not provide iteration support. +/// +/// It supports insert, remove, get functions from FxHashSet. +/// It also allows to convert hashset to a sorted vector with the method `into_sorted_vector()`. +#[derive(Clone)] +pub struct StableSet { + base: FxHashSet, +} + +impl Default for StableSet +where + T: Eq + Hash, +{ + fn default() -> StableSet { + StableSet::new() + } +} + +impl fmt::Debug for StableSet +where + T: Eq + Hash + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.base) + } +} + +impl PartialEq> for StableSet +where + T: Eq + Hash, +{ + fn eq(&self, other: &StableSet) -> bool { + self.base == other.base + } +} + +impl Eq for StableSet where T: Eq + Hash {} + +impl StableSet { + pub fn new() -> StableSet { + StableSet { base: FxHashSet::default() } + } + + pub fn into_sorted_vector(self) -> Vec + where + T: Ord, + { + let mut vector = self.base.into_iter().collect::>(); + vector.sort_unstable(); + vector + } + + pub fn get(&self, value: &Q) -> Option<&T> + where + T: Borrow, + Q: Hash + Eq, + { + self.base.get(value) + } + + pub fn insert(&mut self, value: T) -> bool { + self.base.insert(value) + } + + pub fn remove(&mut self, value: &Q) -> bool + where + T: Borrow, + Q: Hash + Eq, + { + self.base.remove(value) + } +} diff --git a/src/librustc_data_structures/svh.rs b/src/librustc_data_structures/svh.rs index 3123c182b0f4c..64042264d794f 100644 --- a/src/librustc_data_structures/svh.rs +++ b/src/librustc_data_structures/svh.rs @@ -61,11 +61,7 @@ impl Decodable for Svh { impl stable_hasher::HashStable for Svh { #[inline] - fn hash_stable( - &self, - ctx: &mut T, - hasher: &mut stable_hasher::StableHasher - ) { + fn hash_stable(&self, ctx: &mut T, hasher: &mut stable_hasher::StableHasher) { let Svh { hash } = *self; diff --git a/src/librustc_data_structures/thin_vec.rs b/src/librustc_data_structures/thin_vec.rs index 6692903cd4fe9..93a8b7f525fff 100644 --- a/src/librustc_data_structures/thin_vec.rs +++ b/src/librustc_data_structures/thin_vec.rs @@ -1,4 +1,4 @@ -use crate::stable_hasher::{StableHasher, StableHasherResult, HashStable}; +use crate::stable_hasher::{StableHasher, HashStable}; /// A vector type optimized for cases where this size is usually 0 (cf. `SmallVector`). /// The `Option>` wrapping allows us to represent a zero sized vector with `None`, @@ -60,9 +60,7 @@ impl Extend for ThinVec { } impl, CTX> HashStable for ThinVec { - fn hash_stable(&self, - hcx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { (**self).hash_stable(hcx, hasher) } } diff --git a/src/librustc_data_structures/tiny_list.rs b/src/librustc_data_structures/tiny_list.rs index 1c0d9360f2511..ea771d9f20f8b 100644 --- a/src/librustc_data_structures/tiny_list.rs +++ b/src/librustc_data_structures/tiny_list.rs @@ -20,7 +20,6 @@ pub struct TinyList { } impl TinyList { - #[inline] pub fn new() -> TinyList { TinyList { @@ -60,20 +59,24 @@ impl TinyList { #[inline] pub fn contains(&self, data: &T) -> bool { - if let Some(ref head) = self.head { - head.contains(data) - } else { - false + let mut elem = self.head.as_ref(); + while let Some(ref e) = elem { + if &e.data == data { + return true; + } + elem = e.next.as_ref().map(|e| &**e); } + false } #[inline] pub fn len(&self) -> usize { - if let Some(ref head) = self.head { - head.len() - } else { - 0 + let (mut elem, mut count) = (self.head.as_ref(), 0); + while let Some(ref e) = elem { + count += 1; + elem = e.next.as_ref().map(|e| &**e); } + count } } @@ -84,40 +87,13 @@ struct Element { } impl Element { - fn remove_next(&mut self, data: &T) -> bool { - let new_next = if let Some(ref mut next) = self.next { - if next.data != *data { - return next.remove_next(data) - } else { - next.next.take() - } - } else { - return false + let new_next = match self.next { + Some(ref mut next) if next.data == *data => next.next.take(), + Some(ref mut next) => return next.remove_next(data), + None => return false, }; - self.next = new_next; - true } - - fn len(&self) -> usize { - if let Some(ref next) = self.next { - 1 + next.len() - } else { - 1 - } - } - - fn contains(&self, data: &T) -> bool { - if self.data == *data { - return true - } - - if let Some(ref next) = self.next { - next.contains(data) - } else { - false - } - } } diff --git a/src/librustc_data_structures/tiny_list/tests.rs b/src/librustc_data_structures/tiny_list/tests.rs index 8374659e1e67b..0142631590cc9 100644 --- a/src/librustc_data_structures/tiny_list/tests.rs +++ b/src/librustc_data_structures/tiny_list/tests.rs @@ -1,7 +1,7 @@ use super::*; extern crate test; -use test::Bencher; +use test::{Bencher, black_box}; #[test] fn test_contains_and_insert() { @@ -98,36 +98,59 @@ fn test_remove_single() { #[bench] fn bench_insert_empty(b: &mut Bencher) { b.iter(|| { - let mut list = TinyList::new(); + let mut list = black_box(TinyList::new()); list.insert(1); + list }) } #[bench] fn bench_insert_one(b: &mut Bencher) { b.iter(|| { - let mut list = TinyList::new_single(0); + let mut list = black_box(TinyList::new_single(0)); list.insert(1); + list }) } +#[bench] +fn bench_contains_empty(b: &mut Bencher) { + b.iter(|| { + black_box(TinyList::new()).contains(&1) + }); +} + +#[bench] +fn bench_contains_unknown(b: &mut Bencher) { + b.iter(|| { + black_box(TinyList::new_single(0)).contains(&1) + }); +} + +#[bench] +fn bench_contains_one(b: &mut Bencher) { + b.iter(|| { + black_box(TinyList::new_single(1)).contains(&1) + }); +} + #[bench] fn bench_remove_empty(b: &mut Bencher) { b.iter(|| { - TinyList::new().remove(&1) + black_box(TinyList::new()).remove(&1) }); } #[bench] fn bench_remove_unknown(b: &mut Bencher) { b.iter(|| { - TinyList::new_single(0).remove(&1) + black_box(TinyList::new_single(0)).remove(&1) }); } #[bench] fn bench_remove_one(b: &mut Bencher) { b.iter(|| { - TinyList::new_single(1).remove(&1) + black_box(TinyList::new_single(1)).remove(&1) }); } diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index ffc964ddb5ae2..f0a9c3afc68b0 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -1,6 +1,6 @@ -use crate::bit_set::BitMatrix; +use rustc_index::bit_set::BitMatrix; use crate::fx::FxHashMap; -use crate::stable_hasher::{HashStable, StableHasher, StableHasherResult}; +use crate::stable_hasher::{HashStable, StableHasher}; use crate::sync::Lock; use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; use std::fmt::Debug; @@ -442,9 +442,7 @@ impl Decodable for TransitiveRelation impl HashStable for TransitiveRelation where T: HashStable + Eq + Debug + Clone + Hash { - fn hash_stable(&self, - hcx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { // We are assuming here that the relation graph has been built in a // deterministic way and we can just hash it the way it is. let TransitiveRelation { @@ -462,9 +460,7 @@ impl HashStable for TransitiveRelation } impl HashStable for Edge { - fn hash_stable(&self, - hcx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { let Edge { ref source, ref target, @@ -476,9 +472,7 @@ impl HashStable for Edge { } impl HashStable for Index { - fn hash_stable(&self, - hcx: &mut CTX, - hasher: &mut StableHasher) { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { let Index(idx) = *self; idx.hash_stable(hcx, hasher); } diff --git a/src/librustc_data_structures/vec_linked_list.rs b/src/librustc_data_structures/vec_linked_list.rs index 0fb8060031843..7744c30655dce 100644 --- a/src/librustc_data_structures/vec_linked_list.rs +++ b/src/librustc_data_structures/vec_linked_list.rs @@ -1,4 +1,4 @@ -use crate::indexed_vec::{Idx, IndexVec}; +use rustc_index::vec::{Idx, IndexVec}; pub fn iter( first: Option, diff --git a/src/librustc_data_structures/work_queue.rs b/src/librustc_data_structures/work_queue.rs index 193025aafad20..af63b18e9e922 100644 --- a/src/librustc_data_structures/work_queue.rs +++ b/src/librustc_data_structures/work_queue.rs @@ -1,5 +1,5 @@ -use crate::bit_set::BitSet; -use crate::indexed_vec::Idx; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::Idx; use std::collections::VecDeque; /// A work queue is a handy data structure for tracking work left to diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index 42aa8203cba0e..aa74966d0ab4c 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -11,15 +11,17 @@ crate-type = ["dylib"] [dependencies] graphviz = { path = "../libgraphviz" } +lazy_static = "1.0" log = "0.4" -env_logger = { version = "0.5", default-features = false } +env_logger = { version = "0.7", default-features = false } rustc = { path = "../librustc" } rustc_target = { path = "../librustc_target" } -rustc_ast_borrowck = { path = "../librustc_ast_borrowck" } rustc_data_structures = { path = "../librustc_data_structures" } errors = { path = "../librustc_errors", package = "rustc_errors" } rustc_metadata = { path = "../librustc_metadata" } rustc_mir = { path = "../librustc_mir" } +rustc_plugin = { path = "../librustc_plugin/deprecated" } # To get this in the sysroot +rustc_plugin_impl = { path = "../librustc_plugin" } rustc_save_analysis = { path = "../librustc_save_analysis" } rustc_codegen_utils = { path = "../librustc_codegen_utils" } rustc_interface = { path = "../librustc_interface" } diff --git a/src/librustc_driver/args.rs b/src/librustc_driver/args.rs new file mode 100644 index 0000000000000..0906d358badd4 --- /dev/null +++ b/src/librustc_driver/args.rs @@ -0,0 +1,53 @@ +use std::error; +use std::fmt; +use std::fs; +use std::io; +use std::str; +use std::sync::atomic::{AtomicBool, Ordering}; + +static USED_ARGSFILE_FEATURE: AtomicBool = AtomicBool::new(false); + +pub fn used_unstable_argsfile() -> bool { + USED_ARGSFILE_FEATURE.load(Ordering::Relaxed) +} + +pub fn arg_expand(arg: String) -> Result, Error> { + if arg.starts_with("@") { + let path = &arg[1..]; + let file = match fs::read_to_string(path) { + Ok(file) => { + USED_ARGSFILE_FEATURE.store(true, Ordering::Relaxed); + file + } + Err(ref err) if err.kind() == io::ErrorKind::InvalidData => { + return Err(Error::Utf8Error(Some(path.to_string()))); + } + Err(err) => return Err(Error::IOError(path.to_string(), err)), + }; + Ok(file.lines().map(ToString::to_string).collect()) + } else { + Ok(vec![arg]) + } +} + +#[derive(Debug)] +pub enum Error { + Utf8Error(Option), + IOError(String, io::Error), +} + +impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::Utf8Error(None) => write!(fmt, "Utf8 error"), + Error::Utf8Error(Some(path)) => write!(fmt, "Utf8 error in {}", path), + Error::IOError(path, err) => write!(fmt, "IO Error: {}: {}", path, err), + } + } +} + +impl error::Error for Error { + fn description(&self) -> &'static str { + "argument error" + } +} diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 77b7ef96d3f6c..dd088b68a239a 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -9,7 +9,6 @@ #![feature(box_syntax)] #![cfg_attr(unix, feature(libc))] #![feature(nll)] -#![feature(rustc_diagnostic_macros)] #![feature(set_stdio)] #![feature(no_debug)] #![feature(integer_atomics)] @@ -21,6 +20,10 @@ pub extern crate getopts; extern crate libc; #[macro_use] extern crate log; +#[macro_use] +extern crate lazy_static; + +pub extern crate rustc_plugin_impl as plugin; use pretty::{PpMode, UserIdentifiedItem}; @@ -34,8 +37,8 @@ use rustc::session::{early_error, early_warn}; use rustc::lint::Lint; use rustc::lint; use rustc::hir::def_id::LOCAL_CRATE; -use rustc::util::common::{ErrorReported, install_panic_hook, print_time_passes_entry}; -use rustc::util::common::{set_time_depth, time}; +use rustc::ty::TyCtxt; +use rustc::util::common::{set_time_depth, time, print_time_passes_entry, ErrorReported}; use rustc_metadata::locator; use rustc_metadata::cstore::CStore; use rustc_codegen_utils::codegen_backend::CodegenBackend; @@ -63,9 +66,10 @@ use syntax::source_map::FileLoader; use syntax::feature_gate::{GatedCfg, UnstableFeatures}; use syntax::parse::{self, PResult}; use syntax::symbol::sym; -use syntax_pos::{DUMMY_SP, MultiSpan, FileName}; +use syntax_pos::{DUMMY_SP, FileName}; pub mod pretty; +mod args; /// Exit status code used for successful compilation and help output. pub const EXIT_SUCCESS: i32 = 0; @@ -130,8 +134,11 @@ pub struct TimePassesCallbacks { impl Callbacks for TimePassesCallbacks { fn config(&mut self, config: &mut interface::Config) { + // If a --prints=... option has been given, we don't print the "total" + // time because it will mess up the --prints output. See #64339. self.time_passes = - config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time; + config.opts.prints.is_empty() && + (config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time); } } @@ -139,20 +146,26 @@ impl Callbacks for TimePassesCallbacks { // 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( - args: &[String], + at_args: &[String], callbacks: &mut (dyn Callbacks + Send), file_loader: Option>, emitter: Option> ) -> interface::Result<()> { + let mut args = Vec::new(); + for arg in at_args { + match args::arg_expand(arg.clone()) { + Ok(arg) => args.extend(arg), + Err(err) => early_error(ErrorOutputType::default(), + &format!("Failed to load argument file: {}", err)), + } + } let diagnostic_output = emitter.map(|emitter| DiagnosticOutput::Raw(emitter)) .unwrap_or(DiagnosticOutput::Default); - let matches = match handle_options(args) { + let matches = match handle_options(&args) { Some(matches) => matches, None => return Ok(()), }; - install_panic_hook(); - let (sopts, cfg) = config::build_session_options_and_crate_config(&matches); let mut dummy_config = |sopts, cfg, diagnostic_output| { @@ -283,7 +296,6 @@ pub fn run_compiler( ); Ok(()) })?; - return sess.compile_status(); } else { let mut krate = compiler.parse()?.take(); pretty::visit_crate(sess, &mut krate, ppm); @@ -294,8 +306,8 @@ pub fn run_compiler( ppm, compiler.output_file().as_ref().map(|p| &**p), ); - return sess.compile_status(); } + return sess.compile_status(); } if callbacks.after_parsing(compiler) == Compilation::Stop { @@ -428,6 +440,15 @@ fn make_input(free_matches: &[String]) -> Option<(Input, Option, Option } else { None }; + if let Ok(path) = env::var("UNSTABLE_RUSTDOC_TEST_PATH") { + let line = env::var("UNSTABLE_RUSTDOC_TEST_LINE"). + expect("when UNSTABLE_RUSTDOC_TEST_PATH is set \ + UNSTABLE_RUSTDOC_TEST_LINE also needs to be set"); + let line = isize::from_str_radix(&line, 10). + expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number"); + let file_name = FileName::doc_test_source_code(PathBuf::from(path), line); + return Some((Input::Str { name: file_name, input: src }, None, err)); + } Some((Input::Str { name: FileName::anon_source_code(&src), input: src }, None, err)) } else { @@ -678,8 +699,8 @@ impl RustcDefaultCalls { let mut cfgs = sess.parse_sess.config.iter().filter_map(|&(name, ref value)| { let gated_cfg = GatedCfg::gate(&ast::MetaItem { - path: ast::Path::from_ident(ast::Ident::with_empty_ctxt(name)), - node: ast::MetaItemKind::Word, + path: ast::Path::from_ident(ast::Ident::with_dummy_span(name)), + kind: ast::MetaItemKind::Word, span: DUMMY_SP, }); @@ -777,13 +798,19 @@ fn usage(verbose: bool, include_unstable_options: bool) { } else { "\n --help -v Print the full set of options rustc accepts" }; - println!("{}\nAdditional help: + let at_path = if verbose && nightly_options::is_nightly_build() { + " @path Read newline separated options from `path`\n" + } else { + "" + }; + println!("{options}{at_path}\nAdditional help: -C help Print codegen options -W help \ - Print 'lint' options and default settings{}{}\n", - options.usage(message), - nightly_help, - verbose_help); + Print 'lint' options and default settings{nightly}{verbose}\n", + options = options.usage(message), + at_path = at_path, + nightly = nightly_help, + verbose = verbose_help); } fn print_wall_help() { @@ -957,14 +984,11 @@ fn print_flag_list(cmdline_opt: &str, /// otherwise returns `None`. /// /// The compiler's handling of options is a little complicated as it ties into -/// our stability story, and it's even *more* complicated by historical -/// accidents. The current intention of each compiler option is to have one of -/// three modes: +/// our stability story. The current intention of each compiler option is to +/// have one of two modes: /// /// 1. An option is stable and can be used everywhere. -/// 2. An option is unstable, but was historically allowed on the stable -/// channel. -/// 3. An option is unstable, and can only be used on nightly. +/// 2. An option is unstable, and can only be used on nightly. /// /// Like unstable library and language features, however, unstable options have /// always required a form of "opt in" to indicate that you're using them. This @@ -1007,19 +1031,19 @@ pub fn handle_options(args: &[String]) -> Option { // this option that was passed. // * If we're a nightly compiler, then unstable options are now unlocked, so // we're good to go. - // * Otherwise, if we're a truly unstable option then we generate an error + // * Otherwise, if we're an unstable option then we generate an error // (unstable option being used on stable) - // * If we're a historically stable-but-should-be-unstable option then we - // emit a warning that we're going to turn this into an error soon. nightly_options::check_nightly_options(&matches, &config::rustc_optgroups()); + // Late check to see if @file was used without unstable options enabled + if crate::args::used_unstable_argsfile() && !nightly_options::is_unstable_enabled(&matches) { + early_error(ErrorOutputType::default(), + "@path is unstable - use -Z unstable-options to enable its use"); + } + if matches.opt_present("h") || matches.opt_present("help") { - // Only show unstable options in --help if we *really* accept unstable - // options, which catches the case where we got `-Z unstable-options` on - // the stable channel of Rust which was accidentally allowed - // historically. - usage(matches.opt_present("verbose"), - nightly_options::is_unstable_enabled(&matches)); + // Only show unstable options in --help if we accept unstable options. + usage(matches.opt_present("verbose"), nightly_options::is_unstable_enabled(&matches)); return None; } @@ -1129,59 +1153,104 @@ fn extra_compiler_flags() -> Option<(Vec, bool)> { } } -/// Runs a procedure which will detect panics in the compiler and print nicer -/// error messages rather than just failing the test. +/// Runs a closure and catches unwinds triggered by fatal errors. /// -/// The diagnostic emitter yielded to the procedure should be used for reporting -/// errors of the compiler. -pub fn report_ices_to_stderr_if_any R, R>(f: F) -> Result { +/// The compiler currently unwinds with a special sentinel value to abort +/// compilation on fatal errors. This function catches that sentinel and turns +/// the panic into a `Result` instead. +pub fn catch_fatal_errors R, R>(f: F) -> Result { catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| { if value.is::() { ErrorReported } else { - // Thread panicked without emitting a fatal diagnostic - eprintln!(""); - - let emitter = - Box::new(errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto, - None, - false, - false)); - let handler = errors::Handler::with_emitter(true, None, emitter); - - // a .span_bug or .bug call has already printed what - // it wants to print. - if !value.is::() { - handler.emit(&MultiSpan::new(), - "unexpected panic", - errors::Level::Bug); - } + panic::resume_unwind(value); + } + }) +} - let mut xs: Vec> = vec![ - "the compiler unexpectedly panicked. this is a bug.".into(), - format!("we would appreciate a bug report: {}", BUG_REPORT_URL).into(), - format!("rustc {} running on {}", - option_env!("CFG_VERSION").unwrap_or("unknown_version"), - config::host_triple()).into(), - ]; +lazy_static! { + static ref DEFAULT_HOOK: Box) + Sync + Send + 'static> = { + let hook = panic::take_hook(); + panic::set_hook(Box::new(|info| report_ice(info, BUG_REPORT_URL))); + hook + }; +} - if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() { - xs.push(format!("compiler flags: {}", flags.join(" ")).into()); +/// Prints the ICE message, including backtrace and query stack. +/// +/// The message will point the user at `bug_report_url` to report the ICE. +/// +/// When `install_ice_hook` is called, this function will be called as the panic +/// hook. +pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { + // Invoke the default handler, which prints the actual panic message and optionally a backtrace + (*DEFAULT_HOOK)(info); + + // Separate the output with an empty line + eprintln!(); + + let emitter = Box::new(errors::emitter::EmitterWriter::stderr( + errors::ColorConfig::Auto, + None, + false, + false, + None, + false, + )); + let handler = errors::Handler::with_emitter(true, None, emitter); + + // a .span_bug or .bug call has already printed what + // it wants to print. + if !info.payload().is::() { + let d = errors::Diagnostic::new(errors::Level::Bug, "unexpected panic"); + handler.emit_diagnostic(&d); + handler.abort_if_errors_and_should_abort(); + } - if excluded_cargo_defaults { - xs.push("some of the compiler flags provided by cargo are hidden".into()); - } - } + let mut xs: Vec> = vec![ + "the compiler unexpectedly panicked. this is a bug.".into(), + format!("we would appreciate a bug report: {}", bug_report_url).into(), + format!("rustc {} running on {}", + option_env!("CFG_VERSION").unwrap_or("unknown_version"), + config::host_triple()).into(), + ]; - for note in &xs { - handler.emit(&MultiSpan::new(), - note, - errors::Level::Note); - } + if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() { + xs.push(format!("compiler flags: {}", flags.join(" ")).into()); - panic::resume_unwind(Box::new(errors::FatalErrorMarker)); + if excluded_cargo_defaults { + xs.push("some of the compiler flags provided by cargo are hidden".into()); } - }) + } + + for note in &xs { + handler.note_without_error(¬e); + } + + // If backtraces are enabled, also print the query stack + let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false); + + if backtrace { + TyCtxt::try_print_query_stack(&handler); + } + + #[cfg(windows)] + unsafe { + if env::var("RUSTC_BREAK_ON_ICE").is_ok() { + extern "system" { + fn DebugBreak(); + } + // Trigger a debugger if we crashed during bootstrap + DebugBreak(); + } + } +} + +/// Installs a panic hook that will print the ICE message on unexpected panics. +/// +/// A custom rustc driver can skip calling this to set up a custom ICE hook. +pub fn install_ice_hook() { + lazy_static::initialize(&DEFAULT_HOOK); } /// This allows tools to enable rust logging without having to magically match rustc's @@ -1194,10 +1263,11 @@ pub fn main() { let start = Instant::now(); init_rustc_env_logger(); let mut callbacks = TimePassesCallbacks::default(); - let result = report_ices_to_stderr_if_any(|| { + install_ice_hook(); + let result = catch_fatal_errors(|| { let args = env::args_os().enumerate() .map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| { - early_error(ErrorOutputType::default(), + early_error(ErrorOutputType::default(), &format!("Argument {} is not valid Unicode: {:?}", i, arg)) })) .collect::>(); diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index cb17401f6247b..0de5b700b4faa 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -1,10 +1,7 @@ //! The various pretty-printing routines. -use rustc::cfg; -use rustc::cfg::graphviz::LabelledCFG; use rustc::hir; use rustc::hir::map as hir_map; -use rustc::hir::map::blocks; use rustc::hir::print as pprust_hir; use rustc::hir::def_id::LOCAL_CRATE; use rustc::session::Session; @@ -12,8 +9,6 @@ use rustc::session::config::Input; use rustc::ty::{self, TyCtxt}; use rustc::util::common::ErrorReported; use rustc_interface::util::ReplaceBodyWithLoop; -use rustc_ast_borrowck as borrowck; -use rustc_ast_borrowck::graphviz as borrowck_dot; use rustc_mir::util::{write_mir_pretty, write_mir_graphviz}; use syntax::ast; @@ -21,11 +16,9 @@ use syntax::mut_visit::MutVisitor; use syntax::print::{pprust}; use syntax_pos::FileName; -use graphviz as dot; - use std::cell::Cell; use std::fs::File; -use std::io::{self, Write}; +use std::io::Write; use std::option; use std::path::Path; use std::str::FromStr; @@ -49,21 +42,11 @@ pub enum PpSourceMode { PpmTyped, } -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum PpFlowGraphMode { - Default, - /// Drops the labels from the edges in the flowgraph output. This - /// is mostly for use in the -Z unpretty flowgraph run-make tests, - /// since the labels are largely uninteresting in those cases and - /// have become a pain to maintain. - UnlabelledEdges, -} #[derive(Copy, Clone, PartialEq, Debug)] pub enum PpMode { PpmSource(PpSourceMode), PpmHir(PpSourceMode), PpmHirTree(PpSourceMode), - PpmFlowGraph(PpFlowGraphMode), PpmMir, PpmMirCFG, } @@ -81,15 +64,14 @@ impl PpMode { PpmHir(_) | PpmHirTree(_) | PpmMir | - PpmMirCFG | - PpmFlowGraph(_) => true, + PpmMirCFG => true, PpmSource(PpmTyped) => panic!("invalid state"), } } pub fn needs_analysis(&self) -> bool { match *self { - PpmMir | PpmMirCFG | PpmFlowGraph(_) => true, + PpmMir | PpmMirCFG => true, _ => false, } } @@ -115,13 +97,11 @@ pub fn parse_pretty(sess: &Session, ("hir-tree", true) => PpmHirTree(PpmNormal), ("mir", true) => PpmMir, ("mir-cfg", true) => PpmMirCFG, - ("flowgraph", true) => PpmFlowGraph(PpFlowGraphMode::Default), - ("flowgraph,unlabelled", true) => PpmFlowGraph(PpFlowGraphMode::UnlabelledEdges), _ => { if extended { sess.fatal(&format!("argument to `unpretty` must be one of `normal`, \ - `expanded`, `flowgraph[,unlabelled]=`, \ - `identified`, `expanded,identified`, `everybody_loops`, \ + `expanded`, `identified`, `expanded,identified`, \ + `expanded,hygiene`, `everybody_loops`, \ `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \ `mir` or `mir-cfg`; got {}", name)); @@ -327,6 +307,7 @@ impl<'hir> pprust::PpAnn for IdentifiedAnnotation<'hir> { } fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) { match node { + pprust::AnnNode::Crate(_) | pprust::AnnNode::Ident(_) | pprust::AnnNode::Name(_) => {}, @@ -432,14 +413,18 @@ impl<'a> pprust::PpAnn for HygieneAnnotation<'a> { match node { pprust::AnnNode::Ident(&ast::Ident { name, span }) => { s.s.space(); - // FIXME #16420: this doesn't display the connections - // between syntax contexts s.synth_comment(format!("{}{:?}", name.as_u32(), span.ctxt())) } pprust::AnnNode::Name(&name) => { s.s.space(); s.synth_comment(name.as_u32().to_string()) } + pprust::AnnNode::Crate(_) => { + s.s.hardbreak(); + let verbose = self.sess.verbose(); + s.synth_comment(syntax_pos::hygiene::debug_hygiene_data(verbose)); + s.s.hardbreak_if_not_bol(); + } _ => {} } } @@ -497,24 +482,6 @@ impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> { } } -fn gather_flowgraph_variants(sess: &Session) -> Vec { - let print_loans = sess.opts.debugging_opts.flowgraph_print_loans; - let print_moves = sess.opts.debugging_opts.flowgraph_print_moves; - let print_assigns = sess.opts.debugging_opts.flowgraph_print_assigns; - let print_all = sess.opts.debugging_opts.flowgraph_print_all; - let mut variants = Vec::new(); - if print_all || print_loans { - variants.push(borrowck_dot::Loans); - } - if print_all || print_moves { - variants.push(borrowck_dot::Moves); - } - if print_all || print_assigns { - variants.push(borrowck_dot::Assigns); - } - variants -} - #[derive(Clone, Debug)] pub enum UserIdentifiedItem { ItemViaNode(ast::NodeId), @@ -605,81 +572,6 @@ impl UserIdentifiedItem { } } -fn print_flowgraph<'tcx, W: Write>( - variants: Vec, - tcx: TyCtxt<'tcx>, - code: blocks::Code<'tcx>, - mode: PpFlowGraphMode, - mut out: W, -) -> io::Result<()> { - let body_id = match code { - blocks::Code::Expr(expr) => { - // Find the function this expression is from. - let mut hir_id = expr.hir_id; - loop { - let node = tcx.hir().get(hir_id); - if let Some(n) = hir::map::blocks::FnLikeNode::from_node(node) { - break n.body(); - } - let parent = tcx.hir().get_parent_node(hir_id); - assert_ne!(hir_id, parent); - hir_id = parent; - } - } - blocks::Code::FnLike(fn_like) => fn_like.body(), - }; - let body = tcx.hir().body(body_id); - let cfg = cfg::CFG::new(tcx, &body); - let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges; - let hir_id = code.id(); - // We have to disassemble the hir_id because name must be ASCII - // alphanumeric. This does not appear in the rendered graph, so it does not - // have to be user friendly. - let name = format!( - "hir_id_{}_{}", - hir_id.owner.index(), - hir_id.local_id.index(), - ); - let lcfg = LabelledCFG { - tcx, - cfg: &cfg, - name, - labelled_edges, - }; - - match code { - _ if variants.is_empty() => { - let r = dot::render(&lcfg, &mut out); - return expand_err_details(r); - } - blocks::Code::Expr(_) => { - tcx.sess.err("--pretty flowgraph with -Z flowgraph-print annotations requires \ - fn-like node id."); - return Ok(()); - } - blocks::Code::FnLike(fn_like) => { - let (bccx, analysis_data) = - borrowck::build_borrowck_dataflow_data_for_fn(tcx, fn_like.body(), &cfg); - - let lcfg = borrowck_dot::DataflowLabeller { - inner: lcfg, - variants, - borrowck_ctxt: &bccx, - analysis_data: &analysis_data, - }; - let r = dot::render(&lcfg, &mut out); - return expand_err_details(r); - } - } - - fn expand_err_details(r: io::Result<()>) -> io::Result<()> { - r.map_err(|ioerr| { - io::Error::new(io::ErrorKind::Other, - format!("graphviz::render failed: {}", ioerr)) - }) - } -} - pub fn visit_crate(sess: &Session, krate: &mut ast::Crate, ppm: PpMode) { if let PpmSource(PpmEveryBodyLoops) = ppm { ReplaceBodyWithLoop::new(sess).visit_crate(krate); @@ -868,55 +760,17 @@ fn print_with_analysis( tcx.analysis(LOCAL_CRATE)?; - let mut print = || match ppm { + match ppm { PpmMir | PpmMirCFG => { - if let Some(nodeid) = nodeid { - let def_id = tcx.hir().local_def_id_from_node_id(nodeid); - match ppm { - PpmMir => write_mir_pretty(tcx, Some(def_id), &mut out), - PpmMirCFG => write_mir_graphviz(tcx, Some(def_id), &mut out), - _ => unreachable!(), - }?; - } else { - match ppm { - PpmMir => write_mir_pretty(tcx, None, &mut out), - PpmMirCFG => write_mir_graphviz(tcx, None, &mut out), - _ => unreachable!(), - }?; - } - Ok(()) - } - PpmFlowGraph(mode) => { - let nodeid = - nodeid.expect("`pretty flowgraph=..` needs NodeId (int) or unique path \ - suffix (b::c::d)"); - let hir_id = tcx.hir().node_to_hir_id(nodeid); - let node = tcx.hir().find(hir_id).unwrap_or_else(|| { - tcx.sess.fatal(&format!("`--pretty=flowgraph` couldn't find ID: {}", nodeid)) - }); - - match blocks::Code::from_node(&tcx.hir(), hir_id) { - Some(code) => { - let variants = gather_flowgraph_variants(tcx.sess); - - let out: &mut dyn Write = &mut out; - - print_flowgraph(variants, tcx, code, mode, out) - } - None => { - let message = format!("`--pretty=flowgraph` needs block, fn, or method; \ - got {:?}", - node); - - let hir_id = tcx.hir().node_to_hir_id(nodeid); - tcx.sess.span_fatal(tcx.hir().span(hir_id), &message) - } + let def_id = nodeid.map(|nid| tcx.hir().local_def_id_from_node_id(nid)); + match ppm { + PpmMir => write_mir_pretty(tcx, def_id, &mut out), + PpmMirCFG => write_mir_graphviz(tcx, def_id, &mut out), + _ => unreachable!(), } } _ => unreachable!(), - }; - - print().unwrap(); + }.unwrap(); write_output(out, ofile); diff --git a/src/librustc_errors/Cargo.toml b/src/librustc_errors/Cargo.toml index 32f121f18f689..1541845bb55f6 100644 --- a/src/librustc_errors/Cargo.toml +++ b/src/librustc_errors/Cargo.toml @@ -18,3 +18,4 @@ unicode-width = "0.1.4" atty = "0.2" termcolor = "1.0" annotate-snippets = "0.6.1" +term_size = "0.3.1" diff --git a/src/librustc_errors/annotate_snippet_emitter_writer.rs b/src/librustc_errors/annotate_snippet_emitter_writer.rs index 96a9b6c5c4f7f..0281d10fd930e 100644 --- a/src/librustc_errors/annotate_snippet_emitter_writer.rs +++ b/src/librustc_errors/annotate_snippet_emitter_writer.rs @@ -7,7 +7,7 @@ use syntax_pos::{SourceFile, MultiSpan, Loc}; use crate::{ - Level, CodeSuggestion, DiagnosticBuilder, Emitter, + Level, CodeSuggestion, Diagnostic, Emitter, SourceMapperDyn, SubDiagnostic, DiagnosticId }; use crate::emitter::FileWithAnnotatedLines; @@ -25,17 +25,21 @@ pub struct AnnotateSnippetEmitterWriter { short_message: bool, /// If true, will normalize line numbers with `LL` to prevent noise in UI test diffs. ui_testing: bool, + + external_macro_backtrace: bool, } impl Emitter for AnnotateSnippetEmitterWriter { /// The entry point for the diagnostics generation - fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) { - let primary_span = db.span.clone(); - let children = db.children.clone(); - // FIXME(#59346): Collect suggestions (see emitter.rs) - let suggestions: &[_] = &[]; + fn emit_diagnostic(&mut self, db: &Diagnostic) { + let mut children = db.children.clone(); + let (mut primary_span, suggestions) = self.primary_span_formatted(&db); - // FIXME(#59346): Add `fix_multispans_in_std_macros` function from emitter.rs + self.fix_multispans_in_std_macros(&self.source_map, + &mut primary_span, + &mut children, + &db.level, + self.external_macro_backtrace); self.emit_messages_default(&db.level, db.message(), @@ -107,7 +111,7 @@ impl<'a> DiagnosticConverter<'a> { annotated_files: Vec, primary_lo: Loc ) -> Vec { - // FIXME(#59346): Provide a test case where `annotated_files` is > 1 + // FIXME(#64205): Provide a test case where `annotated_files` is > 1 annotated_files.iter().flat_map(|annotated_file| { annotated_file.lines.iter().map(|line| { let line_source = Self::source_string(annotated_file.file.clone(), &line); @@ -148,7 +152,7 @@ impl<'a> DiagnosticConverter<'a> { /// Maps `Diagnostic::Level` to `snippet::AnnotationType` fn annotation_type_for_level(level: Level) -> AnnotationType { match level { - Level::Bug | Level::Fatal | Level::PhaseFatal | Level::Error => AnnotationType::Error, + Level::Bug | Level::Fatal | Level::Error => AnnotationType::Error, Level::Warning => AnnotationType::Warning, Level::Note => AnnotationType::Note, Level::Help => AnnotationType::Help, @@ -161,12 +165,14 @@ impl<'a> DiagnosticConverter<'a> { impl AnnotateSnippetEmitterWriter { pub fn new( source_map: Option>, - short_message: bool + short_message: bool, + external_macro_backtrace: bool, ) -> Self { Self { source_map, short_message, ui_testing: false, + external_macro_backtrace, } } diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 424d7c0038389..fd74d8673da4d 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -94,7 +94,6 @@ impl Diagnostic { match self.level { Level::Bug | Level::Fatal | - Level::PhaseFatal | Level::Error | Level::FailureNote => { true @@ -120,6 +119,9 @@ impl Diagnostic { } /// Adds a span/label to be included in the resulting snippet. + /// This label will be shown together with the original span/label used when creating the + /// diagnostic, *not* a span added by one of the `span_*` methods. + /// /// This is pushed onto the `MultiSpan` that was created when the /// diagnostic was first built. If you don't call this function at /// all, and you just supplied a `Span` to create the diagnostic, @@ -196,6 +198,7 @@ impl Diagnostic { self } + /// Prints the span with a note above it. pub fn span_note>(&mut self, sp: S, msg: &str) @@ -209,6 +212,7 @@ impl Diagnostic { self } + /// Prints the span with a warn above it. pub fn span_warn>(&mut self, sp: S, msg: &str) @@ -222,6 +226,7 @@ impl Diagnostic { self } + /// Prints the span with some help above it. pub fn span_help>(&mut self, sp: S, msg: &str) @@ -293,9 +298,31 @@ impl Diagnostic { /// * may contain a name of a function, variable, or type, but not whole expressions /// /// See `CodeSuggestion` for more information. - pub fn span_suggestion(&mut self, sp: Span, msg: &str, - suggestion: String, - applicability: Applicability) -> &mut Self { + pub fn span_suggestion( + &mut self, + sp: Span, + msg: &str, + suggestion: String, + applicability: Applicability, + ) -> &mut Self { + self.span_suggestion_with_style( + sp, + msg, + suggestion, + applicability, + SuggestionStyle::ShowCode, + ); + self + } + + pub fn span_suggestion_with_style( + &mut self, + sp: Span, + msg: &str, + suggestion: String, + applicability: Applicability, + style: SuggestionStyle, + ) -> &mut Self { self.suggestions.push(CodeSuggestion { substitutions: vec![Substitution { parts: vec![SubstitutionPart { @@ -304,16 +331,37 @@ impl Diagnostic { }], }], msg: msg.to_owned(), - style: SuggestionStyle::ShowCode, + style, applicability, }); self } + pub fn span_suggestion_verbose( + &mut self, + sp: Span, + msg: &str, + suggestion: String, + applicability: Applicability, + ) -> &mut Self { + self.span_suggestion_with_style( + sp, + msg, + suggestion, + applicability, + SuggestionStyle::ShowAlways, + ); + self + } + /// Prints out a message with multiple suggested edits of the code. - pub fn span_suggestions(&mut self, sp: Span, msg: &str, - suggestions: impl Iterator, applicability: Applicability) -> &mut Self - { + pub fn span_suggestions( + &mut self, + sp: Span, + msg: &str, + suggestions: impl Iterator, + applicability: Applicability, + ) -> &mut Self { self.suggestions.push(CodeSuggestion { substitutions: suggestions.map(|snippet| Substitution { parts: vec![SubstitutionPart { @@ -335,17 +383,13 @@ impl Diagnostic { pub fn span_suggestion_short( &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability ) -> &mut Self { - self.suggestions.push(CodeSuggestion { - substitutions: vec![Substitution { - parts: vec![SubstitutionPart { - snippet: suggestion, - span: sp, - }], - }], - msg: msg.to_owned(), - style: SuggestionStyle::HideCodeInline, + self.span_suggestion_with_style( + sp, + msg, + suggestion, applicability, - }); + SuggestionStyle::HideCodeInline, + ); self } @@ -358,17 +402,13 @@ impl Diagnostic { pub fn span_suggestion_hidden( &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability ) -> &mut Self { - self.suggestions.push(CodeSuggestion { - substitutions: vec![Substitution { - parts: vec![SubstitutionPart { - snippet: suggestion, - span: sp, - }], - }], - msg: msg.to_owned(), - style: SuggestionStyle::HideCodeAlways, + self.span_suggestion_with_style( + sp, + msg, + suggestion, applicability, - }); + SuggestionStyle::HideCodeAlways, + ); self } @@ -379,17 +419,13 @@ impl Diagnostic { pub fn tool_only_span_suggestion( &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability ) -> &mut Self { - self.suggestions.push(CodeSuggestion { - substitutions: vec![Substitution { - parts: vec![SubstitutionPart { - snippet: suggestion, - span: sp, - }], - }], - msg: msg.to_owned(), - style: SuggestionStyle::CompletelyHidden, + self.span_suggestion_with_style( + sp, + msg, + suggestion, applicability, - }); + SuggestionStyle::CompletelyHidden, + ); self } diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 41d0638f7c6bd..cc60bf89c7eca 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -1,10 +1,6 @@ -use crate::Diagnostic; -use crate::DiagnosticId; -use crate::DiagnosticStyledString; -use crate::Applicability; +use crate::{Diagnostic, DiagnosticId, DiagnosticStyledString}; +use crate::{Applicability, Level, Handler, StashKey}; -use crate::Level; -use crate::Handler; use std::fmt::{self, Debug}; use std::ops::{Deref, DerefMut}; use std::thread::panicking; @@ -18,8 +14,17 @@ use log::debug; /// extending `HandlerFlags`, accessed via `self.handler.flags`. #[must_use] #[derive(Clone)] -pub struct DiagnosticBuilder<'a> { - pub handler: &'a Handler, +pub struct DiagnosticBuilder<'a>(Box>); + +/// This is a large type, and often used as a return value, especially within +/// the frequently-used `PResult` type. In theory, return value optimization +/// (RVO) should avoid unnecessary copying. In practice, it does not (at the +/// time of writing). The split between `DiagnosticBuilder` and +/// `DiagnosticBuilderInner` exists to avoid many `memcpy` calls. +#[must_use] +#[derive(Clone)] +struct DiagnosticBuilderInner<'a> { + handler: &'a Handler, diagnostic: Diagnostic, allow_suggestions: bool, } @@ -52,7 +57,7 @@ macro_rules! forward { ) => { $(#[$attrs])* pub fn $n(&mut self, $($name: $ty),*) -> &mut Self { - self.diagnostic.$n($($name),*); + self.0.diagnostic.$n($($name),*); self } }; @@ -69,7 +74,7 @@ macro_rules! forward { ) => { $(#[$attrs])* pub fn $n>(&mut self, $($name: $ty),*) -> &mut Self { - self.diagnostic.$n($($name),*); + self.0.diagnostic.$n($($name),*); self } }; @@ -79,24 +84,20 @@ impl<'a> Deref for DiagnosticBuilder<'a> { type Target = Diagnostic; fn deref(&self) -> &Diagnostic { - &self.diagnostic + &self.0.diagnostic } } impl<'a> DerefMut for DiagnosticBuilder<'a> { fn deref_mut(&mut self) -> &mut Diagnostic { - &mut self.diagnostic + &mut self.0.diagnostic } } impl<'a> DiagnosticBuilder<'a> { /// Emit the diagnostic. pub fn emit(&mut self) { - if self.cancelled() { - return; - } - - self.handler.emit_db(&self); + self.0.handler.emit_diagnostic(&self); self.cancel(); } @@ -112,27 +113,46 @@ impl<'a> DiagnosticBuilder<'a> { } } - /// Buffers the diagnostic for later emission, unless handler - /// has disabled such buffering. - pub fn buffer(mut self, buffered_diagnostics: &mut Vec) { - if self.handler.flags.dont_buffer_diagnostics || - self.handler.flags.treat_err_as_bug.is_some() + /// Stashes diagnostic for possible later improvement in a different, + /// later stage of the compiler. The diagnostic can be accessed with + /// the provided `span` and `key` through `.steal_diagnostic` on `Handler`. + /// + /// As with `buffer`, this is unless the handler has disabled such buffering. + pub fn stash(self, span: Span, key: StashKey) { + if let Some((diag, handler)) = self.into_diagnostic() { + handler.stash_diagnostic(span, key, diag); + } + } + + /// Converts the builder to a `Diagnostic` for later emission, + /// unless handler has disabled such buffering. + pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a Handler)> { + if self.0.handler.flags.dont_buffer_diagnostics || + self.0.handler.flags.treat_err_as_bug.is_some() { self.emit(); - return; + return None; } - // We need to use `ptr::read` because `DiagnosticBuilder` - // implements `Drop`. + let handler = self.0.handler; + + // We need to use `ptr::read` because `DiagnosticBuilder` implements `Drop`. let diagnostic; unsafe { - diagnostic = std::ptr::read(&self.diagnostic); + diagnostic = std::ptr::read(&self.0.diagnostic); std::mem::forget(self); }; // Logging here is useful to help track down where in logs an error was // actually emitted. debug!("buffer: diagnostic={:?}", diagnostic); - buffered_diagnostics.push(diagnostic); + + Some((diagnostic, handler)) + } + + /// Buffers the diagnostic for later emission, + /// unless handler has disabled such buffering. + pub fn buffer(self, buffered_diagnostics: &mut Vec) { + buffered_diagnostics.extend(self.into_diagnostic().map(|(diag, _)| diag)); } /// Convenience function for internal use, clients should use one of the @@ -144,7 +164,7 @@ impl<'a> DiagnosticBuilder<'a> { span: Option, ) -> &mut Self { let span = span.map(|s| s.into()).unwrap_or_else(|| MultiSpan::new()); - self.diagnostic.sub(level, message, span, None); + self.0.diagnostic.sub(level, message, span, None); self } @@ -160,7 +180,7 @@ impl<'a> DiagnosticBuilder<'a> { /// locally in whichever way makes the most sense. pub fn delay_as_bug(&mut self) { self.level = Level::Bug; - self.handler.delay_as_bug(self.diagnostic.clone()); + self.0.handler.delay_as_bug(self.0.diagnostic.clone()); self.cancel(); } @@ -171,7 +191,7 @@ impl<'a> DiagnosticBuilder<'a> { /// then the snippet will just include that `Span`, which is /// called the primary span. pub fn span_label>(&mut self, span: Span, label: T) -> &mut Self { - self.diagnostic.span_label(span, label); + self.0.diagnostic.span_label(span, label); self } @@ -208,10 +228,10 @@ impl<'a> DiagnosticBuilder<'a> { suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self { - if !self.allow_suggestions { + if !self.0.allow_suggestions { return self } - self.diagnostic.multipart_suggestion( + self.0.diagnostic.multipart_suggestion( msg, suggestion, applicability, @@ -225,10 +245,10 @@ impl<'a> DiagnosticBuilder<'a> { suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self { - if !self.allow_suggestions { + if !self.0.allow_suggestions { return self } - self.diagnostic.tool_only_multipart_suggestion( + self.0.diagnostic.tool_only_multipart_suggestion( msg, suggestion, applicability, @@ -236,7 +256,6 @@ impl<'a> DiagnosticBuilder<'a> { self } - pub fn span_suggestion( &mut self, sp: Span, @@ -244,10 +263,10 @@ impl<'a> DiagnosticBuilder<'a> { suggestion: String, applicability: Applicability, ) -> &mut Self { - if !self.allow_suggestions { + if !self.0.allow_suggestions { return self } - self.diagnostic.span_suggestion( + self.0.diagnostic.span_suggestion( sp, msg, suggestion, @@ -263,10 +282,10 @@ impl<'a> DiagnosticBuilder<'a> { suggestions: impl Iterator, applicability: Applicability, ) -> &mut Self { - if !self.allow_suggestions { + if !self.0.allow_suggestions { return self } - self.diagnostic.span_suggestions( + self.0.diagnostic.span_suggestions( sp, msg, suggestions, @@ -282,10 +301,10 @@ impl<'a> DiagnosticBuilder<'a> { suggestion: String, applicability: Applicability, ) -> &mut Self { - if !self.allow_suggestions { + if !self.0.allow_suggestions { return self } - self.diagnostic.span_suggestion_short( + self.0.diagnostic.span_suggestion_short( sp, msg, suggestion, @@ -301,10 +320,10 @@ impl<'a> DiagnosticBuilder<'a> { suggestion: String, applicability: Applicability, ) -> &mut Self { - if !self.allow_suggestions { + if !self.0.allow_suggestions { return self } - self.diagnostic.span_suggestion_hidden( + self.0.diagnostic.span_suggestion_hidden( sp, msg, suggestion, @@ -320,10 +339,10 @@ impl<'a> DiagnosticBuilder<'a> { suggestion: String, applicability: Applicability, ) -> &mut Self { - if !self.allow_suggestions { + if !self.0.allow_suggestions { return self } - self.diagnostic.tool_only_span_suggestion( + self.0.diagnostic.tool_only_span_suggestion( sp, msg, suggestion, @@ -336,13 +355,13 @@ impl<'a> DiagnosticBuilder<'a> { forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self); pub fn allow_suggestions(&mut self, allow: bool) -> &mut Self { - self.allow_suggestions = allow; + self.0.allow_suggestions = allow; self } /// Convenience function for internal use, clients should use one of the /// struct_* methods on Handler. - pub fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> { + crate fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> { DiagnosticBuilder::new_with_code(handler, level, None, message) } @@ -359,19 +378,19 @@ impl<'a> DiagnosticBuilder<'a> { /// Creates a new `DiagnosticBuilder` with an already constructed /// diagnostic. - pub fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) + crate fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> DiagnosticBuilder<'a> { - DiagnosticBuilder { + DiagnosticBuilder(Box::new(DiagnosticBuilderInner { handler, diagnostic, allow_suggestions: true, - } + })) } } impl<'a> Debug for DiagnosticBuilder<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.diagnostic.fmt(f) + self.0.diagnostic.fmt(f) } } @@ -381,7 +400,7 @@ impl<'a> Drop for DiagnosticBuilder<'a> { fn drop(&mut self) { if !panicking() && !self.cancelled() { let mut db = DiagnosticBuilder::new( - self.handler, + self.0.handler, Level::Bug, "the following error was constructed but not emitted", ); diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 361b5cd935712..68f933363daa1 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -12,7 +12,7 @@ use Destination::*; use syntax_pos::{SourceFile, Span, MultiSpan}; use crate::{ - Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, + Level, CodeSuggestion, Diagnostic, SubDiagnostic, SuggestionStyle, SourceMapperDyn, DiagnosticId, }; use crate::Level::Error; @@ -24,7 +24,7 @@ use rustc_data_structures::sync::Lrc; use std::borrow::Cow; use std::io::prelude::*; use std::io; -use std::cmp::{min, Reverse}; +use std::cmp::{min, max, Reverse}; use std::path::Path; use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter, Ansi}; use termcolor::{WriteColor, Color, Buffer}; @@ -51,9 +51,127 @@ impl HumanReadableErrorType { dst: Box, source_map: Option>, teach: bool, + terminal_width: Option, + external_macro_backtrace: bool, ) -> EmitterWriter { let (short, color_config) = self.unzip(); - EmitterWriter::new(dst, source_map, short, teach, color_config.suggests_using_colors()) + let color = color_config.suggests_using_colors(); + EmitterWriter::new(dst, source_map, short, teach, color, terminal_width, + external_macro_backtrace) + } +} + +#[derive(Clone, Copy, Debug)] +struct Margin { + /// The available whitespace in the left that can be consumed when centering. + pub whitespace_left: usize, + /// The column of the beginning of left-most span. + pub span_left: usize, + /// The column of the end of right-most span. + pub span_right: usize, + /// The beginning of the line to be displayed. + pub computed_left: usize, + /// The end of the line to be displayed. + pub computed_right: usize, + /// The current width of the terminal. 140 by default and in tests. + pub column_width: usize, + /// The end column of a span label, including the span. Doesn't account for labels not in the + /// same line as the span. + pub label_right: usize, +} + +impl Margin { + fn new( + whitespace_left: usize, + span_left: usize, + span_right: usize, + label_right: usize, + column_width: usize, + max_line_len: usize, + ) -> Self { + // The 6 is padding to give a bit of room for `...` when displaying: + // ``` + // error: message + // --> file.rs:16:58 + // | + // 16 | ... fn foo(self) -> Self::Bar { + // | ^^^^^^^^^ + // ``` + + let mut m = Margin { + whitespace_left: whitespace_left.saturating_sub(6), + span_left: span_left.saturating_sub(6), + span_right: span_right + 6, + computed_left: 0, + computed_right: 0, + column_width, + label_right: label_right + 6, + }; + m.compute(max_line_len); + m + } + + fn was_cut_left(&self) -> bool { + self.computed_left > 0 + } + + fn was_cut_right(&self, line_len: usize) -> bool { + let right = if self.computed_right == self.span_right || + self.computed_right == self.label_right + { + // Account for the "..." padding given above. Otherwise we end up with code lines that + // do fit but end in "..." as if they were trimmed. + self.computed_right - 6 + } else { + self.computed_right + }; + right < line_len && self.computed_left + self.column_width < line_len + } + + fn compute(&mut self, max_line_len: usize) { + // When there's a lot of whitespace (>20), we want to trim it as it is useless. + self.computed_left = if self.whitespace_left > 20 { + self.whitespace_left - 16 // We want some padding. + } else { + 0 + }; + // We want to show as much as possible, max_line_len is the right-most boundary for the + // relevant code. + self.computed_right = max(max_line_len, self.computed_left); + + if self.computed_right - self.computed_left > self.column_width { + // Trimming only whitespace isn't enough, let's get craftier. + if self.label_right - self.whitespace_left <= self.column_width { + // Attempt to fit the code window only trimming whitespace. + self.computed_left = self.whitespace_left; + self.computed_right = self.computed_left + self.column_width; + } else if self.label_right - self.span_left <= self.column_width { + // Attempt to fit the code window considering only the spans and labels. + let padding_left = (self.column_width - (self.label_right - self.span_left)) / 2; + self.computed_left = self.span_left.saturating_sub(padding_left); + self.computed_right = self.computed_left + self.column_width; + } else if self.span_right - self.span_left <= self.column_width { + // Attempt to fit the code window considering the spans and labels plus padding. + let padding_left = (self.column_width - (self.span_right - self.span_left)) / 5 * 2; + self.computed_left = self.span_left.saturating_sub(padding_left); + self.computed_right = self.computed_left + self.column_width; + } else { // Mostly give up but still don't show the full line. + self.computed_left = self.span_left; + self.computed_right = self.span_right; + } + } + } + + fn left(&self, line_len: usize) -> usize { + min(self.computed_left, line_len) + } + + fn right(&self, line_len: usize) -> usize { + if line_len.saturating_sub(self.computed_left) <= self.column_width { + line_len + } else { + min(line_len, self.computed_right) + } } } @@ -62,7 +180,7 @@ const ANONYMIZED_LINE_NUM: &str = "LL"; /// Emitter trait for emitting errors. pub trait Emitter { /// Emit a structured diagnostic. - fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>); + fn emit_diagnostic(&mut self, db: &Diagnostic); /// Emit a notification that an artifact has been output. /// This is currently only supported for the JSON format, @@ -73,16 +191,25 @@ pub trait Emitter { fn should_show_explain(&self) -> bool { true } -} -impl Emitter for EmitterWriter { - fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) { + /// Formats the substitutions of the primary_span + /// + /// The are a lot of conditions to this method, but in short: + /// + /// * If the current `Diagnostic` has only one visible `CodeSuggestion`, + /// we format the `help` suggestion depending on the content of the + /// substitutions. In that case, we return the modified span only. + /// + /// * If the current `Diagnostic` has multiple suggestions, + /// we return the original `primary_span` and the original suggestions. + fn primary_span_formatted<'a>( + &mut self, + db: &'a Diagnostic + ) -> (MultiSpan, &'a [CodeSuggestion]) { let mut primary_span = db.span.clone(); - let mut children = db.children.clone(); - let mut suggestions: &[_] = &[]; - if let Some((sugg, rest)) = db.suggestions.split_first() { if rest.is_empty() && + // ^ if there is only one suggestion // don't display multi-suggestions as labels sugg.substitutions.len() == 1 && // don't display multipart suggestions as labels @@ -91,33 +218,179 @@ impl Emitter for EmitterWriter { sugg.msg.split_whitespace().count() < 10 && // don't display multiline suggestions as labels !sugg.substitutions[0].parts[0].snippet.contains('\n') && - // when this style is set we want the suggestion to be a message, not inline - sugg.style != SuggestionStyle::HideCodeAlways && - // trivial suggestion for tooling's sake, never shown - sugg.style != SuggestionStyle::CompletelyHidden + ![ + // when this style is set we want the suggestion to be a message, not inline + SuggestionStyle::HideCodeAlways, + // trivial suggestion for tooling's sake, never shown + SuggestionStyle::CompletelyHidden, + // subtle suggestion, never shown inline + SuggestionStyle::ShowAlways, + ].contains(&sugg.style) { let substitution = &sugg.substitutions[0].parts[0].snippet.trim(); let msg = if substitution.len() == 0 || sugg.style.hide_inline() { - // This substitution is only removal or we explicitly don't want to show the - // code inline, don't show it + // This substitution is only removal OR we explicitly don't want to show the + // code inline (`hide_inline`). Therefore, we don't show the substitution. format!("help: {}", sugg.msg) } else { + // Show the default suggestion text with the substitution format!("help: {}: `{}`", sugg.msg, substitution) }; primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg); + + // We return only the modified primary_span + (primary_span, &[]) } else { // if there are multiple suggestions, print them all in full // to be consistent. We could try to figure out if we can // make one (or the first one) inline, but that would give // undue importance to a semi-random suggestion - suggestions = &db.suggestions; + (primary_span, &db.suggestions) } + } else { + (primary_span, &db.suggestions) + } + } + + // This does a small "fix" for multispans by looking to see if it can find any that + // point directly at <*macros>. Since these are often difficult to read, this + // will change the span to point at the use site. + fn fix_multispans_in_std_macros(&self, + source_map: &Option>, + span: &mut MultiSpan, + children: &mut Vec, + level: &Level, + backtrace: bool) { + let mut spans_updated = self.fix_multispan_in_std_macros(source_map, span, backtrace); + for child in children.iter_mut() { + spans_updated |= self.fix_multispan_in_std_macros( + source_map, + &mut child.span, + backtrace + ); } + let msg = if level == &Error { + "this error originates in a macro outside of the current crate \ + (in Nightly builds, run with -Z external-macro-backtrace \ + for more info)".to_string() + } else { + "this warning originates in a macro outside of the current crate \ + (in Nightly builds, run with -Z external-macro-backtrace \ + for more info)".to_string() + }; + + if spans_updated { + children.push(SubDiagnostic { + level: Level::Note, + message: vec![ + (msg, + Style::NoStyle), + ], + span: MultiSpan::new(), + render_span: None, + }); + } + } - self.fix_multispans_in_std_macros(&mut primary_span, + // This "fixes" MultiSpans that contain Spans that are pointing to locations inside of + // <*macros>. Since these locations are often difficult to read, we move these Spans from + // <*macros> to their corresponding use site. + fn fix_multispan_in_std_macros(&self, + source_map: &Option>, + span: &mut MultiSpan, + always_backtrace: bool) -> bool { + let sm = match source_map { + Some(ref sm) => sm, + None => return false, + }; + + let mut before_after: Vec<(Span, Span)> = vec![]; + let mut new_labels: Vec<(Span, String)> = vec![]; + + // First, find all the spans in <*macros> and point instead at their use site + for sp in span.primary_spans() { + if sp.is_dummy() { + continue; + } + let call_sp = sm.call_span_if_macro(*sp); + if call_sp != *sp && !always_backtrace { + before_after.push((*sp, call_sp)); + } + let backtrace_len = sp.macro_backtrace().len(); + for (i, trace) in sp.macro_backtrace().iter().rev().enumerate() { + // Only show macro locations that are local + // and display them like a span_note + if trace.def_site_span.is_dummy() { + continue; + } + if always_backtrace { + new_labels.push((trace.def_site_span, + format!("in this expansion of `{}`{}", + trace.macro_decl_name, + if backtrace_len > 2 { + // if backtrace_len == 1 it'll be pointed + // at by "in this macro invocation" + format!(" (#{})", i + 1) + } else { + String::new() + }))); + } + // Check to make sure we're not in any <*macros> + if !sm.span_to_filename(trace.def_site_span).is_macros() && + !trace.macro_decl_name.starts_with("desugaring of ") && + !trace.macro_decl_name.starts_with("#[") || + always_backtrace { + new_labels.push((trace.call_site, + format!("in this macro invocation{}", + if backtrace_len > 2 && always_backtrace { + // only specify order when the macro + // backtrace is multiple levels deep + format!(" (#{})", i + 1) + } else { + String::new() + }))); + if !always_backtrace { + break; + } + } + } + } + for (label_span, label_text) in new_labels { + span.push_span_label(label_span, label_text); + } + for sp_label in span.span_labels() { + if sp_label.span.is_dummy() { + continue; + } + if sm.span_to_filename(sp_label.span.clone()).is_macros() && + !always_backtrace + { + let v = sp_label.span.macro_backtrace(); + if let Some(use_site) = v.last() { + before_after.push((sp_label.span.clone(), use_site.call_site.clone())); + } + } + } + // After we have them, make sure we replace these 'bad' def sites with their use sites + let spans_updated = !before_after.is_empty(); + for (before, after) in before_after { + span.replace(before, after); + } + + spans_updated + } +} + +impl Emitter for EmitterWriter { + fn emit_diagnostic(&mut self, db: &Diagnostic) { + let mut children = db.children.clone(); + let (mut primary_span, suggestions) = self.primary_span_formatted(&db); + + self.fix_multispans_in_std_macros(&self.sm, + &mut primary_span, &mut children, &db.level, - db.handler.flags.external_macro_backtrace); + self.external_macro_backtrace); self.emit_messages_default(&db.level, &db.styled_message(), @@ -180,6 +453,9 @@ pub struct EmitterWriter { short_message: bool, teach: bool, ui_testing: bool, + terminal_width: Option, + + external_macro_backtrace: bool, } #[derive(Debug)] @@ -190,11 +466,14 @@ pub struct FileWithAnnotatedLines { } impl EmitterWriter { - pub fn stderr(color_config: ColorConfig, - source_map: Option>, - short_message: bool, - teach: bool) - -> EmitterWriter { + pub fn stderr( + color_config: ColorConfig, + source_map: Option>, + short_message: bool, + teach: bool, + terminal_width: Option, + external_macro_backtrace: bool, + ) -> EmitterWriter { let dst = Destination::from_stderr(color_config); EmitterWriter { dst, @@ -202,6 +481,8 @@ impl EmitterWriter { short_message, teach, ui_testing: false, + terminal_width, + external_macro_backtrace, } } @@ -211,6 +492,8 @@ impl EmitterWriter { short_message: bool, teach: bool, colored: bool, + terminal_width: Option, + external_macro_backtrace: bool, ) -> EmitterWriter { EmitterWriter { dst: Raw(dst, colored), @@ -218,6 +501,8 @@ impl EmitterWriter { short_message, teach, ui_testing: false, + terminal_width, + external_macro_backtrace, } } @@ -234,12 +519,70 @@ impl EmitterWriter { } } - fn render_source_line(&self, - buffer: &mut StyledBuffer, - file: Lrc, - line: &Line, - width_offset: usize, - code_offset: usize) -> Vec<(usize, Style)> { + fn draw_line( + &self, + buffer: &mut StyledBuffer, + source_string: &str, + line_index: usize, + line_offset: usize, + width_offset: usize, + code_offset: usize, + margin: Margin, + ) { + let line_len = source_string.len(); + // Create the source line we will highlight. + let left = margin.left(line_len); + let right = margin.right(line_len); + // On long lines, we strip the source line, accounting for unicode. + let mut taken = 0; + let code: String = source_string.chars().skip(left).take_while(|ch| { + // Make sure that the trimming on the right will fall within the terminal width. + // FIXME: `unicode_width` sometimes disagrees with terminals on how wide a `char` is. + // For now, just accept that sometimes the code line will be longer than desired. + let next = unicode_width::UnicodeWidthChar::width(*ch).unwrap_or(1); + if taken + next > right - left { + return false; + } + taken += next; + true + }).collect(); + buffer.puts(line_offset, code_offset, &code, Style::Quotation); + if margin.was_cut_left() { + // We have stripped some code/whitespace from the beginning, make it clear. + buffer.puts(line_offset, code_offset, "...", Style::LineNumber); + } + if margin.was_cut_right(line_len) { + // We have stripped some code after the right-most span end, make it clear we did so. + buffer.puts(line_offset, code_offset + taken - 3, "...", Style::LineNumber); + } + buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber); + + draw_col_separator(buffer, line_offset, width_offset - 2); + } + + fn render_source_line( + &self, + buffer: &mut StyledBuffer, + file: Lrc, + line: &Line, + width_offset: usize, + code_offset: usize, + margin: Margin, + ) -> Vec<(usize, Style)> { + // Draw: + // + // LL | ... code ... + // | ^^-^ span label + // | | + // | secondary span label + // + // ^^ ^ ^^^ ^^^^ ^^^ we don't care about code too far to the right of a span, we trim it + // | | | | + // | | | actual code found in your source code and the spans we use to mark it + // | | when there's too much wasted space to the left, trim it + // | vertical divider between the column number and the code + // column number + if line.line_index == 0 { return Vec::new(); } @@ -251,14 +594,21 @@ impl EmitterWriter { let line_offset = buffer.num_lines(); - // First create the source line we will highlight. - buffer.puts(line_offset, code_offset, &source_string, Style::Quotation); - buffer.puts(line_offset, - 0, - &self.maybe_anonymized(line.line_index), - Style::LineNumber); - - draw_col_separator(buffer, line_offset, width_offset - 2); + let left = margin.left(source_string.len()); // Left trim + // Account for unicode characters of width !=0 that were removed. + let left = source_string.chars().take(left) + .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1)) + .sum(); + + self.draw_line( + buffer, + &source_string, + line.line_index, + line_offset, + width_offset, + code_offset, + margin, + ); // Special case when there's only one annotation involved, it is the start of a multiline // span and there's no text at the beginning of the code line. Instead of doing the whole @@ -276,23 +626,16 @@ impl EmitterWriter { // 3 | | // 4 | | } // | |_^ test - if line.annotations.len() == 1 { - if let Some(ref ann) = line.annotations.get(0) { - if let AnnotationType::MultilineStart(depth) = ann.annotation_type { - if source_string.chars() - .take(ann.start_col) - .all(|c| c.is_whitespace()) { - let style = if ann.is_primary { - Style::UnderlinePrimary - } else { - Style::UnderlineSecondary - }; - buffer.putc(line_offset, - width_offset + depth - 1, - '/', - style); - return vec![(depth, style)]; - } + if let [ann] = &line.annotations[..] { + if let AnnotationType::MultilineStart(depth) = ann.annotation_type { + if source_string.chars().take(ann.start_col).all(|c| c.is_whitespace()) { + let style = if ann.is_primary { + Style::UnderlinePrimary + } else { + Style::UnderlineSecondary + }; + buffer.putc(line_offset, width_offset + depth - 1, '/', style); + return vec![(depth, style)]; } } } @@ -421,11 +764,7 @@ impl EmitterWriter { annotations_position.push((p, annotation)); for (j, next) in annotations.iter().enumerate() { if j > i { - let l = if let Some(ref label) = next.label { - label.len() + 2 - } else { - 0 - }; + let l = next.label.as_ref().map_or(0, |label| label.len() + 2); if (overlaps(next, annotation, l) // Do not allow two labels to be in the same // line if they overlap including padding, to // avoid situations like: @@ -455,9 +794,7 @@ impl EmitterWriter { } } } - if line_len < p { - line_len = p; - } + line_len = max(line_len, p); } if line_len != 0 { @@ -511,19 +848,23 @@ impl EmitterWriter { match annotation.annotation_type { AnnotationType::MultilineStart(depth) | AnnotationType::MultilineEnd(depth) => { - draw_range(buffer, - '_', - line_offset + pos, - width_offset + depth, - code_offset + annotation.start_col, - style); + draw_range( + buffer, + '_', + line_offset + pos, + width_offset + depth, + code_offset + annotation.start_col - left, + style, + ); } _ if self.teach => { - buffer.set_style_range(line_offset, - code_offset + annotation.start_col, - code_offset + annotation.end_col, - style, - annotation.is_primary); + buffer.set_style_range( + line_offset, + code_offset + annotation.start_col - left, + code_offset + annotation.end_col - left, + style, + annotation.is_primary, + ); } _ => {} } @@ -551,7 +892,7 @@ impl EmitterWriter { if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..=line_offset + pos { buffer.putc(p, - code_offset + annotation.start_col, + code_offset + annotation.start_col - margin.computed_left, '|', style); } @@ -595,15 +936,12 @@ impl EmitterWriter { Style::LabelSecondary }; let (pos, col) = if pos == 0 { - (pos + 1, annotation.end_col + 1) + (pos + 1, (annotation.end_col + 1).saturating_sub(left)) } else { - (pos + 2, annotation.start_col) + (pos + 2, annotation.start_col.saturating_sub(left)) }; if let Some(ref label) = annotation.label { - buffer.puts(line_offset + pos, - code_offset + col, - &label, - style); + buffer.puts(line_offset + pos, code_offset + col, &label, style); } } @@ -615,9 +953,9 @@ impl EmitterWriter { // | | | // | | something about `foo` // | something about `fn foo()` - annotations_position.sort_by(|a, b| { - // Decreasing order. When `a` and `b` are the same length, prefer `Primary`. - (a.1.len(), !a.1.is_primary).cmp(&(b.1.len(), !b.1.is_primary)).reverse() + annotations_position.sort_by_key(|(_, ann)| { + // Decreasing order. When annotations share the same length, prefer `Primary`. + (Reverse(ann.len()), ann.is_primary) }); // Write the underlines. @@ -638,10 +976,12 @@ impl EmitterWriter { ('-', Style::UnderlineSecondary) }; for p in annotation.start_col..annotation.end_col { - buffer.putc(line_offset + 1, - code_offset + p, - underline, - style); + buffer.putc( + line_offset + 1, + (code_offset + p).saturating_sub(left), + underline, + style, + ); } } annotations_position.iter().filter_map(|&(_, annotation)| { @@ -661,162 +1001,37 @@ impl EmitterWriter { } fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize { + let sm = match self.sm { + Some(ref sm) => sm, + None => return 0, + }; + let mut max = 0; - if let Some(ref sm) = self.sm { - for primary_span in msp.primary_spans() { - if !primary_span.is_dummy() { - let hi = sm.lookup_char_pos(primary_span.hi()); - if hi.line > max { - max = hi.line; - } - } + for primary_span in msp.primary_spans() { + if !primary_span.is_dummy() { + let hi = sm.lookup_char_pos(primary_span.hi()); + max = (hi.line).max(max); } - if !self.short_message { - for span_label in msp.span_labels() { - if !span_label.span.is_dummy() { - let hi = sm.lookup_char_pos(span_label.span.hi()); - if hi.line > max { - max = hi.line; - } - } + } + if !self.short_message { + for span_label in msp.span_labels() { + if !span_label.span.is_dummy() { + let hi = sm.lookup_char_pos(span_label.span.hi()); + max = (hi.line).max(max); } } } + max } fn get_max_line_num(&mut self, span: &MultiSpan, children: &[SubDiagnostic]) -> usize { - let mut max = 0; - let primary = self.get_multispan_max_line_num(span); - max = if primary > max { primary } else { max }; - - for sub in children { - let sub_result = self.get_multispan_max_line_num(&sub.span); - max = if sub_result > max { primary } else { max }; - } - max - } - - // This "fixes" MultiSpans that contain Spans that are pointing to locations inside of - // <*macros>. Since these locations are often difficult to read, we move these Spans from - // <*macros> to their corresponding use site. - fn fix_multispan_in_std_macros(&mut self, - span: &mut MultiSpan, - always_backtrace: bool) -> bool { - let mut spans_updated = false; - - if let Some(ref sm) = self.sm { - let mut before_after: Vec<(Span, Span)> = vec![]; - let mut new_labels: Vec<(Span, String)> = vec![]; - - // First, find all the spans in <*macros> and point instead at their use site - for sp in span.primary_spans() { - if sp.is_dummy() { - continue; - } - let call_sp = sm.call_span_if_macro(*sp); - if call_sp != *sp && !always_backtrace { - before_after.push((*sp, call_sp)); - } - let backtrace_len = sp.macro_backtrace().len(); - for (i, trace) in sp.macro_backtrace().iter().rev().enumerate() { - // Only show macro locations that are local - // and display them like a span_note - if trace.def_site_span.is_dummy() { - continue; - } - if always_backtrace { - new_labels.push((trace.def_site_span, - format!("in this expansion of `{}`{}", - trace.macro_decl_name, - if backtrace_len > 2 { - // if backtrace_len == 1 it'll be pointed - // at by "in this macro invocation" - format!(" (#{})", i + 1) - } else { - String::new() - }))); - } - // Check to make sure we're not in any <*macros> - if !sm.span_to_filename(trace.def_site_span).is_macros() && - !trace.macro_decl_name.starts_with("desugaring of ") && - !trace.macro_decl_name.starts_with("#[") || - always_backtrace { - new_labels.push((trace.call_site, - format!("in this macro invocation{}", - if backtrace_len > 2 && always_backtrace { - // only specify order when the macro - // backtrace is multiple levels deep - format!(" (#{})", i + 1) - } else { - String::new() - }))); - if !always_backtrace { - break; - } - } - } - } - for (label_span, label_text) in new_labels { - span.push_span_label(label_span, label_text); - } - for sp_label in span.span_labels() { - if sp_label.span.is_dummy() { - continue; - } - if sm.span_to_filename(sp_label.span.clone()).is_macros() && - !always_backtrace - { - let v = sp_label.span.macro_backtrace(); - if let Some(use_site) = v.last() { - before_after.push((sp_label.span.clone(), use_site.call_site.clone())); - } - } - } - // After we have them, make sure we replace these 'bad' def sites with their use sites - for (before, after) in before_after { - span.replace(before, after); - spans_updated = true; - } - } - - spans_updated - } - - // This does a small "fix" for multispans by looking to see if it can find any that - // point directly at <*macros>. Since these are often difficult to read, this - // will change the span to point at the use site. - fn fix_multispans_in_std_macros(&mut self, - span: &mut MultiSpan, - children: &mut Vec, - level: &Level, - backtrace: bool) { - let mut spans_updated = self.fix_multispan_in_std_macros(span, backtrace); - for child in children.iter_mut() { - spans_updated |= self.fix_multispan_in_std_macros(&mut child.span, backtrace); - } - let msg = if level == &Error { - "this error originates in a macro outside of the current crate \ - (in Nightly builds, run with -Z external-macro-backtrace \ - for more info)".to_string() - } else { - "this warning originates in a macro outside of the current crate \ - (in Nightly builds, run with -Z external-macro-backtrace \ - for more info)".to_string() - }; - - if spans_updated { - children.push(SubDiagnostic { - level: Level::Note, - message: vec![ - (msg, - Style::NoStyle), - ], - span: MultiSpan::new(), - render_span: None, - }); - } + children.iter() + .map(|sub| self.get_multispan_max_line_num(&sub.span)) + .max() + .unwrap_or(0) + .max(primary) } /// Adds a left margin to every line but the first, given a padding length and the label being @@ -846,14 +1061,12 @@ impl EmitterWriter { // `max_line_num_len` let padding = " ".repeat(padding + label.len() + 5); - /// Returns `true` if `style`, or the override if present and the style is `NoStyle`. - fn style_or_override(style: Style, override_style: Option\n\n").unwrap(); - trace::write_traces(&mut html_file, &mut counts_file, &frame.traces); - writeln!(html_file, "\n").unwrap(); - - let ack_path = format!("{}.ack", params.path); - let ack_file = File::create(&ack_path).unwrap(); - drop(ack_file); - - // Tell main thread that we are done, e.g., so it can exit - params.ack.send(()).unwrap(); - } - // Actual query message: - msg => { - // Record msg in our log - profq_msgs.push(msg.clone()); - // Respond to the message, knowing that we've already handled Halt and Dump, above. - match (frame.parse_st.clone(), msg) { - (_, ProfileQueriesMsg::Halt) | (_, ProfileQueriesMsg::Dump(_)) => { - unreachable!(); - }, - // Parse State: Clear - (ParseState::Clear, - ProfileQueriesMsg::QueryBegin(span, querymsg)) => { - let start = Instant::now(); - frame.parse_st = ParseState::HaveQuery - (Query { span, msg: querymsg }, start) - }, - (ParseState::Clear, - ProfileQueriesMsg::CacheHit) => { - panic!("parse error: unexpected CacheHit; expected QueryBegin") - }, - (ParseState::Clear, - ProfileQueriesMsg::ProviderBegin) => { - panic!("parse error: expected QueryBegin before beginning a provider") - }, - (ParseState::Clear, - ProfileQueriesMsg::ProviderEnd) => { - let provider_extent = frame.traces; - match stack.pop() { - None => - panic!("parse error: expected a stack frame; found an empty stack"), - Some(old_frame) => { - match old_frame.parse_st { - ParseState::HaveQuery(q, start) => { - let duration = start.elapsed(); - frame = StackFrame{ - parse_st: ParseState::Clear, - traces: old_frame.traces - }; - let dur_extent = total_duration(&provider_extent); - let trace = Rec { - effect: Effect::QueryBegin(q, CacheCase::Miss), - extent: Box::new(provider_extent), - start: start, - dur_self: duration - dur_extent, - dur_total: duration, - }; - frame.traces.push( trace ); - }, - _ => panic!("internal parse error: malformed parse stack") - } - } - } - }, - (ParseState::Clear, - ProfileQueriesMsg::TimeBegin(msg)) => { - let start = Instant::now(); - frame.parse_st = ParseState::HaveTimeBegin(msg, start); - stack.push(frame); - frame = StackFrame{parse_st: ParseState::Clear, traces: vec![]}; - }, - (_, ProfileQueriesMsg::TimeBegin(_)) => { - panic!("parse error; did not expect time begin here"); - }, - (ParseState::Clear, - ProfileQueriesMsg::TimeEnd) => { - let provider_extent = frame.traces; - match stack.pop() { - None => - panic!("parse error: expected a stack frame; found an empty stack"), - Some(old_frame) => { - match old_frame.parse_st { - ParseState::HaveTimeBegin(msg, start) => { - let duration = start.elapsed(); - frame = StackFrame{ - parse_st: ParseState::Clear, - traces: old_frame.traces - }; - let dur_extent = total_duration(&provider_extent); - let trace = Rec { - effect: Effect::TimeBegin(msg), - extent: Box::new(provider_extent), - start: start, - dur_total: duration, - dur_self: duration - dur_extent, - }; - frame.traces.push( trace ); - }, - _ => panic!("internal parse error: malformed parse stack") - } - } - } - }, - (_, ProfileQueriesMsg::TimeEnd) => { - panic!("parse error") - }, - (ParseState::Clear, - ProfileQueriesMsg::TaskBegin(key)) => { - let start = Instant::now(); - frame.parse_st = ParseState::HaveTaskBegin(key, start); - stack.push(frame); - frame = StackFrame{ parse_st: ParseState::Clear, traces: vec![] }; - }, - (_, ProfileQueriesMsg::TaskBegin(_)) => { - panic!("parse error; did not expect time begin here"); - }, - (ParseState::Clear, - ProfileQueriesMsg::TaskEnd) => { - let provider_extent = frame.traces; - match stack.pop() { - None => - panic!("parse error: expected a stack frame; found an empty stack"), - Some(old_frame) => { - match old_frame.parse_st { - ParseState::HaveTaskBegin(key, start) => { - let duration = start.elapsed(); - frame = StackFrame{ - parse_st: ParseState::Clear, - traces: old_frame.traces - }; - let dur_extent = total_duration(&provider_extent); - let trace = Rec { - effect: Effect::TaskBegin(key), - extent: Box::new(provider_extent), - start: start, - dur_total: duration, - dur_self: duration - dur_extent, - }; - frame.traces.push( trace ); - }, - _ => panic!("internal parse error: malformed parse stack") - } - } - } - }, - (_, ProfileQueriesMsg::TaskEnd) => { - panic!("parse error") - }, - // Parse State: HaveQuery - (ParseState::HaveQuery(q,start), - ProfileQueriesMsg::CacheHit) => { - let duration = start.elapsed(); - let trace : Rec = Rec{ - effect: Effect::QueryBegin(q, CacheCase::Hit), - extent: Box::new(vec![]), - start: start, - dur_self: duration, - dur_total: duration, - }; - frame.traces.push( trace ); - frame.parse_st = ParseState::Clear; - }, - (ParseState::HaveQuery(_, _), - ProfileQueriesMsg::ProviderBegin) => { - stack.push(frame); - frame = StackFrame{ parse_st: ParseState::Clear, traces: vec![] }; - }, - - // Parse errors: - - (ParseState::HaveQuery(q, _), - ProfileQueriesMsg::ProviderEnd) => { - panic!("parse error: unexpected ProviderEnd; \ - expected something else to follow BeginQuery for {:?}", q) - }, - (ParseState::HaveQuery(q1, _), - ProfileQueriesMsg::QueryBegin(span2, querymsg2)) => { - panic!("parse error: unexpected QueryBegin; \ - earlier query is unfinished: {:?} and now {:?}", - q1, Query{span:span2, msg: querymsg2}) - }, - (ParseState::HaveTimeBegin(_, _), _) => { - unreachable!() - }, - (ParseState::HaveTaskBegin(_, _), _) => { - unreachable!() - }, - } - } - } - } -} diff --git a/src/librustc_interface/profile/trace.rs b/src/librustc_interface/profile/trace.rs deleted file mode 100644 index 95c4ea6ff2347..0000000000000 --- a/src/librustc_interface/profile/trace.rs +++ /dev/null @@ -1,304 +0,0 @@ -use super::*; -use syntax_pos::SpanData; -use rustc_data_structures::fx::FxHashMap; -use rustc::util::common::QueryMsg; -use std::fs::File; -use std::time::{Duration, Instant}; -use rustc::dep_graph::{DepNode}; - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Query { - pub span: SpanData, - pub msg: QueryMsg, -} -pub enum Effect { - QueryBegin(Query, CacheCase), - TimeBegin(String), - TaskBegin(DepNode), -} -pub enum CacheCase { - Hit, Miss -} -/// Recursive trace structure -pub struct Rec { - pub effect: Effect, - pub start: Instant, - pub dur_self: Duration, - pub dur_total: Duration, - pub extent: Box>, -} -pub struct QueryMetric { - pub count: usize, - pub dur_self: Duration, - pub dur_total: Duration, -} - -fn cons(s: &str) -> String { - let first = s.split(|d| d == '(' || d == '{').next(); - assert!(first.is_some() && first != Some("")); - first.unwrap().to_owned() -} - -pub fn cons_of_query_msg(q: &trace::Query) -> String { - cons(&format!("{:?}", q.msg)) -} - -pub fn cons_of_key(k: &DepNode) -> String { - cons(&format!("{:?}", k)) -} - -// First return value is text; second return value is a CSS class -pub fn html_of_effect(eff: &Effect) -> (String, String) { - match *eff { - Effect::TimeBegin(ref msg) => { - (msg.clone(), - "time-begin".to_string()) - }, - Effect::TaskBegin(ref key) => { - let cons = cons_of_key(key); - (cons.clone(), format!("{} task-begin", cons)) - }, - Effect::QueryBegin(ref qmsg, ref cc) => { - let cons = cons_of_query_msg(qmsg); - (cons.clone(), - format!("{} {}", - cons, - match *cc { - CacheCase::Hit => "hit", - CacheCase::Miss => "miss", - })) - } - } -} - -// First return value is text; second return value is a CSS class -fn html_of_duration(_start: &Instant, dur: &Duration) -> (String, String) { - use rustc::util::common::duration_to_secs_str; - (duration_to_secs_str(dur.clone()), String::new()) -} - -fn html_of_fraction(frac: f64) -> (String, &'static str) { - let css = { - if frac > 0.50 { "frac-50" } - else if frac > 0.40 { "frac-40" } - else if frac > 0.30 { "frac-30" } - else if frac > 0.20 { "frac-20" } - else if frac > 0.10 { "frac-10" } - else if frac > 0.05 { "frac-05" } - else if frac > 0.02 { "frac-02" } - else if frac > 0.01 { "frac-01" } - else if frac > 0.001 { "frac-001" } - else { "frac-0" } - }; - let percent = frac * 100.0; - - if percent > 0.1 { - (format!("{:.1}%", percent), css) - } else { - ("< 0.1%".to_string(), css) - } -} - -fn total_duration(traces: &[Rec]) -> Duration { - Duration::new(0, 0) + traces.iter().map(|t| t.dur_total).sum() -} - -fn duration_div(nom: Duration, den: Duration) -> f64 { - fn to_nanos(d: Duration) -> u64 { - d.as_secs() * 1_000_000_000 + d.subsec_nanos() as u64 - } - - to_nanos(nom) as f64 / to_nanos(den) as f64 -} - -fn write_traces_rec(file: &mut File, traces: &[Rec], total: Duration, depth: usize) { - for t in traces { - let (eff_text, eff_css_classes) = html_of_effect(&t.effect); - let (dur_text, dur_css_classes) = html_of_duration(&t.start, &t.dur_total); - let fraction = duration_div(t.dur_total, total); - let percent = fraction * 100.0; - let (frc_text, frc_css_classes) = html_of_fraction(fraction); - writeln!(file, "

").unwrap(); - } -} - -fn compute_counts_rec(counts: &mut FxHashMap, traces: &[Rec]) { - counts.reserve(traces.len()); - for t in traces.iter() { - match t.effect { - Effect::TimeBegin(ref msg) => { - let qm = match counts.get(msg) { - Some(_qm) => panic!("TimeBegin with non-unique, repeat message"), - None => QueryMetric { - count: 1, - dur_self: t.dur_self, - dur_total: t.dur_total, - } - }; - counts.insert(msg.clone(), qm); - }, - Effect::TaskBegin(ref key) => { - let cons = cons_of_key(key); - let qm = match counts.get(&cons) { - Some(qm) => - QueryMetric { - count: qm.count + 1, - dur_self: qm.dur_self + t.dur_self, - dur_total: qm.dur_total + t.dur_total, - }, - None => QueryMetric { - count: 1, - dur_self: t.dur_self, - dur_total: t.dur_total, - } - }; - counts.insert(cons, qm); - }, - Effect::QueryBegin(ref qmsg, ref _cc) => { - let qcons = cons_of_query_msg(qmsg); - let qm = match counts.get(&qcons) { - Some(qm) => - QueryMetric { - count: qm.count + 1, - dur_total: qm.dur_total + t.dur_total, - dur_self: qm.dur_self + t.dur_self - }, - None => QueryMetric { - count: 1, - dur_total: t.dur_total, - dur_self: t.dur_self, - } - }; - counts.insert(qcons, qm); - } - } - compute_counts_rec(counts, &t.extent) - } -} - -pub fn write_counts(count_file: &mut File, counts: &mut FxHashMap) { - use rustc::util::common::duration_to_secs_str; - use std::cmp::Reverse; - - let mut data = counts.iter().map(|(ref cons, ref qm)| - (cons.clone(), qm.count.clone(), qm.dur_total.clone(), qm.dur_self.clone()) - ).collect::>(); - - data.sort_by_key(|k| Reverse(k.3)); - for (cons, count, dur_total, dur_self) in data { - writeln!(count_file, "{}, {}, {}, {}", - cons, count, - duration_to_secs_str(dur_total), - duration_to_secs_str(dur_self) - ).unwrap(); - } -} - -pub fn write_traces(html_file: &mut File, counts_file: &mut File, traces: &[Rec]) { - let capacity = traces.iter().fold(0, |acc, t| acc + 1 + t.extent.len()); - let mut counts = FxHashMap::with_capacity_and_hasher(capacity, Default::default()); - compute_counts_rec(&mut counts, traces); - write_counts(counts_file, &mut counts); - - let total: Duration = total_duration(traces); - write_traces_rec(html_file, traces, total, 0) -} - -pub fn write_style(html_file: &mut File) { - write!(html_file, "{}", " -body { - font-family: sans-serif; - background: black; -} -.trace { - color: black; - display: inline-block; - border-style: solid; - border-color: red; - border-width: 1px; - border-radius: 5px; - padding: 0px; - margin: 1px; - font-size: 0px; -} -.task-begin { - border-width: 1px; - color: white; - border-color: #ff8; - font-size: 0px; -} -.miss { - border-color: red; - border-width: 1px; -} -.extent-0 { - padding: 2px; -} -.time-begin { - border-width: 4px; - font-size: 12px; - color: white; - border-color: #afa; -} -.important { - border-width: 3px; - font-size: 12px; - color: white; - border-color: #f77; -} -.hit { - padding: 0px; - border-color: blue; - border-width: 3px; -} -.eff { - color: #fff; - display: inline-block; -} -.frc { - color: #7f7; - display: inline-block; -} -.dur { - display: none -} -.frac-50 { - padding: 10px; - border-width: 10px; - font-size: 32px; -} -.frac-40 { - padding: 8px; - border-width: 8px; - font-size: 24px; -} -.frac-30 { - padding: 6px; - border-width: 6px; - font-size: 18px; -} -.frac-20 { - padding: 4px; - border-width: 6px; - font-size: 16px; -} -.frac-10 { - padding: 2px; - border-width: 6px; - font-size: 14px; -} -").unwrap(); -} diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs index 2e7952cd00447..cd72dc9453c7e 100644 --- a/src/librustc_interface/queries.rs +++ b/src/librustc_interface/queries.rs @@ -10,7 +10,6 @@ use rustc::ty::steal::Steal; use rustc::dep_graph::DepGraph; use std::cell::{Ref, RefMut, RefCell}; use std::rc::Rc; -use std::sync::mpsc; use std::any::Any; use std::mem; use syntax::{self, ast}; @@ -76,12 +75,10 @@ pub(crate) struct Queries { parse: Query, crate_name: Query, register_plugins: Query<(ast::Crate, PluginInfo)>, - expansion: Query<(ast::Crate, Rc>>)>, + expansion: Query<(ast::Crate, Steal>>)>, dep_graph: Query, lower_to_hir: Query<(Steal, ExpansionResult)>, prepare_outputs: Query, - codegen_channel: Query<(Steal>>, - Steal>>)>, global_ctxt: Query, ongoing_codegen: Query>, link: Query<()>, @@ -114,35 +111,44 @@ impl Compiler { let crate_name = self.crate_name()?.peek().clone(); let krate = self.parse()?.take(); - passes::register_plugins( - self, + let result = passes::register_plugins( self.session(), self.cstore(), krate, &crate_name, - ) + ); + + // Compute the dependency graph (in the background). We want to do + // this as early as possible, to give the DepGraph maximum time to + // load before dep_graph() is called, but it also can't happen + // until after rustc_incremental::prepare_session_directory() is + // called, which happens within passes::register_plugins(). + self.dep_graph_future().ok(); + + result }) } pub fn crate_name(&self) -> Result<&Query> { self.queries.crate_name.compute(|| { - let parse_result = self.parse()?; - let krate = parse_result.peek(); - let result = match self.crate_name { + Ok(match self.crate_name { Some(ref crate_name) => crate_name.clone(), - None => rustc_codegen_utils::link::find_crate_name( - Some(self.session()), - &krate.attrs, - &self.input - ), - }; - Ok(result) + None => { + let parse_result = self.parse()?; + let krate = parse_result.peek(); + rustc_codegen_utils::link::find_crate_name( + Some(self.session()), + &krate.attrs, + &self.input + ) + } + }) }) } pub fn expansion( &self - ) -> Result<&Query<(ast::Crate, Rc>>)>> { + ) -> Result<&Query<(ast::Crate, Steal>>)>> { self.queries.expansion.compute(|| { let crate_name = self.crate_name()?.peek().clone(); let (krate, plugin_info) = self.register_plugins()?.take(); @@ -152,7 +158,7 @@ impl Compiler { krate, &crate_name, plugin_info, - ).map(|(krate, resolver)| (krate, Rc::new(Some(RefCell::new(resolver))))) + ).map(|(krate, resolver)| (krate, Steal::new(Rc::new(RefCell::new(resolver))))) }) } @@ -176,9 +182,10 @@ impl Compiler { pub fn lower_to_hir(&self) -> Result<&Query<(Steal, ExpansionResult)>> { self.queries.lower_to_hir.compute(|| { let expansion_result = self.expansion()?; - let (krate, resolver) = expansion_result.take(); - let resolver_ref = &*resolver; - let hir = Steal::new(resolver_ref.as_ref().unwrap().borrow_mut().access(|resolver| { + let peeked = expansion_result.peek(); + let krate = &peeked.0; + let resolver = peeked.1.steal(); + let hir = Steal::new(resolver.borrow_mut().access(|resolver| { passes::lower_to_hir( self.session(), self.cstore(), @@ -187,14 +194,12 @@ impl Compiler { &krate ) })?); - expansion_result.give((krate, Rc::new(None))); Ok((hir, BoxedResolver::to_expansion_result(resolver))) }) } pub fn prepare_outputs(&self) -> Result<&Query> { self.queries.prepare_outputs.compute(|| { - self.lower_to_hir()?; let krate = self.expansion()?; let krate = krate.peek(); let crate_name = self.crate_name()?; @@ -203,14 +208,6 @@ impl Compiler { }) } - pub fn codegen_channel(&self) -> Result<&Query<(Steal>>, - Steal>>)>> { - self.queries.codegen_channel.compute(|| { - let (tx, rx) = mpsc::channel(); - Ok((Steal::new(tx), Steal::new(rx))) - }) - } - pub fn global_ctxt(&self) -> Result<&Query> { self.queries.global_ctxt.compute(|| { let crate_name = self.crate_name()?.peek().clone(); @@ -218,21 +215,18 @@ impl Compiler { let hir = self.lower_to_hir()?; let hir = hir.peek(); let (ref hir_forest, ref expansion) = *hir; - let tx = self.codegen_channel()?.peek().0.steal(); Ok(passes::create_global_ctxt( self, hir_forest.steal(), expansion.defs.steal(), expansion.resolutions.steal(), outputs, - tx, &crate_name)) }) } pub fn ongoing_codegen(&self) -> Result<&Query>> { self.queries.ongoing_codegen.compute(|| { - let rx = self.codegen_channel()?.peek().1.steal(); let outputs = self.prepare_outputs()?; self.global_ctxt()?.peek_mut().enter(|tcx| { tcx.analysis(LOCAL_CRATE).ok(); @@ -243,7 +237,6 @@ impl Compiler { Ok(passes::start_codegen( &***self.codegen_backend(), tcx, - rx, &*outputs.peek() )) }) @@ -267,6 +260,11 @@ impl Compiler { }) } + // This method is different to all the other methods in `Compiler` because + // it lacks a `Queries` entry. It's also not currently used. It does serve + // as an example of how `Compiler` can be used, with additional steps added + // between some passes. And see `rustc_driver::run_compiler` for a more + // complex example. pub fn compile(&self) -> Result<()> { self.prepare_outputs()?; @@ -278,12 +276,12 @@ impl Compiler { self.global_ctxt()?; - // Drop AST after creating GlobalCtxt to free memory + // Drop AST after creating GlobalCtxt to free memory. mem::drop(self.expansion()?.take()); self.ongoing_codegen()?; - // Drop GlobalCtxt after starting codegen to free memory + // Drop GlobalCtxt after starting codegen to free memory. mem::drop(self.global_ctxt()?.take()); self.link().map(|_| ()) diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index f007a0cf2abee..0c272f0c4563b 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -43,17 +43,17 @@ use std::{thread, panic}; pub fn diagnostics_registry() -> Registry { let mut all_errors = Vec::new(); - all_errors.extend_from_slice(&rustc::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_typeck::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS); + all_errors.extend_from_slice(&rustc::error_codes::DIAGNOSTICS); + all_errors.extend_from_slice(&rustc_typeck::error_codes::DIAGNOSTICS); + all_errors.extend_from_slice(&rustc_resolve::error_codes::DIAGNOSTICS); + all_errors.extend_from_slice(&rustc_privacy::error_codes::DIAGNOSTICS); // FIXME: need to figure out a way to get these back in here // all_errors.extend_from_slice(get_codegen_backend(sess).diagnostics()); - all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_mir::DIAGNOSTICS); - all_errors.extend_from_slice(&syntax::DIAGNOSTICS); + all_errors.extend_from_slice(&rustc_metadata::error_codes::DIAGNOSTICS); + all_errors.extend_from_slice(&rustc_passes::error_codes::DIAGNOSTICS); + all_errors.extend_from_slice(&rustc_plugin::error_codes::DIAGNOSTICS); + all_errors.extend_from_slice(&rustc_mir::error_codes::DIAGNOSTICS); + all_errors.extend_from_slice(&syntax::error_codes::DIAGNOSTICS); Registry::new(&all_errors) } @@ -173,7 +173,7 @@ pub fn scoped_thread R + Send, R: Send>(cfg: thread::Builder, f: #[cfg(not(parallel_compiler))] pub fn spawn_thread_pool R + Send, R: Send>( edition: Edition, - _threads: Option, + _threads: usize, stderr: &Option>>>, f: F, ) -> R { @@ -198,18 +198,19 @@ pub fn spawn_thread_pool R + Send, R: Send>( #[cfg(parallel_compiler)] pub fn spawn_thread_pool R + Send, R: Send>( edition: Edition, - threads: Option, + threads: usize, stderr: &Option>>>, f: F, ) -> R { - use rayon::{ThreadPool, ThreadPoolBuilder}; + use rayon::{ThreadBuilder, ThreadPool, ThreadPoolBuilder}; let gcx_ptr = &Lock::new(0); let mut config = ThreadPoolBuilder::new() + .thread_name(|_| "rustc".to_string()) .acquire_thread_handler(jobserver::acquire_thread) .release_thread_handler(jobserver::release_thread) - .num_threads(Session::threads_from_count(threads)) + .num_threads(threads) .deadlock_handler(|| unsafe { ty::query::handle_deadlock() }); if let Some(size) = get_stack_size() { @@ -225,20 +226,20 @@ pub fn spawn_thread_pool R + Send, R: Send>( // 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 dyn FnMut()| { + let main_handler = move |thread: ThreadBuilder| { syntax::GLOBALS.set(syntax_globals, || { syntax_pos::GLOBALS.set(syntax_pos_globals, || { if let Some(stderr) = stderr { io::set_panic(Some(box Sink(stderr.clone()))); } ty::tls::with_thread_locals(|| { - ty::tls::GCX_PTR.set(gcx_ptr, || worker()) + ty::tls::GCX_PTR.set(gcx_ptr, || thread.run()) }) }) }) }; - ThreadPool::scoped_pool(config, main_handler, with_pool).unwrap() + config.build_scoped(main_handler, with_pool).unwrap() }) }) }) @@ -289,20 +290,39 @@ pub fn get_codegen_backend(sess: &Session) -> Box { backend } -pub fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box { - // For now we only allow this function to be called once as it'll dlopen a - // few things, which seems to work best if we only do that once. In - // general this assertion never trips due to the once guard in `get_codegen_backend`, - // but there's a few manual calls to this function in this file we protect - // against. - static LOADED: AtomicBool = AtomicBool::new(false); - assert!(!LOADED.fetch_or(true, Ordering::SeqCst), - "cannot load the default codegen backend twice"); +// This is used for rustdoc, but it uses similar machinery to codegen backend +// loading, so we leave the code here. It is potentially useful for other tools +// that want to invoke the rustc binary while linking to rustc as well. +pub fn rustc_path<'a>() -> Option<&'a Path> { + static RUSTC_PATH: once_cell::sync::OnceCell> = + once_cell::sync::OnceCell::new(); + const BIN_PATH: &str = env!("RUSTC_INSTALL_BINDIR"); + + RUSTC_PATH.get_or_init(|| get_rustc_path_inner(BIN_PATH)).as_ref().map(|v| &**v) +} + +fn get_rustc_path_inner(bin_path: &str) -> Option { + sysroot_candidates().iter() + .filter_map(|sysroot| { + let candidate = sysroot.join(bin_path).join(if cfg!(target_os = "windows") { + "rustc.exe" + } else { + "rustc" + }); + if candidate.exists() { + Some(candidate) + } else { + None + } + }) + .next() +} + +fn sysroot_candidates() -> Vec { let target = session::config::host_triple(); let mut sysroot_candidates = vec![filesearch::get_or_default_sysroot()]; - let path = current_dll_path() - .and_then(|s| s.canonicalize().ok()); + let path = current_dll_path().and_then(|s| s.canonicalize().ok()); if let Some(dll) = path { // use `parent` twice to chop off the file name and then also the // directory containing the dll which should be either `lib` or `bin`. @@ -327,69 +347,7 @@ pub fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box>() - .join("\n* "); - let err = format!("failed to find a `codegen-backends` folder \ - in the sysroot candidates:\n* {}", candidates); - early_error(ErrorOutputType::default(), &err); - }); - info!("probing {} for a codegen backend", sysroot.display()); - - let d = sysroot.read_dir().unwrap_or_else(|e| { - let err = format!("failed to load default codegen backend, couldn't \ - read `{}`: {}", sysroot.display(), e); - early_error(ErrorOutputType::default(), &err); - }); - - let mut file: Option = None; - - let expected_name = format!("rustc_codegen_llvm-{}", backend_name); - for entry in d.filter_map(|e| e.ok()) { - let path = entry.path(); - let filename = match path.file_name().and_then(|s| s.to_str()) { - Some(s) => s, - None => continue, - }; - if !(filename.starts_with(DLL_PREFIX) && filename.ends_with(DLL_SUFFIX)) { - continue - } - let name = &filename[DLL_PREFIX.len() .. filename.len() - DLL_SUFFIX.len()]; - if name != expected_name { - continue - } - if let Some(ref prev) = file { - let err = format!("duplicate codegen backends found\n\ - first: {}\n\ - second: {}\n\ - ", prev.display(), path.display()); - early_error(ErrorOutputType::default(), &err); - } - file = Some(path.clone()); - } - - match file { - Some(ref s) => return load_backend_from_dylib(s), - None => { - let err = format!("failed to load default codegen backend for `{}`, \ - no appropriate codegen dylib found in `{}`", - backend_name, sysroot.display()); - early_error(ErrorOutputType::default(), &err); - } - } + return sysroot_candidates; #[cfg(unix)] fn current_dll_path() -> Option { @@ -459,6 +417,85 @@ pub fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box fn() -> Box { + // For now we only allow this function to be called once as it'll dlopen a + // few things, which seems to work best if we only do that once. In + // general this assertion never trips due to the once guard in `get_codegen_backend`, + // but there's a few manual calls to this function in this file we protect + // against. + static LOADED: AtomicBool = AtomicBool::new(false); + assert!(!LOADED.fetch_or(true, Ordering::SeqCst), + "cannot load the default codegen backend twice"); + + let target = session::config::host_triple(); + let sysroot_candidates = sysroot_candidates(); + + let sysroot = sysroot_candidates.iter() + .map(|sysroot| { + let libdir = filesearch::relative_target_lib_path(&sysroot, &target); + sysroot.join(libdir).with_file_name( + option_env!("CFG_CODEGEN_BACKENDS_DIR").unwrap_or("codegen-backends")) + }) + .filter(|f| { + info!("codegen backend candidate: {}", f.display()); + f.exists() + }) + .next(); + let sysroot = sysroot.unwrap_or_else(|| { + let candidates = sysroot_candidates.iter() + .map(|p| p.display().to_string()) + .collect::>() + .join("\n* "); + let err = format!("failed to find a `codegen-backends` folder \ + in the sysroot candidates:\n* {}", candidates); + early_error(ErrorOutputType::default(), &err); + }); + info!("probing {} for a codegen backend", sysroot.display()); + + let d = sysroot.read_dir().unwrap_or_else(|e| { + let err = format!("failed to load default codegen backend, couldn't \ + read `{}`: {}", sysroot.display(), e); + early_error(ErrorOutputType::default(), &err); + }); + + let mut file: Option = None; + + let expected_name = format!("rustc_codegen_llvm-{}", backend_name); + for entry in d.filter_map(|e| e.ok()) { + let path = entry.path(); + let filename = match path.file_name().and_then(|s| s.to_str()) { + Some(s) => s, + None => continue, + }; + if !(filename.starts_with(DLL_PREFIX) && filename.ends_with(DLL_SUFFIX)) { + continue + } + let name = &filename[DLL_PREFIX.len() .. filename.len() - DLL_SUFFIX.len()]; + if name != expected_name { + continue + } + if let Some(ref prev) = file { + let err = format!("duplicate codegen backends found\n\ + first: {}\n\ + second: {}\n\ + ", prev.display(), path.display()); + early_error(ErrorOutputType::default(), &err); + } + file = Some(path.clone()); + } + + match file { + Some(ref s) => return load_backend_from_dylib(s), + None => { + let err = format!("failed to load default codegen backend for `{}`, \ + no appropriate codegen dylib found in `{}`", + backend_name, sysroot.display()); + early_error(ErrorOutputType::default(), &err); + } + } + +} + pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguator { use std::hash::Hasher; @@ -466,7 +503,7 @@ pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguat // into various other hashes quite a bit (symbol hashes, incr. comp. hashes, // debuginfo type IDs, etc), so we don't want it to be too wide. 128 bits // should still be safe enough to avoid collisions in practice. - let mut hasher = StableHasher::::new(); + let mut hasher = StableHasher::new(); let mut metadata = session.opts.cg.metadata.clone(); // We don't want the crate_disambiguator to dependent on the order @@ -492,7 +529,7 @@ pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguat .contains(&config::CrateType::Executable); hasher.write(if is_exe { b"exe" } else { b"lib" }); - CrateDisambiguator::from(hasher.finish()) + CrateDisambiguator::from(hasher.finish::()) } pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec { @@ -520,7 +557,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec ReplaceBodyWithLoop<'a> { fn should_ignore_fn(ret_ty: &ast::FnDecl) -> bool { if let ast::FunctionRetTy::Ty(ref ty) = ret_ty.output { fn involves_impl_trait(ty: &ast::Ty) -> bool { - match ty.node { + match ty.kind { ast::TyKind::ImplTrait(..) => true, ast::TyKind::Slice(ref subty) | ast::TyKind::Array(ref subty, _) | @@ -760,7 +797,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a> { } fn flat_map_trait_item(&mut self, i: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> { - let is_const = match i.node { + let is_const = match i.kind { ast::TraitItemKind::Const(..) => true, ast::TraitItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) => header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), @@ -770,7 +807,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a> { } fn flat_map_impl_item(&mut self, i: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> { - let is_const = match i.node { + let is_const = match i.kind { ast::ImplItemKind::Const(..) => true, ast::ImplItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) => header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), @@ -798,21 +835,21 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a> { fn block_to_stmt(b: ast::Block, sess: &Session) -> ast::Stmt { let expr = P(ast::Expr { id: sess.next_node_id(), - node: ast::ExprKind::Block(P(b), None), + kind: ast::ExprKind::Block(P(b), None), span: syntax_pos::DUMMY_SP, attrs: ThinVec::new(), }); ast::Stmt { id: sess.next_node_id(), - node: ast::StmtKind::Expr(expr), + kind: ast::StmtKind::Expr(expr), span: syntax_pos::DUMMY_SP, } } let empty_block = stmt_to_block(BlockCheckMode::Default, None, self.sess); let loop_expr = P(ast::Expr { - node: ast::ExprKind::Loop(P(empty_block), None), + kind: ast::ExprKind::Loop(P(empty_block), None), id: self.sess.next_node_id(), span: syntax_pos::DUMMY_SP, attrs: ThinVec::new(), @@ -821,7 +858,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a> { let loop_stmt = ast::Stmt { id: self.sess.next_node_id(), span: syntax_pos::DUMMY_SP, - node: ast::StmtKind::Expr(loop_expr), + kind: ast::StmtKind::Expr(loop_expr), }; if self.within_static_or_const { diff --git a/src/librustc_lexer/Cargo.toml b/src/librustc_lexer/Cargo.toml index 0dbcda618ecac..950771f0a6927 100644 --- a/src/librustc_lexer/Cargo.toml +++ b/src/librustc_lexer/Cargo.toml @@ -2,14 +2,20 @@ authors = ["The Rust Project Developers"] name = "rustc_lexer" version = "0.1.0" +license = "MIT OR Apache-2.0" edition = "2018" -# Note that this crate purposefully does not depend on other rustc crates -[dependencies] -unicode-xid = { version = "0.1.0", optional = true } +repository = "https://github.com/rust-lang/rust/" +description = """ +Rust lexer used by rustc. No stability guarantees are provided. +""" # Note: do not remove this blank `[lib]` section. # This will be used when publishing this crate as `rustc-ap-rustc_lexer`. [lib] doctest = false name = "rustc_lexer" + +# Note that this crate purposefully does not depend on other rustc crates +[dependencies] +unicode-xid = "0.2.0" diff --git a/src/librustc_lexer/src/lib.rs b/src/librustc_lexer/src/lib.rs index c02abe6b89f97..30a5175d8cdb0 100644 --- a/src/librustc_lexer/src/lib.rs +++ b/src/librustc_lexer/src/lib.rs @@ -1,6 +1,5 @@ -// We want to be able to build this crate with a stable compiler, so feature -// flags should be optional. -#![cfg_attr(not(feature = "unicode-xid"), feature(unicode_internals))] +// We want to be able to build this crate with a stable compiler, so no +// `#![feature]` attributes should be added. mod cursor; pub mod unescape; @@ -23,9 +22,6 @@ pub enum TokenKind { Lifetime { starts_with_number: bool }, Semi, Comma, - DotDotDot, - DotDotEq, - DotDot, Dot, OpenParen, CloseParen, @@ -37,41 +33,19 @@ pub enum TokenKind { Pound, Tilde, Question, - ColonColon, Colon, Dollar, - EqEq, Eq, - FatArrow, - Ne, Not, - Le, - LArrow, Lt, - ShlEq, - Shl, - Ge, Gt, - ShrEq, - Shr, - RArrow, Minus, - MinusEq, And, - AndAnd, - AndEq, Or, - OrOr, - OrEq, - PlusEq, Plus, - StarEq, Star, - SlashEq, Slash, - CaretEq, Caret, - PercentEq, Percent, Unknown, } @@ -128,6 +102,62 @@ pub fn tokenize(mut input: &str) -> impl Iterator + '_ { }) } +// See [UAX #31](http://unicode.org/reports/tr31) for definitions of these +// classes. + +/// True if `c` is considered a whitespace according to Rust language definition. +pub fn is_whitespace(c: char) -> bool { + // This is Pattern_White_Space. + // + // Note that this set is stable (ie, it doesn't change with different + // Unicode versions), so it's ok to just hard-code the values. + + match c { + // Usual ASCII suspects + | '\u{0009}' // \t + | '\u{000A}' // \n + | '\u{000B}' // vertical tab + | '\u{000C}' // form feed + | '\u{000D}' // \r + | '\u{0020}' // space + + // NEXT LINE from latin1 + | '\u{0085}' + + // Bidi markers + | '\u{200E}' // LEFT-TO-RIGHT MARK + | '\u{200F}' // RIGHT-TO-LEFT MARK + + // Dedicated whitespace characters from Unicode + | '\u{2028}' // LINE SEPARATOR + | '\u{2029}' // PARAGRAPH SEPARATOR + => true, + _ => false, + } +} + +/// True if `c` is valid as a first character of an identifier. +pub fn is_id_start(c: char) -> bool { + // This is XID_Start OR '_' (which formally is not a XID_Start). + // We also add fast-path for ascii idents + ('a' <= c && c <= 'z') + || ('A' <= c && c <= 'Z') + || c == '_' + || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_start(c)) +} + +/// True if `c` is valid as a non-first character of an identifier. +pub fn is_id_continue(c: char) -> bool { + // This is exactly XID_Continue. + // We also add fast-path for ascii idents + ('a' <= c && c <= 'z') + || ('A' <= c && c <= 'Z') + || ('0' <= c && c <= '9') + || c == '_' + || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_continue(c)) +} + + impl Cursor<'_> { fn advance_token(&mut self) -> Token { let first_char = self.bump().unwrap(); @@ -135,17 +165,11 @@ impl Cursor<'_> { '/' => match self.nth_char(0) { '/' => self.line_comment(), '*' => self.block_comment(), - _ => { - if self.eat_assign() { - SlashEq - } else { - Slash - } - } + _ => Slash, }, - c if character_properties::is_whitespace(c) => self.whitespace(), + c if is_whitespace(c) => self.whitespace(), 'r' => match (self.nth_char(0), self.nth_char(1)) { - ('#', c1) if character_properties::is_id_start(c1) => self.raw_ident(), + ('#', c1) if is_id_start(c1) => self.raw_ident(), ('#', _) | ('"', _) => { let (n_hashes, started, terminated) = self.raw_double_quoted_string(); let suffix_start = self.len_consumed(); @@ -190,7 +214,7 @@ impl Cursor<'_> { } _ => self.ident(), }, - c if character_properties::is_id_start(c) => self.ident(), + c if is_id_start(c) => self.ident(), c @ '0'..='9' => { let literal_kind = self.number(c); let suffix_start = self.len_consumed(); @@ -199,22 +223,7 @@ impl Cursor<'_> { } ';' => Semi, ',' => Comma, - '.' => { - if self.nth_char(0) == '.' { - self.bump(); - if self.nth_char(0) == '.' { - self.bump(); - DotDotDot - } else if self.nth_char(0) == '=' { - self.bump(); - DotDotEq - } else { - DotDot - } - } else { - Dot - } - } + '.' => Dot, '(' => OpenParen, ')' => CloseParen, '{' => OpenBrace, @@ -225,112 +234,19 @@ impl Cursor<'_> { '#' => Pound, '~' => Tilde, '?' => Question, - ':' => { - if self.nth_char(0) == ':' { - self.bump(); - ColonColon - } else { - Colon - } - } + ':' => Colon, '$' => Dollar, - '=' => { - if self.nth_char(0) == '=' { - self.bump(); - EqEq - } else if self.nth_char(0) == '>' { - self.bump(); - FatArrow - } else { - Eq - } - } - '!' => { - if self.nth_char(0) == '=' { - self.bump(); - Ne - } else { - Not - } - } - '<' => match self.nth_char(0) { - '=' => { - self.bump(); - Le - } - '<' => { - self.bump(); - if self.eat_assign() { ShlEq } else { Shl } - } - '-' => { - self.bump(); - LArrow - } - _ => Lt, - }, - '>' => match self.nth_char(0) { - '=' => { - self.bump(); - Ge - } - '>' => { - self.bump(); - if self.eat_assign() { ShrEq } else { Shr } - } - _ => Gt, - }, - '-' => { - if self.nth_char(0) == '>' { - self.bump(); - RArrow - } else { - if self.eat_assign() { MinusEq } else { Minus } - } - } - '&' => { - if self.nth_char(0) == '&' { - self.bump(); - AndAnd - } else { - if self.eat_assign() { AndEq } else { And } - } - } - '|' => { - if self.nth_char(0) == '|' { - self.bump(); - OrOr - } else { - if self.eat_assign() { OrEq } else { Or } - } - } - '+' => { - if self.eat_assign() { - PlusEq - } else { - Plus - } - } - '*' => { - if self.eat_assign() { - StarEq - } else { - Star - } - } - '^' => { - if self.eat_assign() { - CaretEq - } else { - Caret - } - } - '%' => { - if self.eat_assign() { - PercentEq - } else { - Percent - } - } + '=' => Eq, + '!' => Not, + '<' => Lt, + '>' => Gt, + '-' => Minus, + '&' => And, + '|' => Or, + '+' => Plus, + '*' => Star, + '^' => Caret, + '%' => Percent, '\'' => self.lifetime_or_char(), '"' => { let terminated = self.double_quoted_string(); @@ -352,7 +268,6 @@ impl Cursor<'_> { loop { match self.nth_char(0) { '\n' => break, - '\r' if self.nth_char(1) == '\n' => break, EOF_CHAR if self.is_eof() => break, _ => { self.bump(); @@ -387,8 +302,8 @@ impl Cursor<'_> { } fn whitespace(&mut self) -> TokenKind { - debug_assert!(character_properties::is_whitespace(self.prev())); - while character_properties::is_whitespace(self.nth_char(0)) { + debug_assert!(is_whitespace(self.prev())); + while is_whitespace(self.nth_char(0)) { self.bump(); } Whitespace @@ -398,19 +313,19 @@ impl Cursor<'_> { debug_assert!( self.prev() == 'r' && self.nth_char(0) == '#' - && character_properties::is_id_start(self.nth_char(1)) + && is_id_start(self.nth_char(1)) ); self.bump(); self.bump(); - while character_properties::is_id_continue(self.nth_char(0)) { + while is_id_continue(self.nth_char(0)) { self.bump(); } RawIdent } fn ident(&mut self) -> TokenKind { - debug_assert!(character_properties::is_id_start(self.prev())); - while character_properties::is_id_continue(self.nth_char(0)) { + debug_assert!(is_id_start(self.prev())); + while is_id_continue(self.nth_char(0)) { self.bump(); } Ident @@ -455,7 +370,7 @@ impl Cursor<'_> { // integer literal followed by field/method access or a range pattern // (`0..2` and `12.foo()`) '.' if self.nth_char(1) != '.' - && !character_properties::is_id_start(self.nth_char(1)) => + && !is_id_start(self.nth_char(1)) => { // might have stuff after the ., and if it does, it needs to start // with a number @@ -485,7 +400,7 @@ impl Cursor<'_> { fn lifetime_or_char(&mut self) -> TokenKind { debug_assert!(self.prev() == '\''); let mut starts_with_number = false; - if (character_properties::is_id_start(self.nth_char(0)) + if (is_id_start(self.nth_char(0)) || self.nth_char(0).is_digit(10) && { starts_with_number = true; true @@ -493,7 +408,7 @@ impl Cursor<'_> { && self.nth_char(1) != '\'' { self.bump(); - while character_properties::is_id_continue(self.nth_char(0)) { + while is_id_continue(self.nth_char(0)) { self.bump(); } @@ -525,7 +440,6 @@ impl Cursor<'_> { match self.nth_char(0) { '/' if !first => break, '\n' if self.nth_char(1) != '\'' => break, - '\r' if self.nth_char(1) == '\n' => break, EOF_CHAR if self.is_eof() => break, '\'' => { self.bump(); @@ -636,75 +550,13 @@ impl Cursor<'_> { } fn eat_literal_suffix(&mut self) { - if !character_properties::is_id_start(self.nth_char(0)) { + if !is_id_start(self.nth_char(0)) { return; } self.bump(); - while character_properties::is_id_continue(self.nth_char(0)) { + while is_id_continue(self.nth_char(0)) { self.bump(); } } - - fn eat_assign(&mut self) -> bool { - if self.nth_char(0) == '=' { - self.bump(); - true - } else { - false - } - } -} - -pub mod character_properties { - // this is Pattern_White_Space - #[cfg(feature = "unicode-xid")] - pub fn is_whitespace(c: char) -> bool { - match c { - '\u{0009}' | '\u{000A}' | '\u{000B}' | '\u{000C}' | '\u{000D}' | '\u{0020}' - | '\u{0085}' | '\u{200E}' | '\u{200F}' | '\u{2028}' | '\u{2029}' => true, - _ => false, - } - } - - #[cfg(not(feature = "unicode-xid"))] - pub fn is_whitespace(c: char) -> bool { - core::unicode::property::Pattern_White_Space(c) - } - - // this is XID_Start OR '_' (which formally is not a XID_Start) - #[cfg(feature = "unicode-xid")] - pub fn is_id_start(c: char) -> bool { - ('a' <= c && c <= 'z') - || ('A' <= c && c <= 'Z') - || c == '_' - || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_start(c)) - } - - #[cfg(not(feature = "unicode-xid"))] - pub fn is_id_start(c: char) -> bool { - ('a' <= c && c <= 'z') - || ('A' <= c && c <= 'Z') - || c == '_' - || (c > '\x7f' && c.is_xid_start()) - } - - // this is XID_Continue - #[cfg(feature = "unicode-xid")] - pub fn is_id_continue(c: char) -> bool { - ('a' <= c && c <= 'z') - || ('A' <= c && c <= 'Z') - || ('0' <= c && c <= '9') - || c == '_' - || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_continue(c)) - } - - #[cfg(not(feature = "unicode-xid"))] - pub fn is_id_continue(c: char) -> bool { - ('a' <= c && c <= 'z') - || ('A' <= c && c <= 'Z') - || ('0' <= c && c <= '9') - || c == '_' - || (c > '\x7f' && c.is_xid_continue()) - } } diff --git a/src/librustc_lexer/src/unescape.rs b/src/librustc_lexer/src/unescape.rs index d8e00d4c7c5ea..c709b7526082f 100644 --- a/src/librustc_lexer/src/unescape.rs +++ b/src/librustc_lexer/src/unescape.rs @@ -128,11 +128,7 @@ fn scan_escape(first_char: char, chars: &mut Chars<'_>, mode: Mode) -> Result Err(EscapeError::EscapeOnlyChar), - '\r' => Err(if chars.clone().next() == Some('\n') { - EscapeError::EscapeOnlyChar - } else { - EscapeError::BareCarriageReturn - }), + '\r' => Err(EscapeError::BareCarriageReturn), '\'' if mode.in_single_quotes() => Err(EscapeError::EscapeOnlyChar), '"' if mode.in_double_quotes() => Err(EscapeError::EscapeOnlyChar), _ => { @@ -244,27 +240,15 @@ where let unescaped_char = match first_char { '\\' => { - let (second_char, third_char) = { - let mut chars = chars.clone(); - (chars.next(), chars.next()) - }; - match (second_char, third_char) { - (Some('\n'), _) | (Some('\r'), Some('\n')) => { + let second_char = chars.clone().next(); + match second_char { + Some('\n') => { skip_ascii_whitespace(&mut chars); continue; } _ => scan_escape(first_char, &mut chars, mode), } } - '\r' => { - let second_char = chars.clone().next(); - if second_char == Some('\n') { - chars.next(); - Ok('\n') - } else { - scan_escape(first_char, &mut chars, mode) - } - } '\n' => Ok('\n'), '\t' => Ok('\t'), _ => scan_escape(first_char, &mut chars, mode), @@ -298,15 +282,11 @@ where while let Some(curr) = chars.next() { let start = initial_len - chars.as_str().len() - curr.len_utf8(); - let result = match (curr, chars.clone().next()) { - ('\r', Some('\n')) => { - chars.next(); - Ok('\n') - }, - ('\r', _) => Err(EscapeError::BareCarriageReturnInRawString), - (c, _) if mode.is_bytes() && !c.is_ascii() => + let result = match curr { + '\r' => Err(EscapeError::BareCarriageReturnInRawString), + c if mode.is_bytes() && !c.is_ascii() => Err(EscapeError::NonAsciiCharInByteString), - (c, _) => Ok(c), + c => Ok(c), }; let end = initial_len - chars.as_str().len(); diff --git a/src/librustc_lexer/src/unescape/tests.rs b/src/librustc_lexer/src/unescape/tests.rs index 496527eb265b0..e7b1ff6479d88 100644 --- a/src/librustc_lexer/src/unescape/tests.rs +++ b/src/librustc_lexer/src/unescape/tests.rs @@ -11,7 +11,6 @@ fn test_unescape_char_bad() { check(r"\", EscapeError::LoneSlash); check("\n", EscapeError::EscapeOnlyChar); - check("\r\n", EscapeError::EscapeOnlyChar); check("\t", EscapeError::EscapeOnlyChar); check("'", EscapeError::EscapeOnlyChar); check("\r", EscapeError::BareCarriageReturn); @@ -31,6 +30,7 @@ fn test_unescape_char_bad() { check(r"\v", EscapeError::InvalidEscape); check(r"\💩", EscapeError::InvalidEscape); check(r"\●", EscapeError::InvalidEscape); + check("\\\r", EscapeError::InvalidEscape); check(r"\x", EscapeError::TooShortHexEscape); check(r"\x0", EscapeError::TooShortHexEscape); @@ -116,10 +116,9 @@ fn test_unescape_str_good() { check("foo", "foo"); check("", ""); - check(" \t\n\r\n", " \t\n\n"); + check(" \t\n", " \t\n"); check("hello \\\n world", "hello world"); - check("hello \\\r\n world", "hello world"); check("thread's", "thread's") } @@ -134,7 +133,6 @@ fn test_unescape_byte_bad() { check(r"\", EscapeError::LoneSlash); check("\n", EscapeError::EscapeOnlyChar); - check("\r\n", EscapeError::EscapeOnlyChar); check("\t", EscapeError::EscapeOnlyChar); check("'", EscapeError::EscapeOnlyChar); check("\r", EscapeError::BareCarriageReturn); @@ -238,10 +236,9 @@ fn test_unescape_byte_str_good() { check("foo", b"foo"); check("", b""); - check(" \t\n\r\n", b" \t\n\n"); + check(" \t\n", b" \t\n"); check("hello \\\n world", b"hello world"); - check("hello \\\r\n world", b"hello world"); check("thread's", b"thread's") } @@ -253,7 +250,6 @@ fn test_unescape_raw_str() { assert_eq!(unescaped, expected); } - check("\r\n", &[(0..2, Ok('\n'))]); check("\r", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString))]); check("\rx", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString)), (1..2, Ok('x'))]); } @@ -266,7 +262,6 @@ fn test_unescape_raw_byte_str() { assert_eq!(unescaped, expected); } - check("\r\n", &[(0..2, Ok(byte_from_char('\n')))]); check("\r", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString))]); check("🦀", &[(0..4, Err(EscapeError::NonAsciiCharInByteString))]); check( diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index 041d0aaead913..a61a314d5492d 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -15,3 +15,4 @@ rustc_target = { path = "../librustc_target" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_index = { path = "../librustc_index" } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index c9153f285fff7..d0a7eab071c31 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -21,9 +21,11 @@ //! If you define a new `LateLintPass`, you will also need to add it to the //! `late_lint_methods!` invocation in `lib.rs`. +use std::fmt::Write; + use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt, layout::VariantIdx}; use rustc::{lint, util}; use hir::Node; use util::nodemap::HirIdSet; @@ -40,7 +42,7 @@ use syntax::source_map::Spanned; use syntax::edition::Edition; use syntax::feature_gate::{self, AttributeGate, AttributeType}; use syntax::feature_gate::{Stability, deprecated_attributes}; -use syntax_pos::{BytePos, Span, SyntaxContext}; +use syntax_pos::{BytePos, Span}; use syntax::symbol::{Symbol, kw, sym}; use syntax::errors::{Applicability, DiagnosticBuilder}; use syntax::print::pprust::expr_to_string; @@ -65,7 +67,7 @@ declare_lint_pass!(WhileTrue => [WHILE_TRUE]); /// Traverse through any amount of parenthesis and return the first non-parens expression. fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr { - while let ast::ExprKind::Paren(sub) = &expr.node { + while let ast::ExprKind::Paren(sub) = &expr.kind { expr = sub; } expr @@ -73,10 +75,10 @@ fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr { impl EarlyLintPass for WhileTrue { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - if let ast::ExprKind::While(cond, ..) = &e.node { - if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).node { - if let ast::LitKind::Bool(true) = lit.node { - if lit.span.ctxt() == SyntaxContext::empty() { + if let ast::ExprKind::While(cond, ..) = &e.kind { + if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind { + if let ast::LitKind::Bool(true) = lit.kind { + if !lit.span.from_expansion() { let msg = "denote infinite loops with `loop { ... }`"; let condition_span = cx.sess.source_map().def_span(e.span); cx.struct_span_lint(WHILE_TRUE, condition_span, msg) @@ -115,7 +117,7 @@ impl BoxPointers { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxPointers { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { - match it.node { + match it.kind { hir::ItemKind::Fn(..) | hir::ItemKind::TyAlias(..) | hir::ItemKind::Enum(..) | @@ -128,7 +130,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxPointers { } // If it's a struct, we also have to check the fields' types - match it.node { + match it.kind { hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => { for struct_field in struct_def.fields() { @@ -157,23 +159,23 @@ declare_lint_pass!(NonShorthandFieldPatterns => [NON_SHORTHAND_FIELD_PATTERNS]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonShorthandFieldPatterns { fn check_pat(&mut self, cx: &LateContext<'_, '_>, pat: &hir::Pat) { - if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.node { + if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.kind { let variant = cx.tables.pat_ty(pat).ty_adt_def() .expect("struct pattern type is not an ADT") .variant_of_res(cx.tables.qpath_res(qpath, pat.hir_id)); for fieldpat in field_pats { - if fieldpat.node.is_shorthand { + if fieldpat.is_shorthand { continue; } - if fieldpat.span.ctxt().outer_expn_info().is_some() { + if fieldpat.span.from_expansion() { // Don't lint if this is a macro expansion: macro authors // shouldn't have to worry about this kind of style issue // (Issue #49588) continue; } - if let PatKind::Binding(_, _, ident, None) = fieldpat.node.pat.node { + if let PatKind::Binding(_, _, ident, None) = fieldpat.pat.kind { if cx.tcx.find_field_index(ident, &variant) == - Some(cx.tcx.field_index(fieldpat.node.hir_id, cx.tables)) { + Some(cx.tcx.field_index(fieldpat.hir_id, cx.tables)) { let mut err = cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, &format!("the `{}:` in this pattern is redundant", ident)); @@ -222,7 +224,7 @@ impl EarlyLintPass for UnsafeCode { } fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - if let ast::ExprKind::Block(ref blk, _) = e.node { + if let ast::ExprKind::Block(ref blk, _) = e.kind { // Don't warn about generated blocks; that'll just pollute the output. if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) { self.report_unsafe(cx, blk.span, "usage of an `unsafe` block"); @@ -231,7 +233,7 @@ impl EarlyLintPass for UnsafeCode { } fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { - match it.node { + match it.kind { ast::ItemKind::Trait(_, ast::Unsafety::Unsafe, ..) => { self.report_unsafe(cx, it.span, "declaration of an `unsafe` trait") } @@ -266,7 +268,7 @@ impl EarlyLintPass for UnsafeCode { } fn check_trait_item(&mut self, cx: &EarlyContext<'_>, item: &ast::TraitItem) { - if let ast::TraitItemKind::Method(ref sig, None) = item.node { + if let ast::TraitItemKind::Method(ref sig, None) = item.kind { if sig.header.unsafety == ast::Unsafety::Unsafe { self.report_unsafe(cx, item.span, "declaration of an `unsafe` method") } @@ -389,7 +391,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { } fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { - let desc = match it.node { + let desc = match it.kind { hir::ItemKind::Fn(..) => "a function", hir::ItemKind::Mod(..) => "a module", hir::ItemKind::Enum(..) => "an enum", @@ -438,7 +440,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { return; } - let desc = match trait_item.node { + let desc = match trait_item.kind { hir::TraitItemKind::Const(..) => "an associated constant", hir::TraitItemKind::Method(..) => "a trait method", hir::TraitItemKind::Type(..) => "an associated type", @@ -457,7 +459,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { return; } - let desc = match impl_item.node { + let desc = match impl_item.kind { hir::ImplItemKind::Const(..) => "an associated constant", hir::ImplItemKind::Method(..) => "a method", hir::ImplItemKind::TyAlias(_) => "an associated type", @@ -480,10 +482,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { } } - fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant, _: &hir::Generics) { + fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant) { self.check_missing_docs_attrs(cx, - Some(v.node.id), - &v.node.attrs, + Some(v.id), + &v.attrs, v.span, "a variant"); } @@ -502,7 +504,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations { if !cx.access_levels.is_reachable(item.hir_id) { return; } - let (def, ty) = match item.node { + let (def, ty) = match item.kind { hir::ItemKind::Struct(_, ref ast_generics) => { if !ast_generics.params.is_empty() { return; @@ -561,14 +563,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations { return; } - match item.node { + match item.kind { hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {} _ => return, } - let debug = match cx.tcx.lang_items().debug_trait() { + let debug = match cx.tcx.get_diagnostic_item(sym::debug_trait) { Some(debug) => debug, None => return, }; @@ -609,10 +611,10 @@ declare_lint_pass!( impl EarlyLintPass for AnonymousParameters { fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::TraitItem) { - match it.node { + match it.kind { ast::TraitItemKind::Method(ref sig, _) => { for arg in sig.decl.inputs.iter() { - match arg.pat.node { + match arg.pat.kind { ast::PatKind::Ident(_, ident, None) => { if ident.name == kw::Invalid { let ty_snip = cx @@ -667,6 +669,22 @@ impl DeprecatedAttr { } } +fn lint_deprecated_attr( + cx: &EarlyContext<'_>, + attr: &ast::Attribute, + msg: &str, + suggestion: Option<&str>, +) { + cx.struct_span_lint(DEPRECATED, attr.span, &msg) + .span_suggestion_short( + attr.span, + suggestion.unwrap_or("remove this attribute"), + String::new(), + Applicability::MachineApplicable + ) + .emit(); +} + impl EarlyLintPass for DeprecatedAttr { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { for &&(n, _, _, ref g) in &self.depr_attrs { @@ -677,18 +695,15 @@ impl EarlyLintPass for DeprecatedAttr { _) = g { let msg = format!("use of deprecated attribute `{}`: {}. See {}", name, reason, link); - let mut err = cx.struct_span_lint(DEPRECATED, attr.span, &msg); - err.span_suggestion_short( - attr.span, - suggestion.unwrap_or("remove this attribute"), - String::new(), - Applicability::MachineApplicable - ); - err.emit(); + lint_deprecated_attr(cx, attr, &msg, suggestion); } return; } } + if attr.check_name(sym::no_start) || attr.check_name(sym::crate_id) { + let msg = format!("use of deprecated attribute `{}`: no longer used.", attr.path); + lint_deprecated_attr(cx, attr, &msg, None); + } } } @@ -751,13 +766,13 @@ impl UnusedDocComment { impl EarlyLintPass for UnusedDocComment { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { - if let ast::ItemKind::Mac(..) = item.node { + if let ast::ItemKind::Mac(..) = item.kind { self.warn_if_doc(cx, item.span, "macro expansions", true, &item.attrs); } } fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) { - let (kind, is_macro_expansion) = match stmt.node { + let (kind, is_macro_expansion) = match stmt.kind { ast::StmtKind::Local(..) => ("statements", false), ast::StmtKind::Item(..) => ("inner items", false), ast::StmtKind::Mac(..) => ("macro expansions", true), @@ -766,11 +781,11 @@ impl EarlyLintPass for UnusedDocComment { ast::StmtKind::Expr(..) => return, }; - self.warn_if_doc(cx, stmt.span, kind, is_macro_expansion, stmt.node.attrs()); + self.warn_if_doc(cx, stmt.span, kind, is_macro_expansion, stmt.kind.attrs()); } fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) { - let arm_span = arm.pats[0].span.with_hi(arm.body.span.hi()); + let arm_span = arm.pat.span.with_hi(arm.body.span.hi()); self.warn_if_doc(cx, arm_span, "match arms", false, &arm.attrs); } @@ -794,7 +809,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PluginAsLibrary { return; } - match it.node { + match it.kind { hir::ItemKind::ExternCrate(..) => (), _ => return, }; @@ -834,7 +849,7 @@ declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GEN impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { - match it.node { + match it.kind { hir::ItemKind::Fn(.., ref generics, _) => { if let Some(no_mangle_attr) = attr::find_by_name(&it.attrs, sym::no_mangle) { for param in &generics.params { @@ -903,7 +918,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \ consider instead using an UnsafeCell"; - match get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (&ty1.sty, &ty2.sty)) { + match get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (&ty1.kind, &ty2.kind)) { Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) => { if to_mt == hir::Mutability::MutMutable && from_mt == hir::Mutability::MutImmutable { @@ -917,7 +932,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { (cx: &LateContext<'a, 'tcx>, expr: &hir::Expr) -> Option<(Ty<'tcx>, Ty<'tcx>)> { - let def = if let hir::ExprKind::Path(ref qpath) = expr.node { + let def = if let hir::ExprKind::Path(ref qpath) = expr.kind { cx.tables.qpath_res(qpath, expr.hir_id) } else { return None; @@ -977,7 +992,7 @@ declare_lint_pass!( impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields { fn check_item(&mut self, ctx: &LateContext<'_, '_>, item: &hir::Item) { - if let hir::ItemKind::Union(ref vdata, _) = item.node { + if let hir::ItemKind::Union(ref vdata, _) = item.kind { for field in vdata.fields() { let field_ty = ctx.tcx.type_of( ctx.tcx.hir().local_def_id(field.hir_id)); @@ -1010,7 +1025,7 @@ impl UnreachablePub { let mut applicability = Applicability::MachineApplicable; match vis.node { hir::VisibilityKind::Public if !cx.access_levels.is_reachable(id) => { - if span.ctxt().outer_expn_info().is_some() { + if span.from_expansion() { applicability = Applicability::MaybeIncorrect; } let def_span = cx.tcx.sess.source_map().def_span(span); @@ -1075,7 +1090,7 @@ impl TypeAliasBounds { match *qpath { hir::QPath::TypeRelative(ref ty, _) => { // If this is a type variable, we found a `T::Assoc`. - match ty.node { + match ty.kind { hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => { match path.res { Res::Def(DefKind::TyParam, _) => true, @@ -1122,7 +1137,7 @@ impl TypeAliasBounds { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeAliasBounds { fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) { - let (ty, type_alias_generics) = match item.node { + let (ty, type_alias_generics) = match item.kind { hir::ItemKind::TyAlias(ref ty, ref generics) => (&*ty, generics), _ => return, }; @@ -1189,7 +1204,7 @@ fn check_const(cx: &LateContext<'_, '_>, body_id: hir::BodyId) { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedBrokenConst { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { - match it.node { + match it.kind { hir::ItemKind::Const(_, body_id) => { check_const(cx, body_id); }, @@ -1306,7 +1321,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { /// If `pat` is a `...` pattern, return the start and end of the range, as well as the span /// corresponding to the ellipsis. fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(&P, &P, Span)> { - match &pat.node { + match &pat.kind { PatKind::Range(a, b, Spanned { span, node: RangeEnd::Included(DotDotDot), .. }) => { Some((a, b, *span)) } @@ -1314,7 +1329,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { } } - let (parenthesise, endpoints) = match &pat.node { + let (parenthesise, endpoints) = match &pat.kind { PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(&subpat)), _ => (false, matches_ellipsis_pat(pat)), }; @@ -1380,7 +1395,7 @@ impl UnnameableTestItems { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnameableTestItems { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { if self.items_nameable { - if let hir::ItemKind::Mod(..) = it.node {} + if let hir::ItemKind::Mod(..) = it.kind {} else { self.items_nameable = false; self.boundary = it.hir_id; @@ -1491,7 +1506,7 @@ impl EarlyLintPass for KeywordIdents { self.check_tokens(cx, mac_def.stream()); } fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::Mac) { - self.check_tokens(cx, mac.node.tts.clone().into()); + self.check_tokens(cx, mac.tts.clone().into()); } fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: ast::Ident) { self.check_ident_token(cx, UnderMacro(false), ident); @@ -1669,7 +1684,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements { let def_id = cx.tcx.hir().local_def_id(item.hir_id); if let hir::ItemKind::Struct(_, ref hir_generics) | hir::ItemKind::Enum(_, ref hir_generics) - | hir::ItemKind::Union(_, ref hir_generics) = item.node + | hir::ItemKind::Union(_, ref hir_generics) = item.kind { let inferred_outlives = cx.tcx.inferred_outlives_of(def_id); if inferred_outlives.is_empty() { @@ -1735,7 +1750,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements { hir::WherePredicate::BoundPredicate(predicate) => { // FIXME we can also infer bounds on associated types, // and should check for them here. - match predicate.bounded_ty.node { + match predicate.bounded_ty.kind { hir::TyKind::Path(hir::QPath::Resolved( None, ref path, @@ -1797,7 +1812,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements { // generics, except for tuple struct, which have the `where` // after the fields of the struct. let full_where_span = if let hir::ItemKind::Struct(hir::VariantData::Tuple(..), _) - = item.node + = item.kind { where_span } else { @@ -1862,3 +1877,180 @@ impl EarlyLintPass for IncompleteFeatures { }); } } + +declare_lint! { + pub INVALID_VALUE, + Warn, + "an invalid value is being created (such as a NULL reference)" +} + +declare_lint_pass!(InvalidValue => [INVALID_VALUE]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &hir::Expr) { + + #[derive(Debug, Copy, Clone, PartialEq)] + enum InitKind { Zeroed, Uninit }; + + /// Information about why a type cannot be initialized this way. + /// Contains an error message and optionally a span to point at. + type InitError = (String, Option); + + /// Test if this constant is all-0. + fn is_zero(expr: &hir::Expr) -> bool { + use hir::ExprKind::*; + use syntax::ast::LitKind::*; + match &expr.kind { + Lit(lit) => + if let Int(i, _) = lit.node { + i == 0 + } else { + false + }, + Tup(tup) => + tup.iter().all(is_zero), + _ => + false + } + } + + /// Determine if this expression is a "dangerous initialization". + fn is_dangerous_init(cx: &LateContext<'_, '_>, expr: &hir::Expr) -> Option { + const ZEROED_PATH: &[Symbol] = &[sym::core, sym::mem, sym::zeroed]; + const UININIT_PATH: &[Symbol] = &[sym::core, sym::mem, sym::uninitialized]; + // `transmute` is inside an anonymous module (the `extern` block?); + // `Invalid` represents the empty string and matches that. + const TRANSMUTE_PATH: &[Symbol] = + &[sym::core, sym::intrinsics, kw::Invalid, sym::transmute]; + + if let hir::ExprKind::Call(ref path_expr, ref args) = expr.kind { + if let hir::ExprKind::Path(ref qpath) = path_expr.kind { + let def_id = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id()?; + + if cx.match_def_path(def_id, ZEROED_PATH) { + return Some(InitKind::Zeroed); + } + if cx.match_def_path(def_id, UININIT_PATH) { + return Some(InitKind::Uninit); + } + if cx.match_def_path(def_id, TRANSMUTE_PATH) { + if is_zero(&args[0]) { + return Some(InitKind::Zeroed); + } + } + // FIXME: Also detect `MaybeUninit::zeroed().assume_init()` and + // `MaybeUninit::uninit().assume_init()`. + } + } + + None + } + + /// Return `Some` only if we are sure this type does *not* + /// allow zero initialization. + fn ty_find_init_error<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + init: InitKind, + ) -> Option { + use rustc::ty::TyKind::*; + match ty.kind { + // Primitive types that don't like 0 as a value. + Ref(..) => Some((format!("References must be non-null"), None)), + Adt(..) if ty.is_box() => Some((format!("`Box` must be non-null"), None)), + FnPtr(..) => Some((format!("Function pointers must be non-null"), None)), + Never => Some((format!("The never type (`!`) has no valid value"), None)), + // Primitive types with other constraints. + Bool if init == InitKind::Uninit => + Some((format!("Booleans must be `true` or `false`"), None)), + Char if init == InitKind::Uninit => + Some((format!("Characters must be a valid unicode codepoint"), None)), + // Recurse and checks for some compound types. + Adt(adt_def, substs) if !adt_def.is_union() => { + // First check f this ADT has a layout attribute (like `NonNull` and friends). + use std::ops::Bound; + match tcx.layout_scalar_valid_range(adt_def.did) { + // We exploit here that `layout_scalar_valid_range` will never + // return `Bound::Excluded`. (And we have tests checking that we + // handle the attribute correctly.) + (Bound::Included(lo), _) if lo > 0 => + return Some((format!("{} must be non-null", ty), None)), + (Bound::Included(_), _) | (_, Bound::Included(_)) + if init == InitKind::Uninit => + return Some(( + format!("{} must be initialized inside its custom valid range", ty), + None, + )), + _ => {} + } + // Now, recurse. + match adt_def.variants.len() { + 0 => Some((format!("0-variant enums have no valid value"), None)), + 1 => { + // Struct, or enum with exactly one variant. + // Proceed recursively, check all fields. + let variant = &adt_def.variants[VariantIdx::from_u32(0)]; + variant.fields.iter().find_map(|field| { + ty_find_init_error( + tcx, + field.ty(tcx, substs), + init, + ).map(|(mut msg, span)| if span.is_none() { + // Point to this field, should be helpful for figuring + // out where the source of the error is. + let span = tcx.def_span(field.did); + write!(&mut msg, " (in this {} field)", adt_def.descr()) + .unwrap(); + (msg, Some(span)) + } else { + // Just forward. + (msg, span) + }) + }) + } + // Multi-variant enums are tricky: if all but one variant are + // uninhabited, we might actually do layout like for a single-variant + // enum, and then even leaving them uninitialized could be okay. + _ => None, // Conservative fallback for multi-variant enum. + } + } + Tuple(..) => { + // Proceed recursively, check all fields. + ty.tuple_fields().find_map(|field| ty_find_init_error(tcx, field, init)) + } + // Conservative fallback. + _ => None, + } + } + + if let Some(init) = is_dangerous_init(cx, expr) { + // This conjures an instance of a type out of nothing, + // using zeroed or uninitialized memory. + // We are extremely conservative with what we warn about. + let conjured_ty = cx.tables.expr_ty(expr); + if let Some((msg, span)) = ty_find_init_error(cx.tcx, conjured_ty, init) { + let mut err = cx.struct_span_lint( + INVALID_VALUE, + expr.span, + &format!( + "the type `{}` does not permit {}", + conjured_ty, + match init { + InitKind::Zeroed => "zero-initialization", + InitKind::Uninit => "being left uninitialized", + }, + ), + ); + err.span_label(expr.span, + "this code causes undefined behavior when executed"); + err.span_label(expr.span, "help: use `MaybeUninit` instead"); + if let Some(span) = span { + err.span_note(span, &msg); + } else { + err.note(&msg); + } + err.emit(); + } + } + } +} diff --git a/src/librustc_lint/error_codes.rs b/src/librustc_lint/error_codes.rs index d7c39b780bfdf..2edc8fadf4568 100644 --- a/src/librustc_lint/error_codes.rs +++ b/src/librustc_lint/error_codes.rs @@ -1,5 +1,4 @@ -use syntax::register_diagnostics; - -register_diagnostics! { - E0721, // `await` keyword +syntax::register_diagnostics! { +; +// E0721, // `await` keyword } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 78bc164ba1a0f..0e054013cd779 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -3,7 +3,7 @@ //! This currently only contains the definitions and implementations //! of most of the lints that `rustc` supports directly, it does not //! contain the infrastructure for defining/registering lints. That is -//! available in `rustc::lint` and `rustc_plugin` respectively. +//! available in `rustc::lint` and `rustc_driver::plugin` respectively. //! //! ## Note //! @@ -15,7 +15,6 @@ #![feature(box_patterns)] #![feature(box_syntax)] #![feature(nll)] -#![feature(rustc_diagnostic_macros)] #![recursion_limit="256"] @@ -24,6 +23,7 @@ extern crate rustc; mod error_codes; mod nonstandard_style; +mod redundant_semicolon; pub mod builtin; mod types; mod unused; @@ -55,6 +55,7 @@ use session::Session; use lint::LintId; use lint::FutureIncompatibleInfo; +use redundant_semicolon::*; use nonstandard_style::*; use builtin::*; use types::*; @@ -98,6 +99,7 @@ macro_rules! early_lint_passes { WhileTrue: WhileTrue, NonAsciiIdents: NonAsciiIdents, IncompleteFeatures: IncompleteFeatures, + RedundantSemicolon: RedundantSemicolon, ]); ) } @@ -177,6 +179,7 @@ macro_rules! late_lint_mod_passes { UnreachablePub: UnreachablePub, ExplicitOutlivesRequirements: ExplicitOutlivesRequirements, + InvalidValue: InvalidValue, ]); ) } @@ -432,7 +435,12 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(INDIRECT_STRUCTURAL_MATCH), reference: "issue #62411 ", edition: None, - } + }, + FutureIncompatibleInfo { + id: LintId::of(SOFT_UNSTABLE), + reference: "issue #64266 ", + edition: None, + }, ]); // Register renamed and removed lints. diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs index 8f7fe6680cb14..dceb79fd30985 100644 --- a/src/librustc_lint/nonstandard_style.rs +++ b/src/librustc_lint/nonstandard_style.rs @@ -136,7 +136,7 @@ impl EarlyLintPass for NonCamelCaseTypes { return; } - match it.node { + match it.kind { ast::ItemKind::TyAlias(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Struct(..) | @@ -146,8 +146,8 @@ impl EarlyLintPass for NonCamelCaseTypes { } } - fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &ast::Variant, _: &ast::Generics) { - self.check_case(cx, "variant", &v.node.ident); + fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &ast::Variant) { + self.check_case(cx, "variant", &v.ident); } fn check_generic_param(&mut self, cx: &EarlyContext<'_>, param: &ast::GenericParam) { @@ -258,7 +258,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { .and_then(|attr| attr.meta()) .and_then(|meta| { meta.name_value_literal().and_then(|lit| { - if let ast::LitKind::Str(name, ..) = lit.node { + if let ast::LitKind::Str(name, ..) = lit.kind { // Discard the double quotes surrounding the literal. let sp = cx.sess().source_map().span_to_snippet(lit.span) .ok() @@ -326,13 +326,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { } fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { - if let hir::ItemKind::Mod(_) = it.node { + if let hir::ItemKind::Mod(_) = it.kind { self.check_snake_case(cx, "module", &it.ident); } } fn check_trait_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::TraitItem) { - if let hir::TraitItemKind::Method(_, hir::TraitMethod::Required(pnames)) = &item.node { + if let hir::TraitItemKind::Method(_, hir::TraitMethod::Required(pnames)) = &item.kind { self.check_snake_case(cx, "trait method", &item.ident); for param_name in pnames { self.check_snake_case(cx, "variable", param_name); @@ -341,7 +341,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { } fn check_pat(&mut self, cx: &LateContext<'_, '_>, p: &hir::Pat) { - if let &PatKind::Binding(_, _, ident, _) = &p.node { + if let &PatKind::Binding(_, _, ident, _) = &p.kind { self.check_snake_case(cx, "variable", &ident); } } @@ -350,9 +350,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { &mut self, cx: &LateContext<'_, '_>, s: &hir::VariantData, - _: ast::Name, - _: &hir::Generics, - _: hir::HirId, ) { for sf in s.fields() { self.check_snake_case(cx, "structure field", &sf.ident); @@ -390,7 +387,7 @@ impl NonUpperCaseGlobals { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { - match it.node { + match it.kind { hir::ItemKind::Static(..) if !attr::contains_name(&it.attrs, sym::no_mangle) => { NonUpperCaseGlobals::check_upper_case(cx, "static variable", &it.ident); } @@ -402,20 +399,20 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { } fn check_trait_item(&mut self, cx: &LateContext<'_, '_>, ti: &hir::TraitItem) { - if let hir::TraitItemKind::Const(..) = ti.node { + if let hir::TraitItemKind::Const(..) = ti.kind { NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ti.ident); } } fn check_impl_item(&mut self, cx: &LateContext<'_, '_>, ii: &hir::ImplItem) { - if let hir::ImplItemKind::Const(..) = ii.node { + if let hir::ImplItemKind::Const(..) = ii.kind { NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ii.ident); } } fn check_pat(&mut self, cx: &LateContext<'_, '_>, p: &hir::Pat) { // Lint for constants that look like binding identifiers (#7526) - if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node { + if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.kind { if let Res::Def(DefKind::Const, _) = path.res { if path.segments.len() == 1 { NonUpperCaseGlobals::check_upper_case( diff --git a/src/librustc_lint/redundant_semicolon.rs b/src/librustc_lint/redundant_semicolon.rs new file mode 100644 index 0000000000000..0adf1eeb410b0 --- /dev/null +++ b/src/librustc_lint/redundant_semicolon.rs @@ -0,0 +1,52 @@ +use crate::lint::{EarlyLintPass, LintPass, EarlyContext, LintArray, LintContext}; +use syntax::ast::{Stmt, StmtKind, ExprKind}; +use syntax::errors::Applicability; + +declare_lint! { + pub REDUNDANT_SEMICOLON, + Warn, + "detects unnecessary trailing semicolons" +} + +declare_lint_pass!(RedundantSemicolon => [REDUNDANT_SEMICOLON]); + +impl EarlyLintPass for RedundantSemicolon { + fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &Stmt) { + if let StmtKind::Semi(expr) = &stmt.kind { + if let ExprKind::Tup(ref v) = &expr.kind { + if v.is_empty() { + // Strings of excess semicolons are encoded as empty tuple expressions + // during the parsing stage, so we check for empty tuple expressions + // which span only semicolons + if let Ok(source_str) = cx.sess().source_map().span_to_snippet(stmt.span) { + if source_str.chars().all(|c| c == ';') { + let multiple = (stmt.span.hi() - stmt.span.lo()).0 > 1; + let msg = if multiple { + "unnecessary trailing semicolons" + } else { + "unnecessary trailing semicolon" + }; + let mut err = cx.struct_span_lint( + REDUNDANT_SEMICOLON, + stmt.span, + &msg + ); + let suggest_msg = if multiple { + "remove these semicolons" + } else { + "remove this semicolon" + }; + err.span_suggestion( + stmt.span, + &suggest_msg, + String::new(), + Applicability::MaybeIncorrect + ); + err.emit(); + } + } + } + } + } + } +} diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index e86230437f277..aa6dfa50dddf3 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -7,7 +7,7 @@ use rustc::ty::subst::SubstsRef; use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; use rustc::ty::layout::{self, IntegerExt, LayoutOf, VariantIdx, SizeSkeleton}; use rustc::{lint, util}; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use util::nodemap::FxHashSet; use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; @@ -72,7 +72,7 @@ fn lint_overflowing_range_endpoint<'a, 'tcx>( ) -> bool { // We only want to handle exclusive (`..`) ranges, // which are represented as `ExprKind::Struct`. - if let ExprKind::Struct(_, eps, _) = &parent_expr.node { + if let ExprKind::Struct(_, eps, _) = &parent_expr.kind { if eps.len() != 2 { return false; } @@ -227,7 +227,7 @@ fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option { } } } - match t.sty { + match t.kind { ty::Int(i) => find_fit!(i, val, negative, I8 => [U8] => [I16, I32, I64, I128], I16 => [U16] => [I32, I64, I128], @@ -279,7 +279,7 @@ fn lint_int_literal<'a, 'tcx>( let par_id = cx.tcx.hir().get_parent_node(e.hir_id); if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) { - if let hir::ExprKind::Struct(..) = par_e.node { + if let hir::ExprKind::Struct(..) = par_e.kind { if is_range_literal(cx.sess(), par_e) && lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t) { @@ -318,9 +318,9 @@ fn lint_uint_literal<'a, 'tcx>( if lit_val < min || lit_val > max { let parent_id = cx.tcx.hir().get_parent_node(e.hir_id); if let Node::Expr(par_e) = cx.tcx.hir().get(parent_id) { - match par_e.node { + match par_e.kind { hir::ExprKind::Cast(..) => { - if let ty::Char = cx.tables.expr_ty(par_e).sty { + if let ty::Char = cx.tables.expr_ty(par_e).kind { let mut err = cx.struct_span_lint( OVERFLOWING_LITERALS, par_e.span, @@ -364,7 +364,7 @@ fn lint_literal<'a, 'tcx>( e: &'tcx hir::Expr, lit: &hir::Lit, ) { - match cx.tables.node_type(e.hir_id).sty { + match cx.tables.node_type(e.hir_id).kind { ty::Int(t) => { match lit.node { ast::LitKind::Int(v, ast::LitIntType::Signed(_)) | @@ -400,7 +400,7 @@ fn lint_literal<'a, 'tcx>( impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { - match e.node { + match e.kind { hir::ExprKind::Unary(hir::UnNeg, ref expr) => { // propagate negation, if the negation itself isn't negated if self.negated_expr_id != e.hir_id { @@ -445,7 +445,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { l: &hir::Expr, r: &hir::Expr) -> bool { - let (lit, expr, swap) = match (&l.node, &r.node) { + let (lit, expr, swap) = match (&l.kind, &r.kind) { (&hir::ExprKind::Lit(_), _) => (l, r, true), (_, &hir::ExprKind::Lit(_)) => (r, l, false), _ => return true, @@ -453,10 +453,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { // Normalize the binop so that the literal is always on the RHS in // the comparison let norm_binop = if swap { rev_binop(binop) } else { binop }; - match cx.tables.node_type(expr.hir_id).sty { + match cx.tables.node_type(expr.hir_id).kind { ty::Int(int_ty) => { let (min, max) = int_ty_range(int_ty); - let lit_val: i128 = match lit.node { + let lit_val: i128 = match lit.kind { hir::ExprKind::Lit(ref li) => { match li.node { ast::LitKind::Int(v, ast::LitIntType::Signed(_)) | @@ -470,7 +470,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { } ty::Uint(uint_ty) => { let (min, max) :(u128, u128) = uint_ty_range(uint_ty); - let lit_val: u128 = match lit.node { + let lit_val: u128 = match lit.kind { hir::ExprKind::Lit(ref li) => { match li.node { ast::LitKind::Int(v, _) => v, @@ -526,7 +526,7 @@ fn is_zst<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, ty: Ty<'tcx>) -> bool { } fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.sty { + match ty.kind { ty::FnPtr(_) => true, ty::Ref(..) => true, ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => { @@ -615,7 +615,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return FfiSafe; } - match ty.sty { + match ty.kind { ty::Adt(def, substs) => { if def.is_phantom_data() { return FfiPhantom(ty); @@ -624,16 +624,26 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { AdtKind::Struct => { if !def.repr.c() && !def.repr.transparent() { return FfiUnsafe { - ty: ty, + ty, reason: "this struct has unspecified layout", help: Some("consider adding a `#[repr(C)]` or \ `#[repr(transparent)]` attribute to this struct"), }; } + let is_non_exhaustive = + def.non_enum_variant().is_field_list_non_exhaustive(); + if is_non_exhaustive && !def.did.is_local() { + return FfiUnsafe { + ty, + reason: "this struct is non-exhaustive", + help: None, + }; + } + if def.non_enum_variant().fields.is_empty() { return FfiUnsafe { - ty: ty, + ty, reason: "this struct has no fields", help: Some("consider adding a member to this struct"), }; @@ -669,7 +679,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { AdtKind::Union => { if !def.repr.c() && !def.repr.transparent() { return FfiUnsafe { - ty: ty, + ty, reason: "this union has unspecified layout", help: Some("consider adding a `#[repr(C)]` or \ `#[repr(transparent)]` attribute to this union"), @@ -678,7 +688,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if def.non_enum_variant().fields.is_empty() { return FfiUnsafe { - ty: ty, + ty, reason: "this union has no fields", help: Some("consider adding a field to this union"), }; @@ -721,7 +731,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // Special-case types like `Option`. if !is_repr_nullable_ptr(cx, ty, def, substs) { return FfiUnsafe { - ty: ty, + ty, reason: "enum has no representation hint", help: Some("consider adding a `#[repr(C)]`, \ `#[repr(transparent)]`, or integer `#[repr(...)]` \ @@ -730,8 +740,25 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } + if def.is_variant_list_non_exhaustive() && !def.did.is_local() { + return FfiUnsafe { + ty, + reason: "this enum is non-exhaustive", + help: None, + }; + } + // Check the contained variants. for variant in &def.variants { + let is_non_exhaustive = variant.is_field_list_non_exhaustive(); + if is_non_exhaustive && !variant.def_id.is_local() { + return FfiUnsafe { + ty, + reason: "this enum has non-exhaustive variants", + help: None, + }; + } + for field in &variant.fields { let field_ty = cx.normalize_erasing_regions( ParamEnv::reveal_all(), @@ -750,7 +777,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } FfiPhantom(..) => { return FfiUnsafe { - ty: ty, + ty, reason: "this enum contains a PhantomData field", help: None, }; @@ -764,13 +791,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } ty::Char => FfiUnsafe { - ty: ty, + ty, reason: "the `char` type has no C equivalent", help: Some("consider using `u32` or `libc::wchar_t` instead"), }, ty::Int(ast::IntTy::I128) | ty::Uint(ast::UintTy::U128) => FfiUnsafe { - ty: ty, + ty, reason: "128-bit integers don't currently have a known stable ABI", help: None, }, @@ -779,25 +806,25 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe, ty::Slice(_) => FfiUnsafe { - ty: ty, + ty, reason: "slices have no C equivalent", help: Some("consider using a raw pointer instead"), }, ty::Dynamic(..) => FfiUnsafe { - ty: ty, + ty, reason: "trait objects have no C equivalent", help: None, }, ty::Str => FfiUnsafe { - ty: ty, + ty, reason: "string slices have no C equivalent", help: Some("consider using `*const u8` and a length instead"), }, ty::Tuple(..) => FfiUnsafe { - ty: ty, + ty, reason: "tuples have unspecified layout", help: Some("consider using a struct instead"), }, @@ -811,7 +838,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match sig.abi() { Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => { return FfiUnsafe { - ty: ty, + ty, reason: "this function pointer has Rust-specific calling convention", help: Some("consider using an `extern fn(...) -> ...` \ function pointer instead"), @@ -855,11 +882,76 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::UnnormalizedProjection(..) | ty::Projection(..) | ty::Opaque(..) | - ty::FnDef(..) => bug!("Unexpected type in foreign function"), + ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty), + } + } + + fn emit_ffi_unsafe_type_lint( + &mut self, + ty: Ty<'tcx>, + sp: Span, + note: &str, + help: Option<&str>, + ) { + let mut diag = self.cx.struct_span_lint( + IMPROPER_CTYPES, + sp, + &format!("`extern` block uses type `{}`, which is not FFI-safe", ty), + ); + diag.span_label(sp, "not FFI-safe"); + if let Some(help) = help { + diag.help(help); + } + diag.note(note); + if let ty::Adt(def, _) = ty.kind { + if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did) { + diag.span_note(sp, "type defined here"); + } + } + diag.emit(); + } + + fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { + use crate::rustc::ty::TypeFoldable; + + struct ProhibitOpaqueTypes<'tcx> { + ty: Option>, + }; + + impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'tcx> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + if let ty::Opaque(..) = ty.kind { + self.ty = Some(ty); + true + } else { + ty.super_visit_with(self) + } + } + } + + let mut visitor = ProhibitOpaqueTypes { ty: None }; + ty.visit_with(&mut visitor); + if let Some(ty) = visitor.ty { + self.emit_ffi_unsafe_type_lint( + ty, + sp, + "opaque types have no C equivalent", + None, + ); + true + } else { + false } } fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) { + // We have to check for opaque types before `normalize_erasing_regions`, + // which will replace opaque types with their underlying concrete type. + if self.check_for_opaque_ty(sp, ty) { + // We've already emitted an error due to an opaque type. + return; + } + // it is only OK to use this function because extern fns cannot have // any generic types right now: let ty = self.cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); @@ -867,24 +959,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match self.check_type_for_ffi(&mut FxHashSet::default(), ty) { FfiResult::FfiSafe => {} FfiResult::FfiPhantom(ty) => { - self.cx.span_lint(IMPROPER_CTYPES, - sp, - &format!("`extern` block uses type `{}` which is not FFI-safe: \ - composed only of PhantomData", ty)); + self.emit_ffi_unsafe_type_lint(ty, sp, "composed only of `PhantomData`", None); } - FfiResult::FfiUnsafe { ty: unsafe_ty, reason, help } => { - let msg = format!("`extern` block uses type `{}` which is not FFI-safe: {}", - unsafe_ty, reason); - let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg); - if let Some(s) = help { - diag.help(s); - } - if let ty::Adt(def, _) = unsafe_ty.sty { - if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did) { - diag.span_note(sp, "type defined here"); - } - } - diag.emit(); + FfiResult::FfiUnsafe { ty, reason, help } => { + self.emit_ffi_unsafe_type_lint(ty, sp, reason, help); } } } @@ -893,15 +971,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let def_id = self.cx.tcx.hir().local_def_id(id); let sig = self.cx.tcx.fn_sig(def_id); let sig = self.cx.tcx.erase_late_bound_regions(&sig); - let inputs = if sig.c_variadic { - // Don't include the spoofed `VaListImpl` in the functions list - // of inputs. - &sig.inputs()[..sig.inputs().len() - 1] - } else { - &sig.inputs()[..] - }; - for (input_ty, input_hir) in inputs.iter().zip(&decl.inputs) { + for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) { self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty); } @@ -924,8 +995,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes { fn check_foreign_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::ForeignItem) { let mut vis = ImproperCTypesVisitor { cx }; let abi = cx.tcx.hir().get_foreign_abi(it.hir_id); - if abi != Abi::RustIntrinsic && abi != Abi::PlatformIntrinsic { - match it.node { + if let Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi { + // Don't worry about types in internal ABIs. + } else { + match it.kind { hir::ForeignItemKind::Fn(ref decl, _, _) => { vis.check_foreign_fn(it.hir_id, decl); } @@ -942,7 +1015,7 @@ declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { - if let hir::ItemKind::Enum(ref enum_definition, _) = it.node { + if let hir::ItemKind::Enum(ref enum_definition, _) = it.kind { let item_def_id = cx.tcx.hir().local_def_id(it.hir_id); let t = cx.tcx.type_of(item_def_id); let ty = cx.tcx.erase_regions(&t); @@ -976,7 +1049,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { let bytes = variant_layout.size.bytes().saturating_sub(discr_size); debug!("- variant `{}` is {} bytes large", - variant.node.ident, + variant.ident, bytes); bytes }) diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 6a3dfdbe31684..3b3995832cb4c 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -9,7 +9,7 @@ use lint::{LintPass, EarlyLintPass, LateLintPass}; use syntax::ast; use syntax::attr; -use syntax::errors::Applicability; +use syntax::errors::{Applicability, pluralise}; use syntax::feature_gate::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use syntax::print::pprust; use syntax::symbol::{kw, sym}; @@ -38,23 +38,23 @@ declare_lint_pass!(UnusedResults => [UNUSED_MUST_USE, UNUSED_RESULTS]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { fn check_stmt(&mut self, cx: &LateContext<'_, '_>, s: &hir::Stmt) { - let expr = match s.node { + let expr = match s.kind { hir::StmtKind::Semi(ref expr) => &**expr, _ => return, }; - if let hir::ExprKind::Ret(..) = expr.node { + if let hir::ExprKind::Ret(..) = expr.kind { return; } let ty = cx.tables.expr_ty(&expr); - let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", false); + let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", 1); let mut fn_warned = false; let mut op_warned = false; - let maybe_def_id = match expr.node { + let maybe_def_id = match expr.kind { hir::ExprKind::Call(ref callee, _) => { - match callee.node { + match callee.kind { hir::ExprKind::Path(ref qpath) => { match cx.tables.qpath_res(qpath, callee.hir_id) { Res::Def(DefKind::Fn, def_id) @@ -80,7 +80,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { return; } - let must_use_op = match expr.node { + let must_use_op = match expr.kind { // Hardcoding operators here seemed more expedient than the // refactoring that would be needed to look up the `#[must_use]` // attribute which does exist on the comparison trait methods @@ -135,7 +135,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { span: Span, descr_pre: &str, descr_post: &str, - plural: bool, + plural_len: usize, ) -> bool { if ty.is_unit() || cx.tcx.is_ty_uninhabited_from( cx.tcx.hir().get_module_parent(expr.hir_id), ty) @@ -143,13 +143,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { return true; } - let plural_suffix = if plural { "s" } else { "" }; + let plural_suffix = pluralise!(plural_len); - match ty.sty { + match ty.kind { ty::Adt(..) if ty.is_box() => { let boxed_ty = ty.boxed_ty(); let descr_pre = &format!("{}boxed ", descr_pre); - check_must_use_ty(cx, boxed_ty, expr, span, descr_pre, descr_post, plural) + check_must_use_ty(cx, boxed_ty, expr, span, descr_pre, descr_post, plural_len) } ty::Adt(def, _) => { check_must_use_def(cx, def.did, span, descr_pre, descr_post) @@ -193,7 +193,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { } ty::Tuple(ref tys) => { let mut has_emitted = false; - let spans = if let hir::ExprKind::Tup(comps) = &expr.node { + let spans = if let hir::ExprKind::Tup(comps) = &expr.kind { debug_assert_eq!(comps.len(), tys.len()); comps.iter().map(|e| e.span).collect() } else { @@ -202,7 +202,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { for (i, ty) in tys.iter().map(|k| k.expect_ty()).enumerate() { let descr_post = &format!(" in tuple element {}", i); let span = *spans.get(i).unwrap_or(&span); - if check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, plural) { + if check_must_use_ty( + cx, + ty, + expr, + span, + descr_pre, + descr_post, + plural_len + ) { has_emitted = true; } } @@ -216,7 +224,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { descr_pre, plural_suffix, ); - check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, true) + check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, n as usize + 1) } // Otherwise, we don't lint, to avoid false positives. _ => false, @@ -261,8 +269,8 @@ declare_lint_pass!(PathStatements => [PATH_STATEMENTS]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathStatements { fn check_stmt(&mut self, cx: &LateContext<'_, '_>, s: &hir::Stmt) { - if let hir::StmtKind::Semi(ref expr) = s.node { - if let hir::ExprKind::Path(_) = expr.node { + if let hir::StmtKind::Semi(ref expr) = s.kind { + if let hir::ExprKind::Path(_) = expr.kind { cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect"); } } @@ -355,7 +363,7 @@ declare_lint_pass!(UnusedParens => [UNUSED_PARENS]); impl UnusedParens { fn is_expr_parens_necessary(inner: &ast::Expr, followed_by_block: bool) -> bool { - followed_by_block && match inner.node { + followed_by_block && match inner.kind { ast::ExprKind::Ret(_) | ast::ExprKind::Break(..) => true, _ => parser::contains_exterior_struct_lit(&inner), } @@ -368,9 +376,10 @@ impl UnusedParens { followed_by_block: bool, left_pos: Option, right_pos: Option) { - match value.node { + match value.kind { ast::ExprKind::Paren(ref inner) => { - if !Self::is_expr_parens_necessary(inner, followed_by_block) { + if !Self::is_expr_parens_necessary(inner, followed_by_block) && + value.attrs.is_empty() { let expr_text = if let Ok(snippet) = cx.sess().source_map() .span_to_snippet(value.span) { snippet @@ -398,18 +407,37 @@ impl UnusedParens { } } - fn check_unused_parens_pat(&self, - cx: &EarlyContext<'_>, - value: &ast::Pat, - msg: &str) { - if let ast::PatKind::Paren(_) = value.node { + fn check_unused_parens_pat( + &self, + cx: &EarlyContext<'_>, + value: &ast::Pat, + avoid_or: bool, + avoid_mut: bool, + ) { + use ast::{PatKind, BindingMode::ByValue, Mutability::Mutable}; + + if let PatKind::Paren(inner) = &value.kind { + match inner.kind { + // The lint visitor will visit each subpattern of `p`. We do not want to lint + // any range pattern no matter where it occurs in the pattern. For something like + // `&(a..=b)`, there is a recursive `check_pat` on `a` and `b`, but we will assume + // that if there are unnecessary parens they serve a purpose of readability. + PatKind::Range(..) => return, + // Avoid `p0 | .. | pn` if we should. + PatKind::Or(..) if avoid_or => return, + // Avoid `mut x` and `mut x @ p` if we should: + PatKind::Ident(ByValue(Mutable), ..) if avoid_mut => return, + // Otherwise proceed with linting. + _ => {} + } + let pattern_text = if let Ok(snippet) = cx.sess().source_map() .span_to_snippet(value.span) { snippet } else { pprust::pat_to_string(value) }; - Self::remove_outer_parens(cx, value.span, &pattern_text, msg, (false, false)); + Self::remove_outer_parens(cx, value.span, &pattern_text, "pattern", (false, false)); } } @@ -473,7 +501,12 @@ impl UnusedParens { impl EarlyLintPass for UnusedParens { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { use syntax::ast::ExprKind::*; - let (value, msg, followed_by_block, left_pos, right_pos) = match e.node { + let (value, msg, followed_by_block, left_pos, right_pos) = match e.kind { + Let(ref pat, ..) => { + self.check_unused_parens_pat(cx, pat, false, false); + return; + } + If(ref cond, ref block, ..) => { let left = e.span.lo() + syntax_pos::BytePos(2); let right = block.span.lo(); @@ -486,7 +519,8 @@ impl EarlyLintPass for UnusedParens { (cond, "`while` condition", true, Some(left), Some(right)) }, - ForLoop(_, ref cond, ref block, ..) => { + ForLoop(ref pat, ref cond, ref block, ..) => { + self.check_unused_parens_pat(cx, pat, false, false); (cond, "`for` head expression", true, None, Some(block.span.lo())) } @@ -517,9 +551,8 @@ impl EarlyLintPass for UnusedParens { // trigger in situations that macro authors shouldn't have to care about, e.g., // when a parenthesized token tree matched in one macro expansion is matched as // an expression in another and used as a fn/method argument (Issue #47775) - if e.span.ctxt().outer_expn_info() - .map_or(false, |info| info.call_site.ctxt().outer_expn_info().is_some()) { - return; + if e.span.ctxt().outer_expn_data().call_site.from_expansion() { + return; } let msg = format!("{} argument", call_kind); for arg in args_to_check { @@ -532,26 +565,44 @@ impl EarlyLintPass for UnusedParens { } fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) { - use ast::PatKind::{Paren, Range}; - // The lint visitor will visit each subpattern of `p`. We do not want to lint any range - // pattern no matter where it occurs in the pattern. For something like `&(a..=b)`, there - // is a recursive `check_pat` on `a` and `b`, but we will assume that if there are - // unnecessary parens they serve a purpose of readability. - if let Paren(ref pat) = p.node { - match pat.node { - Range(..) => {} - _ => self.check_unused_parens_pat(cx, &p, "pattern") - } + use ast::{PatKind::*, Mutability}; + match &p.kind { + // Do not lint on `(..)` as that will result in the other arms being useless. + Paren(_) + // The other cases do not contain sub-patterns. + | Wild | Rest | Lit(..) | Mac(..) | Range(..) | Ident(.., None) | Path(..) => return, + // These are list-like patterns; parens can always be removed. + TupleStruct(_, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps { + self.check_unused_parens_pat(cx, p, false, false); + }, + Struct(_, fps, _) => for f in fps { + self.check_unused_parens_pat(cx, &f.pat, false, false); + }, + // Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106. + Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false), + // Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342. + // Also avoid linting on `& mut? (p0 | .. | pn)`, #64106. + Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Immutable), } } fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) { - if let ast::StmtKind::Local(ref local) = s.node { + if let ast::StmtKind::Local(ref local) = s.kind { + self.check_unused_parens_pat(cx, &local.pat, false, false); + if let Some(ref value) = local.init { self.check_unused_parens_expr(cx, &value, "assigned value", false, None, None); } } } + + fn check_param(&mut self, cx: &EarlyContext<'_>, param: &ast::Param) { + self.check_unused_parens_pat(cx, ¶m.pat, true, false); + } + + fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) { + self.check_unused_parens_pat(cx, &arm.pat, false, false); + } } declare_lint! { @@ -576,24 +627,19 @@ impl UnusedImportBraces { } // Trigger the lint if the nested item is a non-self single item - let node_ident; - match items[0].0.kind { + let node_name = match items[0].0.kind { ast::UseTreeKind::Simple(rename, ..) => { let orig_ident = items[0].0.prefix.segments.last().unwrap().ident; if orig_ident.name == kw::SelfLower { return; } - node_ident = rename.unwrap_or(orig_ident); + rename.unwrap_or(orig_ident).name } - ast::UseTreeKind::Glob => { - node_ident = ast::Ident::from_str("*"); - } - ast::UseTreeKind::Nested(_) => { - return; - } - } + ast::UseTreeKind::Glob => Symbol::intern("*"), + ast::UseTreeKind::Nested(_) => return, + }; - let msg = format!("braces around {} is unnecessary", node_ident.name); + let msg = format!("braces around {} is unnecessary", node_name); cx.span_lint(UNUSED_IMPORT_BRACES, item.span, &msg); } } @@ -601,7 +647,7 @@ impl UnusedImportBraces { impl EarlyLintPass for UnusedImportBraces { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { - if let ast::ItemKind::Use(ref use_tree) = item.node { + if let ast::ItemKind::Use(ref use_tree) = item.kind { self.check_use_tree(cx, use_tree, item); } } @@ -617,7 +663,7 @@ declare_lint_pass!(UnusedAllocation => [UNUSED_ALLOCATION]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation { fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr) { - match e.node { + match e.kind { hir::ExprKind::Box(_) => {} _ => return, } diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 16cdbb7dd4d39..62a3757757b80 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -54,7 +54,7 @@ fn main() { // LLVM are compiled the same way, but for us that's typically the case. // // We *want* detect this cross compiling situation by asking llvm-config - // what it's host-target is. If that's not the TARGET, then we're cross + // what its host-target is. If that's not the TARGET, then we're cross // compiling. Unfortunately `llvm-config` seems either be buggy, or we're // misconfiguring it, because the `i686-pc-windows-gnu` build of LLVM will // report itself with a `--host-target` of `x86_64-pc-windows-gnu`. This @@ -62,7 +62,7 @@ fn main() { // havoc ensues. // // In any case, if we're cross compiling, this generally just means that we - // can't trust all the output of llvm-config becaues it might be targeted + // can't trust all the output of llvm-config because it might be targeted // for the host rather than the target. As a result a bunch of blocks below // are gated on `if !is_crossed` let target = env::var("TARGET").expect("TARGET was not set"); @@ -151,6 +151,10 @@ fn main() { cfg.define("LLVM_RUSTLLVM", None); } + if env::var_os("LLVM_NDEBUG").is_some() { + cfg.define("NDEBUG", None); + } + build_helper::rerun_if_changed_anything_in_dir(Path::new("../rustllvm")); cfg.file("../rustllvm/PassWrapper.cpp") .file("../rustllvm/RustWrapper.cpp") @@ -162,7 +166,7 @@ fn main() { let (llvm_kind, llvm_link_arg) = detect_llvm_link(); - // Link in all LLVM libraries, if we're uwring the "wrong" llvm-config then + // Link in all LLVM libraries, if we're using the "wrong" llvm-config then // we don't pick up system libs because unfortunately they're for the host // of llvm-config, not the target that we're attempting to link. let mut cmd = Command::new(&llvm_config); @@ -250,8 +254,11 @@ fn main() { let llvm_use_libcxx = env::var_os("LLVM_USE_LIBCXX"); let stdcppname = if target.contains("openbsd") { - // llvm-config on OpenBSD doesn't mention stdlib=libc++ - "c++" + if target.contains("sparc64") { + "estdc++" + } else { + "c++" + } } else if target.contains("freebsd") { "c++" } else if target.contains("darwin") { diff --git a/src/librustc_lsan/build.rs b/src/librustc_lsan/build.rs index b8c7b7c2d5537..73720d8c2d64e 100644 --- a/src/librustc_lsan/build.rs +++ b/src/librustc_lsan/build.rs @@ -4,6 +4,10 @@ use build_helper::sanitizer_lib_boilerplate; use cmake::Config; fn main() { + println!("cargo:rerun-if-env-changed=RUSTC_BUILD_SANITIZERS"); + if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) { + return; + } if let Some(llvm_config) = env::var_os("LLVM_CONFIG") { build_helper::restore_library_path(); diff --git a/src/librustc_macros/Cargo.toml b/src/librustc_macros/Cargo.toml index f989ebc6dfd8e..c28fcb1a395ff 100644 --- a/src/librustc_macros/Cargo.toml +++ b/src/librustc_macros/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" proc-macro = true [dependencies] -synstructure = "0.10.2" -syn = { version = "0.15.22", features = ["full"] } -proc-macro2 = "0.4.24" -quote = "0.6.10" +synstructure = "0.12.1" +syn = { version = "1", features = ["full"] } +proc-macro2 = "1" +quote = "1" itertools = "0.8" diff --git a/src/librustc_macros/src/hash_stable.rs b/src/librustc_macros/src/hash_stable.rs index 6d7590c7d1cd3..735cfb11b365c 100644 --- a/src/librustc_macros/src/hash_stable.rs +++ b/src/librustc_macros/src/hash_stable.rs @@ -15,22 +15,22 @@ fn parse_attributes(field: &syn::Field) -> Attributes { }; for attr in &field.attrs { if let Ok(meta) = attr.parse_meta() { - if &meta.name().to_string() != "stable_hasher" { + if !meta.path().is_ident("stable_hasher") { continue; } let mut any_attr = false; if let Meta::List(list) = meta { for nested in list.nested.iter() { if let NestedMeta::Meta(meta) = nested { - if &meta.name().to_string() == "ignore" { + if meta.path().is_ident("ignore") { attrs.ignore = true; any_attr = true; } - if &meta.name().to_string() == "project" { + if meta.path().is_ident("project") { if let Meta::List(list) = meta { if let Some(nested) = list.nested.iter().next() { if let NestedMeta::Meta(meta) = nested { - attrs.project = Some(meta.name()); + attrs.project = meta.path().get_ident().cloned(); any_attr = true; } } @@ -76,10 +76,10 @@ pub fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::To s.bound_impl(quote!(::rustc_data_structures::stable_hasher::HashStable <::rustc::ich::StableHashingContext<'__ctx>>), quote!{ - fn hash_stable<__W: ::rustc_data_structures::stable_hasher::StableHasherResult>( + fn hash_stable( &self, __hcx: &mut ::rustc::ich::StableHashingContext<'__ctx>, - __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<__W>) { + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { #discriminant match *self { #body } } diff --git a/src/librustc_macros/src/lib.rs b/src/librustc_macros/src/lib.rs index 85e2247ebd7e3..0540c95d3ded3 100644 --- a/src/librustc_macros/src/lib.rs +++ b/src/librustc_macros/src/lib.rs @@ -1,5 +1,4 @@ -#![feature(proc_macro_hygiene)] -#![cfg_attr(not(bootstrap), allow(rustc::default_hash_types))] +#![allow(rustc::default_hash_types)] #![recursion_limit="128"] diff --git a/src/librustc_macros/src/query.rs b/src/librustc_macros/src/query.rs index a8df7e197a8c9..139e1b554cf90 100644 --- a/src/librustc_macros/src/query.rs +++ b/src/librustc_macros/src/query.rs @@ -442,8 +442,8 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { .map(|c| c.is_green()) .unwrap_or(false)); - let key = RecoverKey::recover(tcx.global_tcx(), self).unwrap(); - if queries::#name::cache_on_disk(tcx.global_tcx(), key, None) { + let key = RecoverKey::recover(tcx, self).unwrap(); + if queries::#name::cache_on_disk(tcx, key, None) { let _ = tcx.#name(key); } } @@ -495,7 +495,11 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { dep_node_force_stream.extend(quote! { DepKind::#name => { if let Some(key) = RecoverKey::recover($tcx, $dep_node) { - force_ex!($tcx, #name, key); + $tcx.force_query::>( + key, + DUMMY_SP, + *$dep_node + ); } else { return false; } diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 5ff60a9267bad..032470e1400ab 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -18,6 +18,7 @@ rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } errors = { path = "../librustc_errors", package = "rustc_errors" } rustc_target = { path = "../librustc_target" } +rustc_index = { path = "../librustc_index" } rustc_serialize = { path = "../libserialize", package = "serialize" } stable_deref_trait = "1.0.0" syntax = { path = "../libsyntax" } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index d5f1e715186f4..042252bc13e61 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -2,8 +2,7 @@ use crate::cstore::{self, CStore, CrateSource, MetadataBlob}; use crate::locator::{self, CratePaths}; -use crate::decoder::proc_macro_def_path_table; -use crate::schema::CrateRoot; +use crate::schema::{CrateRoot, CrateDep}; use rustc_data_structures::sync::{Lrc, RwLock, Lock}; use rustc::hir::def_id::CrateNum; @@ -18,19 +17,20 @@ use rustc::middle::cstore::{ExternCrate, ExternCrateSource}; use rustc::util::common::record_time; use rustc::util::nodemap::FxHashSet; use rustc::hir::map::Definitions; +use rustc::hir::def_id::LOCAL_CRATE; use std::ops::Deref; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::{cmp, fs}; use syntax::ast; use syntax::attr; use syntax::ext::allocator::{global_allocator_spans, AllocatorKind}; -use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind}; use syntax::symbol::{Symbol, sym}; use syntax::{span_err, span_fatal}; use syntax_pos::{Span, DUMMY_SP}; use log::{debug, info, log_enabled}; +use proc_macro::bridge::client::ProcMacro; pub struct Library { pub dylib: Option<(PathBuf, PathKind)>, @@ -112,7 +112,7 @@ impl<'a> CrateLoader<'a> { -> Option { let mut ret = None; self.cstore.iter_crate_data(|cnum, data| { - if data.name != name { return } + if data.root.name != name { return } match hash { Some(hash) if *hash == data.root.hash => { ret = Some(cnum); return } @@ -190,8 +190,7 @@ impl<'a> CrateLoader<'a> { fn register_crate( &mut self, host_lib: Option, - root: &Option, - ident: Symbol, + root: Option<&CratePaths>, span: Span, lib: Library, dep_kind: DepKind, @@ -204,51 +203,40 @@ impl<'a> CrateLoader<'a> { .map(|e| e.is_private_dep) .unwrap_or(false); - info!("register crate `extern crate {} as {}` (private_dep = {})", - crate_root.name, ident, private_dep); - + info!("register crate `{}` (private_dep = {})", crate_root.name, private_dep); // Claim this crate number and cache it let cnum = self.cstore.alloc_new_crate_num(); + // Maintain a reference to the top most crate. // Stash paths for top-most crate locally if necessary. - let crate_paths = if root.is_none() { - Some(CratePaths { - ident: ident.to_string(), + let crate_paths; + let root = if let Some(root) = root { + root + } else { + crate_paths = CratePaths { + ident: crate_root.name.to_string(), dylib: lib.dylib.clone().map(|p| p.0), rlib: lib.rlib.clone().map(|p| p.0), rmeta: lib.rmeta.clone().map(|p| p.0), - }) - } else { - None + }; + &crate_paths }; - // Maintain a reference to the top most crate. - let root = if root.is_some() { root } else { &crate_paths }; let Library { dylib, rlib, rmeta, metadata } = lib; let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind); let dependencies: Vec = cnum_map.iter().cloned().collect(); - let proc_macros = crate_root.proc_macro_decls_static.map(|_| { - if self.sess.opts.debugging_opts.dual_proc_macros { - let host_lib = host_lib.unwrap(); - self.load_derive_macros( - &host_lib.metadata.get_root(), - host_lib.dylib.map(|p| p.0), - span - ) - } else { - self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span) - } - }); - - let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || { - if let Some(proc_macros) = &proc_macros { - proc_macro_def_path_table(&crate_root, proc_macros) - } else { - crate_root.def_path_table.decode((&metadata, self.sess)) - } + let raw_proc_macros = crate_root.proc_macro_data.map(|_| { + let temp_root; + let (dlsym_dylib, dlsym_root) = match &host_lib { + Some(host_lib) => + (&host_lib.dylib, { temp_root = host_lib.metadata.get_root(); &temp_root }), + None => (&dylib, &crate_root), + }; + let dlsym_dylib = dlsym_dylib.as_ref().expect("no dylib for a proc-macro crate"); + self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.disambiguator, span) }); let interpret_alloc_index: Vec = crate_root.interpret_alloc_index @@ -260,13 +248,14 @@ impl<'a> CrateLoader<'a> { .map(|trait_impls| (trait_impls.trait_id, trait_impls.impls)) .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)) + }); + let cmeta = cstore::CrateMetadata { - name: crate_root.name, - imported_name: ident, extern_crate: Lock::new(None), def_path_table: Lrc::new(def_path_table), trait_impls, - proc_macros, root: crate_root, blob: metadata, cnum_map, @@ -280,7 +269,9 @@ impl<'a> CrateLoader<'a> { rlib, rmeta, }, - private_dep + private_dep, + span, + raw_proc_macros }; let cmeta = Lrc::new(cmeta); @@ -345,16 +336,27 @@ impl<'a> CrateLoader<'a> { fn resolve_crate<'b>( &'b mut self, - root: &'b Option, - ident: Symbol, name: Symbol, - hash: Option<&'b Svh>, - extra_filename: Option<&'b str>, span: Span, - path_kind: PathKind, + dep_kind: DepKind, + dep: Option<(&'b CratePaths, &'b CrateDep)>, + ) -> (CrateNum, Lrc) { + self.maybe_resolve_crate(name, span, dep_kind, dep).unwrap_or_else(|err| err.report()) + } + + fn maybe_resolve_crate<'b>( + &'b mut self, + name: Symbol, + span: Span, mut dep_kind: DepKind, + dep: Option<(&'b CratePaths, &'b CrateDep)>, ) -> Result<(CrateNum, Lrc), LoadError<'b>> { - info!("resolving crate `extern crate {} as {}`", name, ident); + info!("resolving crate `{}`", name); + let (root, hash, extra_filename, path_kind) = match dep { + Some((root, dep)) => + (Some(root), Some(&dep.hash), Some(&dep.extra_filename[..]), PathKind::Dependency), + None => (None, None, None, PathKind::Crate), + }; let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) { (LoadResult::Previous(cnum), None) } else { @@ -362,7 +364,6 @@ impl<'a> CrateLoader<'a> { let mut locate_ctxt = locator::Context { sess: self.sess, span, - ident, crate_name: name, hash, extra_filename, @@ -389,7 +390,7 @@ impl<'a> CrateLoader<'a> { match result { (LoadResult::Previous(cnum), None) => { let data = self.cstore.get_crate_data(cnum); - if data.root.proc_macro_decls_static.is_some() { + if data.root.proc_macro_data.is_some() { dep_kind = DepKind::UnexportedMacrosOnly; } data.dep_kind.with_lock(|data_dep_kind| { @@ -398,7 +399,7 @@ impl<'a> CrateLoader<'a> { Ok((cnum, data)) } (LoadResult::Loaded(library), host_library) => { - Ok(self.register_crate(host_library, root, ident, span, library, dep_kind, name)) + Ok(self.register_crate(host_library, root, span, library, dep_kind, name)) } _ => panic!() } @@ -436,7 +437,7 @@ impl<'a> CrateLoader<'a> { mut extern_crate: ExternCrate, visited: &mut FxHashSet<(CrateNum, bool)>) { - if !visited.insert((cnum, extern_crate.direct)) { return } + if !visited.insert((cnum, extern_crate.is_direct())) { return } let cmeta = self.cstore.get_crate_data(cnum); let mut old_extern_crate = cmeta.extern_crate.borrow_mut(); @@ -447,14 +448,14 @@ impl<'a> CrateLoader<'a> { // - shorter paths to longer (tuple.2). let new_rank = ( true, - extern_crate.direct, + extern_crate.is_direct(), cmp::Reverse(extern_crate.path_len), ); let old_rank = match *old_extern_crate { None => (false, false, cmp::Reverse(usize::max_value())), Some(ref c) => ( true, - c.direct, + c.is_direct(), cmp::Reverse(c.path_len), ), }; @@ -466,7 +467,7 @@ impl<'a> CrateLoader<'a> { drop(old_extern_crate); // Propagate the extern crate info to dependencies. - extern_crate.direct = false; + extern_crate.dependency_of = cnum; for &dep_cnum in cmeta.dependencies.borrow().iter() { self.update_extern_crate(dep_cnum, extern_crate, visited); } @@ -474,7 +475,7 @@ impl<'a> CrateLoader<'a> { // Go through the crate metadata and load any crates that it references fn resolve_crate_deps(&mut self, - root: &Option, + root: &CratePaths, crate_root: &CrateRoot<'_>, metadata: &MetadataBlob, krate: CrateNum, @@ -482,16 +483,14 @@ impl<'a> CrateLoader<'a> { dep_kind: DepKind) -> cstore::CrateNumMap { debug!("resolving deps of external crate"); - if crate_root.proc_macro_decls_static.is_some() { + if crate_root.proc_macro_data.is_some() { return cstore::CrateNumMap::new(); } // The map from crate numbers in the crate we're resolving to local crate numbers. // We map 0 and all other holes in the map to our parent crate. The "additional" // self-dependencies should be harmless. - std::iter::once(krate).chain(crate_root.crate_deps - .decode(metadata) - .map(|dep| { + std::iter::once(krate).chain(crate_root.crate_deps.decode(metadata).map(|dep| { info!("resolving dep crate {} hash: `{}` extra filename: `{}`", dep.name, dep.hash, dep.extra_filename); if dep.kind == DepKind::UnexportedMacrosOnly { @@ -501,17 +500,12 @@ impl<'a> CrateLoader<'a> { DepKind::MacrosOnly => DepKind::MacrosOnly, _ => dep.kind, }; - let (local_cnum, ..) = self.resolve_crate( - root, dep.name, dep.name, Some(&dep.hash), Some(&dep.extra_filename), span, - PathKind::Dependency, dep_kind, - ).unwrap_or_else(|err| err.report()); - local_cnum + self.resolve_crate(dep.name, span, dep_kind, Some((root, &dep))).0 })).collect() } - fn read_extension_crate(&mut self, span: Span, orig_name: Symbol, rename: Symbol) - -> ExtensionCrate { - info!("read extension crate `extern crate {} as {}`", orig_name, rename); + fn read_extension_crate(&mut self, name: Symbol, span: Span) -> ExtensionCrate { + info!("read extension crate `{}`", name); let target_triple = self.sess.opts.target_triple.clone(); let host_triple = TargetTriple::from_triple(config::host_triple()); let is_cross = target_triple != host_triple; @@ -519,14 +513,13 @@ impl<'a> CrateLoader<'a> { let mut locate_ctxt = locator::Context { sess: self.sess, span, - ident: orig_name, - crate_name: rename, + crate_name: name, hash: None, extra_filename: None, filesearch: self.sess.host_filesearch(PathKind::Crate), target: &self.sess.host, triple: host_triple, - root: &None, + root: None, rejected_via_hash: vec![], rejected_via_triple: vec![], rejected_via_kind: vec![], @@ -574,24 +567,14 @@ impl<'a> CrateLoader<'a> { } } - /// Loads custom derive macros. - /// - /// Note that this is intentionally similar to how we load plugins today, - /// but also intentionally separate. Plugins are likely always going to be - /// implemented as dynamic libraries, but we have a possible future where - /// custom derive (and other macro-1.1 style features) are implemented via - /// executables and custom IPC. - fn load_derive_macros(&mut self, root: &CrateRoot<'_>, dylib: Option, span: Span) - -> Vec<(ast::Name, Lrc)> { - use std::{env, mem}; + fn dlsym_proc_macros(&self, + path: &Path, + disambiguator: CrateDisambiguator, + span: Span + ) -> &'static [ProcMacro] { + use std::env; use crate::dynamic_lib::DynamicLibrary; - use proc_macro::bridge::client::ProcMacro; - use syntax::ext::proc_macro::{BangProcMacro, AttrProcMacro, ProcMacroDerive}; - let path = match dylib { - Some(dylib) => dylib, - None => span_bug!(span, "proc-macro crate not dylib"), - }; // Make sure the path contains a / or the linker will search for it. let path = env::current_dir().unwrap().join(path); let lib = match DynamicLibrary::open(Some(&path)) { @@ -599,7 +582,7 @@ impl<'a> CrateLoader<'a> { Err(err) => self.sess.span_fatal(span, &err), }; - let sym = self.sess.generate_proc_macro_decls_symbol(root.disambiguator); + let sym = self.sess.generate_proc_macro_decls_symbol(disambiguator); let decls = unsafe { let sym = match lib.symbol(&sym) { Ok(f) => f, @@ -608,38 +591,11 @@ impl<'a> CrateLoader<'a> { *(sym as *const &[ProcMacro]) }; - let extensions = decls.iter().map(|&decl| { - let (name, kind, helper_attrs) = match decl { - ProcMacro::CustomDerive { trait_name, attributes, client } => { - let helper_attrs = - attributes.iter().cloned().map(Symbol::intern).collect::>(); - ( - trait_name, - SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive { - client, attrs: helper_attrs.clone() - })), - helper_attrs, - ) - } - ProcMacro::Attr { name, client } => ( - name, SyntaxExtensionKind::Attr(Box::new(AttrProcMacro { client })), Vec::new() - ), - ProcMacro::Bang { name, client } => ( - name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new() - ) - }; - - (Symbol::intern(name), Lrc::new(SyntaxExtension { - helper_attrs, - ..SyntaxExtension::default(kind, root.edition) - })) - }).collect(); - // Intentionally leak the dynamic library. We can't ever unload it // since the library can make things that will live arbitrarily long. - mem::forget(lib); + std::mem::forget(lib); - extensions + decls } /// Look for a plugin registrar. Returns library path, crate @@ -648,7 +604,7 @@ impl<'a> CrateLoader<'a> { span: Span, name: Symbol) -> Option<(PathBuf, CrateDisambiguator)> { - let ekrate = self.read_extension_crate(span, name, name); + let ekrate = self.read_extension_crate(name, span); if ekrate.target_only { // Need to abort before syntax expansion. @@ -739,10 +695,7 @@ impl<'a> CrateLoader<'a> { }; info!("panic runtime not found -- loading {}", name); - let dep_kind = DepKind::Implicit; - let (cnum, data) = - self.resolve_crate(&None, name, name, None, None, DUMMY_SP, PathKind::Crate, dep_kind) - .unwrap_or_else(|err| err.report()); + let (cnum, data) = self.resolve_crate(name, DUMMY_SP, DepKind::Implicit, None); // Sanity check the loaded crate to ensure it is indeed a panic runtime // and the panic strategy is indeed what we thought it was. @@ -832,26 +785,21 @@ impl<'a> CrateLoader<'a> { let mut uses_std = false; self.cstore.iter_crate_data(|_, data| { - if data.name == sym::std { + if data.root.name == sym::std { uses_std = true; } }); if uses_std { - let name = match *sanitizer { + let name = Symbol::intern(match sanitizer { Sanitizer::Address => "rustc_asan", Sanitizer::Leak => "rustc_lsan", Sanitizer::Memory => "rustc_msan", Sanitizer::Thread => "rustc_tsan", - }; + }); info!("loading sanitizer: {}", name); - let symbol = Symbol::intern(name); - let dep_kind = DepKind::Explicit; - let (_, data) = - self.resolve_crate(&None, symbol, symbol, None, None, DUMMY_SP, - PathKind::Crate, dep_kind) - .unwrap_or_else(|err| err.report()); + let data = self.resolve_crate(name, DUMMY_SP, DepKind::Explicit, None).1; // Sanity check the loaded crate to ensure it is indeed a sanitizer runtime if !data.root.sanitizer_runtime { @@ -870,12 +818,8 @@ impl<'a> CrateLoader<'a> { { info!("loading profiler"); - let symbol = Symbol::intern("profiler_builtins"); - let dep_kind = DepKind::Implicit; - let (_, data) = - self.resolve_crate(&None, symbol, symbol, None, None, DUMMY_SP, - PathKind::Crate, dep_kind) - .unwrap_or_else(|err| err.report()); + let name = Symbol::intern("profiler_builtins"); + let data = self.resolve_crate(name, DUMMY_SP, DepKind::Implicit, None).1; // Sanity check the loaded crate to ensure it is indeed a profiler runtime if !data.root.profiler_runtime { @@ -1038,11 +982,11 @@ impl<'a> CrateLoader<'a> { pub fn process_extern_crate( &mut self, item: &ast::Item, definitions: &Definitions, ) -> CrateNum { - match item.node { + match item.kind { ast::ItemKind::ExternCrate(orig_name) => { debug!("resolving extern crate stmt. ident: {} orig_name: {:?}", item.ident, orig_name); - let orig_name = match orig_name { + let name = match orig_name { Some(orig_name) => { crate::validate_crate_name(Some(self.sess), &orig_name.as_str(), Some(item.span)); @@ -1056,10 +1000,7 @@ impl<'a> CrateLoader<'a> { DepKind::Explicit }; - let (cnum, ..) = self.resolve_crate( - &None, item.ident.name, orig_name, None, None, - item.span, PathKind::Crate, dep_kind, - ).unwrap_or_else(|err| err.report()); + let cnum = self.resolve_crate(name, item.span, dep_kind, None).0; let def_id = definitions.opt_local_def_id(item.id).unwrap(); let path_len = definitions.def_path(def_id.index).data.len(); @@ -1069,7 +1010,7 @@ impl<'a> CrateLoader<'a> { src: ExternCrateSource::Extern(def_id), span: item.span, path_len, - direct: true, + dependency_of: LOCAL_CRATE, }, &mut FxHashSet::default(), ); @@ -1085,9 +1026,7 @@ impl<'a> CrateLoader<'a> { name: Symbol, span: Span, ) -> CrateNum { - let cnum = self.resolve_crate( - &None, name, name, None, None, span, PathKind::Crate, DepKind::Explicit - ).unwrap_or_else(|err| err.report()).0; + let cnum = self.resolve_crate(name, span, DepKind::Explicit, None).0; self.update_extern_crate( cnum, @@ -1096,7 +1035,7 @@ impl<'a> CrateLoader<'a> { span, // to have the least priority in `update_extern_crate` path_len: usize::max_value(), - direct: true, + dependency_of: LOCAL_CRATE, }, &mut FxHashSet::default(), ); @@ -1109,9 +1048,7 @@ impl<'a> CrateLoader<'a> { name: Symbol, span: Span, ) -> Option { - let cnum = self.resolve_crate( - &None, name, name, None, None, span, PathKind::Crate, DepKind::Explicit - ).ok()?.0; + let cnum = self.maybe_resolve_crate(name, span, DepKind::Explicit, None).ok()?.0; self.update_extern_crate( cnum, @@ -1120,7 +1057,7 @@ impl<'a> CrateLoader<'a> { span, // to have the least priority in `update_extern_crate` path_len: usize::max_value(), - direct: true, + dependency_of: LOCAL_CRATE, }, &mut FxHashSet::default(), ); diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 5d8fabc7e69ae..833c846573f63 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -6,13 +6,12 @@ use rustc::hir::def_id::{CrateNum, DefIndex}; use rustc::hir::map::definitions::DefPathTable; use rustc::middle::cstore::{DepKind, ExternCrate, MetadataLoader}; use rustc::mir::interpret::AllocDecodingState; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::vec::IndexVec; use rustc::util::nodemap::{FxHashMap, NodeMap}; use rustc_data_structures::sync::{Lrc, RwLock, Lock}; use syntax::ast; use syntax::ext::base::SyntaxExtension; -use syntax::symbol::Symbol; use syntax_pos; pub use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind, LinkagePreference}; @@ -28,6 +27,8 @@ pub use crate::cstore_impl::{provide, provide_extern}; pub type CrateNumMap = IndexVec; pub use rustc_data_structures::sync::MetadataRef; +use syntax_pos::Span; +use proc_macro::bridge::client::ProcMacro; pub struct MetadataBlob(pub MetadataRef); @@ -43,13 +44,6 @@ pub struct ImportedSourceFile { } pub struct CrateMetadata { - /// Original name of the crate. - pub name: Symbol, - - /// Name of the crate as imported. I.e., if imported with - /// `extern crate foo as bar;` this will be `bar`. - pub imported_name: Symbol, - /// Information about the extern crate that caused this crate to /// be loaded. If this is `None`, then the crate was injected /// (e.g., by the allocator) @@ -65,28 +59,30 @@ pub struct CrateMetadata { pub alloc_decoding_state: AllocDecodingState, // NOTE(eddyb) we pass `'static` to a `'tcx` parameter because this - // lifetime is only used behind `Lazy` / `LazySeq`, and therefore - // acts like an universal (`for<'tcx>`), that is paired up with - // whichever `TyCtxt` is being used to decode those values. + // lifetime is only used behind `Lazy`, and therefore acts like an + // universal (`for<'tcx>`), that is paired up with whichever `TyCtxt` + // is being used to decode those values. pub root: schema::CrateRoot<'static>, - /// For each public item in this crate, we encode a key. When the + /// For each definition in this crate, we encode a key. When the /// crate is loaded, we read all the keys and put them in this /// hashmap, which gives the reverse mapping. This allows us to /// quickly retrace a `DefPath`, which is needed for incremental /// compilation support. pub def_path_table: Lrc, - pub trait_impls: FxHashMap<(u32, DefIndex), schema::LazySeq>, + pub trait_impls: FxHashMap<(u32, DefIndex), schema::Lazy<[DefIndex]>>, pub dep_kind: Lock, pub source: CrateSource, - pub proc_macros: Option)>>, - /// Whether or not this crate should be consider a private dependency /// for purposes of the 'exported_private_dependencies' lint - pub private_dep: bool + pub private_dep: bool, + + pub span: Span, + + pub raw_proc_macros: Option<&'static [ProcMacro]>, } pub struct CStore { @@ -98,7 +94,7 @@ pub struct CStore { pub enum LoadedMacro { MacroDef(ast::Item), - ProcMacro(Lrc), + ProcMacro(SyntaxExtension), } impl CStore { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index ee1175e798d80..6dab9a404b74a 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -10,6 +10,7 @@ use rustc::middle::cstore::{CrateStore, DepKind, EncodedMetadata, NativeLibraryKind}; use rustc::middle::exported_symbols::ExportedSymbol; use rustc::middle::stability::DeprecationEntry; +use rustc::middle::dependency_format::Linkage; use rustc::hir::def; use rustc::hir; use rustc::session::{CrateDisambiguator, Session}; @@ -30,13 +31,12 @@ use syntax::ast; use syntax::attr; use syntax::source_map; use syntax::edition::Edition; -use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind}; -use syntax::ext::proc_macro::BangProcMacro; use syntax::parse::source_file_to_stream; use syntax::parse::parser::emit_unclosed_delims; -use syntax::symbol::{Symbol, sym}; -use syntax_pos::{Span, NO_EXPANSION, FileName}; -use rustc_data_structures::bit_set::BitSet; +use syntax::source_map::Spanned; +use syntax::symbol::Symbol; +use syntax_pos::{Span, FileName}; +use rustc_index::bit_set::BitSet; macro_rules! provide { (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, @@ -127,21 +127,15 @@ provide! { <'tcx> tcx, def_id, other, cdata, bug!("coerce_unsized_info: `{:?}` is missing its info", def_id); }) } - optimized_mir => { - let mir = cdata.maybe_get_optimized_mir(tcx, def_id.index).unwrap_or_else(|| { - bug!("get_optimized_mir: missing MIR for `{:?}`", def_id) - }); - - let mir = tcx.arena.alloc(mir); - - mir - } + optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) } + promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) } mir_const_qualif => { (cdata.mir_const_qualif(def_id.index), tcx.arena.alloc(BitSet::new_empty(0))) } fn_sig => { cdata.fn_sig(def_id.index, tcx) } inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } is_const_fn_raw => { cdata.is_const_fn_raw(def_id.index) } + asyncness => { cdata.asyncness(def_id.index) } is_foreign_item => { cdata.is_foreign_item(def_id.index) } static_mutability => { cdata.static_mutability(def_id.index) } def_kind => { cdata.def_kind(def_id.index) } @@ -157,13 +151,10 @@ provide! { <'tcx> tcx, def_id, other, cdata, // a `fn` when encoding, so the dep-tracking wouldn't work. // This is only used by rustdoc anyway, which shouldn't have // incremental recompilation ever enabled. - fn_arg_names => { cdata.get_fn_arg_names(def_id.index) } + fn_arg_names => { cdata.get_fn_param_names(def_id.index) } rendered_const => { cdata.get_rendered_const(def_id.index) } impl_parent => { cdata.get_parent_impl(def_id.index) } trait_of_item => { cdata.get_trait_of_item(def_id.index) } - const_is_rvalue_promotable_to_static => { - cdata.const_is_rvalue_promotable_to_static(def_id.index) - } is_mir_available => { cdata.is_item_mir_available(def_id.index) } dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) } @@ -227,7 +218,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, let r = *cdata.dep_kind.lock(); r } - crate_name => { cdata.name } + crate_name => { cdata.root.name } item_children => { let mut result = SmallVec::<[_; 8]>::new(); cdata.each_child_of_item(def_id.index, |child| result.push(child), tcx.sess); @@ -235,11 +226,12 @@ provide! { <'tcx> tcx, def_id, other, cdata, } defined_lib_features => { cdata.get_lib_features(tcx) } defined_lang_items => { cdata.get_lang_items(tcx) } + diagnostic_items => { cdata.get_diagnostic_items(tcx) } missing_lang_items => { cdata.get_missing_lang_items(tcx) } missing_extern_crate_item => { let r = match *cdata.extern_crate.borrow() { - Some(extern_crate) if !extern_crate.direct => true, + Some(extern_crate) if !extern_crate.is_direct() => true, _ => false, }; r @@ -247,7 +239,30 @@ provide! { <'tcx> tcx, def_id, other, cdata, used_crate_source => { Lrc::new(cdata.source.clone()) } - exported_symbols => { Arc::new(cdata.exported_symbols(tcx)) } + exported_symbols => { + let mut syms = cdata.exported_symbols(tcx); + + // When linked into a dylib crates don't export their generic symbols, + // so if that's happening then we can't load upstream monomorphizations + // from this crate. + let formats = tcx.dependency_formats(LOCAL_CRATE); + let remove_generics = formats.iter().any(|(_ty, list)| { + match list.get(def_id.krate.as_usize() - 1) { + Some(Linkage::IncludedFromDylib) | Some(Linkage::Dynamic) => true, + _ => false, + } + }); + if remove_generics { + syms.retain(|(sym, _threshold)| { + match sym { + ExportedSymbol::Generic(..) => false, + _ => return true, + } + }); + } + + Arc::new(syms) + } } pub fn provide(providers: &mut Providers<'_>) { @@ -256,7 +271,11 @@ pub fn provide(providers: &mut Providers<'_>) { // resolve! Does this work? Unsure! That's what the issue is about *providers = Providers { is_dllimport_foreign_item: |tcx, id| { - tcx.native_library_kind(id) == Some(NativeLibraryKind::NativeUnknown) + match tcx.native_library_kind(id) { + Some(NativeLibraryKind::NativeUnknown) | + Some(NativeLibraryKind::NativeRawDylib) => true, + _ => false, + } }, is_statically_included_foreign_item: |tcx, id| { match tcx.native_library_kind(id) { @@ -378,6 +397,11 @@ pub fn provide(providers: &mut Providers<'_>) { tcx.arena.alloc(visible_parent_map) }, + dependency_formats: |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + Lrc::new(crate::dependency_format::calculate(tcx)) + }, + ..*providers }; } @@ -401,8 +425,8 @@ impl cstore::CStore { self.get_crate_data(cnum).root.edition } - pub fn struct_field_names_untracked(&self, def: DefId) -> Vec { - self.get_crate_data(def.krate).get_struct_field_names(def.index) + pub fn struct_field_names_untracked(&self, def: DefId, sess: &Session) -> Vec> { + self.get_crate_data(def.krate).get_struct_field_names(def.index, sess) } pub fn ctor_kind_untracked(&self, def: DefId) -> def::CtorKind { @@ -426,24 +450,16 @@ impl cstore::CStore { pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro { let data = self.get_crate_data(id.krate); - if let Some(ref proc_macros) = data.proc_macros { - return LoadedMacro::ProcMacro(proc_macros[id.index.to_proc_macro_index()].1.clone()); - } else if data.name == sym::proc_macro && data.item_name(id.index) == sym::quote { - let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote); - let kind = SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })); - let ext = SyntaxExtension { - allow_internal_unstable: Some([sym::proc_macro_def_site][..].into()), - ..SyntaxExtension::default(kind, data.root.edition) - }; - return LoadedMacro::ProcMacro(Lrc::new(ext)); + if data.is_proc_macro_crate() { + return LoadedMacro::ProcMacro(data.load_proc_macro(id.index, sess)); } let def = data.get_macro(id.index); - let macro_full_name = data.def_path(id.index).to_string_friendly(|_| data.imported_name); + let macro_full_name = data.def_path(id.index).to_string_friendly(|_| data.root.name); let source_name = FileName::Macros(macro_full_name); let source_file = sess.parse_sess.source_map().new_source_file(source_name, def.body); - let local_span = Span::new(source_file.start_pos, source_file.end_pos, NO_EXPANSION); + let local_span = Span::with_root_ctxt(source_file.start_pos, source_file.end_pos); let (body, mut errors) = source_file_to_stream(&sess.parse_sess, source_file, None); emit_unclosed_delims(&mut errors, &sess.diagnostic()); @@ -459,11 +475,12 @@ impl cstore::CStore { .insert(local_span, (name.to_string(), data.get_span(id.index, sess))); LoadedMacro::MacroDef(ast::Item { - ident: ast::Ident::from_str(&name.as_str()), + // FIXME: cross-crate hygiene + ident: ast::Ident::with_dummy_span(name.as_symbol()), id: ast::DUMMY_NODE_ID, span: local_span, attrs: attrs.iter().cloned().collect(), - node: ast::ItemKind::MacroDef(ast::MacroDef { + kind: ast::ItemKind::MacroDef(ast::MacroDef { tokens: body.into(), legacy: def.legacy, }), @@ -488,7 +505,7 @@ impl CrateStore for cstore::CStore { fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol { - self.get_crate_data(cnum).name + self.get_crate_data(cnum).root.name } fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 935187dd0667b..3b655023d28e4 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -3,22 +3,23 @@ use crate::cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, ForeignModule}; use crate::schema::*; +use rustc_index::vec::IndexVec; use rustc_data_structures::sync::{Lrc, ReadGuard}; -use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash, Definitions}; +use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash}; use rustc::hir; use rustc::middle::cstore::LinkagePreference; use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc::hir::def::{self, Res, DefKind, CtorOf, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc::hir::map::definitions::DefPathTable; use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fx::FxHashMap; use rustc::middle::lang_items; use rustc::mir::{self, interpret}; use rustc::mir::interpret::AllocDecodingSession; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::codec::TyDecoder; -use rustc::mir::Body; +use rustc::mir::{Body, Promoted}; use rustc::util::captures::Captures; use std::io; @@ -28,12 +29,13 @@ use std::u32; use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque}; use syntax::attr; use syntax::ast::{self, Ident}; -use syntax::source_map; +use syntax::source_map::{self, respan, Spanned}; use syntax::symbol::{Symbol, sym}; -use syntax::ext::base::{MacroKind, SyntaxExtension}; -use syntax::ext::hygiene::ExpnId; -use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP, NO_EXPANSION}; +use syntax::ext::base::{MacroKind, SyntaxExtensionKind, SyntaxExtension}; +use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP, symbol::{InternedString}}; use log::debug; +use proc_macro::bridge::client::ProcMacro; +use syntax::ext::proc_macro::{AttrProcMacro, ProcMacroDerive, BangProcMacro}; pub struct DecodeContext<'a, 'tcx> { opaque: opaque::Decoder<'a>, @@ -134,14 +136,14 @@ impl<'a, 'tcx, T: Decodable> Lazy { } } -impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable> LazySeq { +impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable> Lazy<[T]> { pub fn decode>( self, meta: M, - ) -> impl Iterator + Captures<'a> + Captures<'tcx> + 'x { + ) -> impl ExactSizeIterator + Captures<'a> + Captures<'tcx> + 'x { let mut dcx = meta.decoder(self.position); dcx.lazy_state = LazyState::NodeStart(self.position); - (0..self.len).map(move |_| T::decode(&mut dcx).unwrap()) + (0..self.meta).map(move |_| T::decode(&mut dcx).unwrap()) } } @@ -154,10 +156,14 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { self.cdata.expect("missing CrateMetadata in DecodeContext") } - fn read_lazy_distance(&mut self, min_size: usize) -> Result::Error> { + fn read_lazy_with_meta( + &mut self, + meta: T::Meta, + ) -> Result, ::Error> { + let min_size = T::min_size(meta); let distance = self.read_usize()?; let position = match self.lazy_state { - LazyState::NoNode => bug!("read_lazy_distance: outside of a metadata node"), + LazyState::NoNode => bug!("read_lazy_with_meta: outside of a metadata node"), LazyState::NodeStart(start) => { assert!(distance + min_size <= start); start - distance - min_size @@ -165,7 +171,7 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { LazyState::Previous(last_min_end) => last_min_end + distance, }; self.lazy_state = LazyState::Previous(position + min_size); - Ok(position) + Ok(Lazy::from_position_and_meta(position, meta)) } } @@ -230,19 +236,18 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> { impl<'a, 'tcx, T> SpecializedDecoder> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result, Self::Error> { - Ok(Lazy::with_position(self.read_lazy_distance(Lazy::::min_size())?)) + self.read_lazy_with_meta(()) } } -impl<'a, 'tcx, T> SpecializedDecoder> for DecodeContext<'a, 'tcx> { - fn specialized_decode(&mut self) -> Result, Self::Error> { +impl<'a, 'tcx, T> SpecializedDecoder> for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result, Self::Error> { let len = self.read_usize()?; - let position = if len == 0 { - 0 + if len == 0 { + Ok(Lazy::empty()) } else { - self.read_lazy_distance(LazySeq::::min_size(len))? - }; - Ok(LazySeq::with_position_and_length(position, len)) + self.read_lazy_with_meta(len) + } } } @@ -344,7 +349,15 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { let hi = (hi + source_file.translated_source_file.start_pos) - source_file.original_start_pos; - Ok(Span::new(lo, hi, NO_EXPANSION)) + Ok(Span::with_root_ctxt(lo, hi)) + } +} + +impl SpecializedDecoder for DecodeContext<'_, '_> { + fn specialized_decode(&mut self) -> Result { + // FIXME(jseyfried): intercrate hygiene + + Ok(Ident::with_dummy_span(Symbol::decode(self)?)) } } @@ -370,7 +383,7 @@ impl<'tcx> MetadataBlob { } pub fn get_rustc_version(&self) -> String { - Lazy::with_position(METADATA_HEADER.len() + 4).decode(self) + Lazy::::from_position(METADATA_HEADER.len() + 4).decode(self) } pub fn get_root(&self) -> CrateRoot<'tcx> { @@ -379,7 +392,7 @@ impl<'tcx> MetadataBlob { let pos = (((slice[offset + 0] as u32) << 24) | ((slice[offset + 1] as u32) << 16) | ((slice[offset + 2] as u32) << 8) | ((slice[offset + 3] as u32) << 0)) as usize; - Lazy::with_position(pos).decode(self) + Lazy::>::from_position(pos).decode(self) } pub fn list_crate_metadata(&self, @@ -434,46 +447,24 @@ impl<'tcx> EntryKind<'tcx> { } } -/// Creates the "fake" DefPathTable for a given proc macro crate. -/// -/// The DefPathTable is as follows: -/// -/// CRATE_ROOT (DefIndex 0:0) -/// |- GlobalMetaDataKind data (DefIndex 1:0 .. DefIndex 1:N) -/// |- proc macro #0 (DefIndex 1:N) -/// |- proc macro #1 (DefIndex 1:N+1) -/// \- ... -crate fn proc_macro_def_path_table(crate_root: &CrateRoot<'_>, - proc_macros: &[(ast::Name, Lrc)]) - -> DefPathTable -{ - let mut definitions = Definitions::default(); - - let name = crate_root.name.as_str(); - let disambiguator = crate_root.disambiguator; - debug!("creating proc macro def path table for {:?}/{:?}", name, disambiguator); - let crate_root = definitions.create_root_def(&name, disambiguator); - for (index, (name, _)) in proc_macros.iter().enumerate() { - let def_index = definitions.create_def_with_parent( - crate_root, - ast::DUMMY_NODE_ID, - DefPathData::MacroNs(name.as_interned_str()), - ExpnId::root(), - DUMMY_SP); - debug!("definition for {:?} is {:?}", name, def_index); - assert_eq!(def_index, DefIndex::from_proc_macro_index(index)); - } - - definitions.def_path_table().clone() -} - impl<'a, 'tcx> CrateMetadata { + pub fn is_proc_macro_crate(&self) -> bool { + self.root.proc_macro_decls_static.is_some() + } + fn is_proc_macro(&self, id: DefIndex) -> bool { - self.proc_macros.is_some() && id != CRATE_DEF_INDEX + self.is_proc_macro_crate() && + self.root.proc_macro_data.unwrap().decode(self).find(|x| *x == id).is_some() + } + + fn entry_unless_proc_macro(&self, id: DefIndex) -> Option> { + match self.is_proc_macro(id) { + true => None, + false => Some(self.entry(id)), + } } fn maybe_entry(&self, item_id: DefIndex) -> Option>> { - assert!(!self.is_proc_macro(item_id)); self.root.entries_index.lookup(self.blob.raw_bytes(), item_id) } @@ -482,7 +473,7 @@ impl<'a, 'tcx> CrateMetadata { None => { bug!("entry: id not found: {:?} in crate {:?} with number {}", item_id, - self.name, + self.root.name, self.cnum) } Some(d) => d.decode(self), @@ -496,13 +487,28 @@ impl<'a, 'tcx> CrateMetadata { } } + fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro { + // DefIndex's in root.proc_macro_data have a one-to-one correspondence + // with items in 'raw_proc_macros'. + // NOTE: If you update the order of macros in 'proc_macro_data' for any reason, + // you must also update src/libsyntax_ext/proc_macro_harness.rs + // Failing to do so will result in incorrect data being associated + // with proc macros when deserialized. + let pos = self.root.proc_macro_data.unwrap().decode(self).position(|i| i == id).unwrap(); + &self.raw_proc_macros.unwrap()[pos] + } + pub fn item_name(&self, item_index: DefIndex) -> Symbol { - self.def_key(item_index) - .disambiguated_data - .data - .get_opt_name() - .expect("no name in item_name") - .as_symbol() + if !self.is_proc_macro(item_index) { + self.def_key(item_index) + .disambiguated_data + .data + .get_opt_name() + .expect("no name in item_name") + .as_symbol() + } else { + Symbol::intern(self.raw_proc_macro(item_index).name()) + } } pub fn def_kind(&self, index: DefIndex) -> Option { @@ -510,16 +516,43 @@ impl<'a, 'tcx> CrateMetadata { self.entry(index).kind.def_kind() } else { Some(DefKind::Macro( - self.proc_macros.as_ref().unwrap()[index.to_proc_macro_index()].1.macro_kind() + macro_kind(self.raw_proc_macro(index)) )) } } pub fn get_span(&self, index: DefIndex, sess: &Session) -> Span { - match self.is_proc_macro(index) { - true => DUMMY_SP, - false => self.entry(index).span.decode((self, sess)), - } + self.entry(index).span.decode((self, sess)) + } + + crate fn load_proc_macro(&self, id: DefIndex, sess: &Session) -> SyntaxExtension { + let (name, kind, helper_attrs) = match *self.raw_proc_macro(id) { + ProcMacro::CustomDerive { trait_name, attributes, client } => { + let helper_attrs = + attributes.iter().cloned().map(Symbol::intern).collect::>(); + ( + trait_name, + SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive { client })), + helper_attrs, + ) + } + ProcMacro::Attr { name, client } => ( + name, SyntaxExtensionKind::Attr(Box::new(AttrProcMacro { client })), Vec::new() + ), + ProcMacro::Bang { name, client } => ( + name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new() + ) + }; + + SyntaxExtension::new( + &sess.parse_sess, + kind, + self.get_span(id, sess), + helper_attrs, + self.root.edition, + Symbol::intern(name), + &self.get_attributes(&self.entry(id), sess), + ) } pub fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef { @@ -569,7 +602,7 @@ impl<'a, 'tcx> CrateMetadata { ty::VariantDef::new( tcx, - Ident::with_empty_ctxt(self.item_name(index)), + Ident::with_dummy_span(self.item_name(index)), variant_did, ctor_did, data.discr, @@ -577,7 +610,7 @@ impl<'a, 'tcx> CrateMetadata { let f = self.entry(index); ty::FieldDef { did: self.local_def_id(index), - ident: Ident::with_empty_ctxt(self.item_name(index)), + ident: Ident::with_dummy_span(self.item_name(index)), vis: f.visibility.decode(self) } }).collect(), @@ -662,10 +695,8 @@ impl<'a, 'tcx> CrateMetadata { } pub fn get_deprecation(&self, id: DefIndex) -> Option { - match self.is_proc_macro(id) { - true => None, - false => self.entry(id).deprecation.map(|depr| depr.decode(self)), - } + self.entry_unless_proc_macro(id) + .and_then(|entry| entry.deprecation.map(|depr| depr.decode(self))) } pub fn get_visibility(&self, id: DefIndex) -> ty::Visibility { @@ -686,7 +717,7 @@ impl<'a, 'tcx> CrateMetadata { self.get_impl_data(id).parent_impl } - pub fn get_impl_polarity(&self, id: DefIndex) -> hir::ImplPolarity { + pub fn get_impl_polarity(&self, id: DefIndex) -> ty::ImplPolarity { self.get_impl_data(id).polarity } @@ -715,7 +746,7 @@ impl<'a, 'tcx> CrateMetadata { /// Iterates over the language items in the given crate. pub fn get_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] { - if self.proc_macros.is_some() { + if self.is_proc_macro_crate() { // Proc macro crates do not export any lang-items to the target. &[] } else { @@ -726,22 +757,39 @@ impl<'a, 'tcx> CrateMetadata { } } + /// Iterates over the diagnostic items in the given crate. + pub fn get_diagnostic_items( + &self, + tcx: TyCtxt<'tcx>, + ) -> &'tcx FxHashMap { + tcx.arena.alloc(if self.is_proc_macro_crate() { + // Proc macro crates do not export any diagnostic-items to the target. + Default::default() + } else { + self.root + .diagnostic_items + .decode(self) + .map(|(name, def_index)| (name, self.local_def_id(def_index))) + .collect() + }) + } + /// Iterates over each child of the given item. pub fn each_child_of_item(&self, id: DefIndex, mut callback: F, sess: &Session) where F: FnMut(def::Export) { - if let Some(ref proc_macros) = self.proc_macros { + if let Some(proc_macros_ids) = self.root.proc_macro_data.map(|d| d.decode(self)) { /* If we are loading as a proc macro, we want to return the view of this crate - * as a proc macro crate, not as a Rust crate. See `proc_macro_def_path_table` - * for the DefPathTable we are corresponding to. + * as a proc macro crate. */ if id == CRATE_DEF_INDEX { - for (id, &(name, ref ext)) in proc_macros.iter().enumerate() { + for def_index in proc_macros_ids { + let raw_macro = self.raw_proc_macro(def_index); let res = Res::Def( - DefKind::Macro(ext.macro_kind()), - self.local_def_id(DefIndex::from_proc_macro_index(id)), + DefKind::Macro(macro_kind(raw_macro)), + self.local_def_id(def_index), ); - let ident = Ident::with_empty_ctxt(name); + let ident = Ident::from_str(raw_macro.name()); callback(def::Export { ident: ident, res: res, @@ -783,7 +831,7 @@ impl<'a, 'tcx> CrateMetadata { if let Some(kind) = self.def_kind(child_index) { callback(def::Export { res: Res::Def(kind, self.local_def_id(child_index)), - ident: Ident::with_empty_ctxt(self.item_name(child_index)), + ident: Ident::with_dummy_span(self.item_name(child_index)), vis: self.get_visibility(child_index), span: self.entry(child_index).span.decode((self, sess)), }); @@ -862,24 +910,29 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn const_is_rvalue_promotable_to_static(&self, id: DefIndex) -> bool { - match self.entry(id).kind { - EntryKind::AssocConst(_, data, _) | - EntryKind::Const(data, _) => data.ast_promotable, - _ => bug!(), - } - } - pub fn is_item_mir_available(&self, id: DefIndex) -> bool { !self.is_proc_macro(id) && self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some() } - pub fn maybe_get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Option> { - match self.is_proc_macro(id) { - true => None, - false => self.entry(id).mir.map(|mir| mir.decode((self, tcx))), - } + pub fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> { + self.entry_unless_proc_macro(id) + .and_then(|entry| entry.mir.map(|mir| mir.decode((self, tcx)))) + .unwrap_or_else(|| { + bug!("get_optimized_mir: missing MIR for `{:?}`", self.local_def_id(id)) + }) + } + + pub fn get_promoted_mir( + &self, + tcx: TyCtxt<'tcx>, + id: DefIndex, + ) -> IndexVec> { + self.entry_unless_proc_macro(id) + .and_then(|entry| entry.promoted_mir.map(|promoted| promoted.decode((self, tcx)))) + .unwrap_or_else(|| { + bug!("get_promoted_mir: missing MIR for `{:?}`", self.local_def_id(id)) + }) } pub fn mir_const_qualif(&self, id: DefIndex) -> u8 { @@ -952,11 +1005,8 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn get_item_attrs(&self, node_id: DefIndex, sess: &Session) -> Lrc<[ast::Attribute]> { - if self.is_proc_macro(node_id) { - return Lrc::new([]); - } + pub fn get_item_attrs(&self, node_id: DefIndex, sess: &Session) -> Lrc<[ast::Attribute]> { // The attributes for a tuple struct/variant are attached to the definition, not the ctor; // we assume that someone passing in a tuple struct ctor is actually wanting to // look at the definition @@ -971,11 +1021,11 @@ impl<'a, 'tcx> CrateMetadata { Lrc::from(self.get_attributes(&item, sess)) } - pub fn get_struct_field_names(&self, id: DefIndex) -> Vec { + pub fn get_struct_field_names(&self, id: DefIndex, sess: &Session) -> Vec> { self.entry(id) .children .decode(self) - .map(|index| self.item_name(index)) + .map(|index| respan(self.get_span(index, sess), self.item_name(index))) .collect() } @@ -1014,7 +1064,7 @@ impl<'a, 'tcx> CrateMetadata { tcx: TyCtxt<'tcx>, filter: Option, ) -> &'tcx [DefId] { - if self.proc_macros.is_some() { + if self.is_proc_macro_crate() { // proc-macro crates export no trait impls. return &[] } @@ -1058,7 +1108,7 @@ impl<'a, 'tcx> CrateMetadata { pub fn get_native_libraries(&self, sess: &Session) -> Vec { - if self.proc_macros.is_some() { + if self.is_proc_macro_crate() { // Proc macro crates do not have any *target* native libraries. vec![] } else { @@ -1067,7 +1117,7 @@ impl<'a, 'tcx> CrateMetadata { } pub fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> &'tcx [ForeignModule] { - if self.proc_macros.is_some() { + if self.is_proc_macro_crate() { // Proc macro crates do not have any *target* foreign modules. &[] } else { @@ -1090,7 +1140,7 @@ impl<'a, 'tcx> CrateMetadata { } pub fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] { - if self.proc_macros.is_some() { + if self.is_proc_macro_crate() { // Proc macro crates do not depend on any target weak lang-items. &[] } else { @@ -1100,21 +1150,21 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn get_fn_arg_names(&self, id: DefIndex) -> Vec { - let arg_names = match self.entry(id).kind { + pub fn get_fn_param_names(&self, id: DefIndex) -> Vec { + let param_names = match self.entry(id).kind { EntryKind::Fn(data) | - EntryKind::ForeignFn(data) => data.decode(self).arg_names, - EntryKind::Method(data) => data.decode(self).fn_data.arg_names, - _ => LazySeq::empty(), + EntryKind::ForeignFn(data) => data.decode(self).param_names, + EntryKind::Method(data) => data.decode(self).fn_data.param_names, + _ => Lazy::empty(), }; - arg_names.decode(self).collect() + param_names.decode(self).collect() } pub fn exported_symbols( &self, tcx: TyCtxt<'tcx>, ) -> Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)> { - if self.proc_macros.is_some() { + if self.is_proc_macro_crate() { // If this crate is a custom derive crate, then we're not even going to // link those in so we skip those crates. vec![] @@ -1149,6 +1199,15 @@ impl<'a, 'tcx> CrateMetadata { constness == hir::Constness::Const } + pub fn asyncness(&self, id: DefIndex) -> hir::IsAsync { + match self.entry(id).kind { + EntryKind::Fn(data) => data.decode(self).asyncness, + EntryKind::Method(data) => data.decode(self).fn_data.asyncness, + EntryKind::ForeignFn(data) => data.decode(self).asyncness, + _ => bug!("asyncness: expect functions entry."), + } + } + pub fn is_foreign_item(&self, id: DefIndex) -> bool { match self.entry(id).kind { EntryKind::ForeignImmStatic | @@ -1183,13 +1242,18 @@ impl<'a, 'tcx> CrateMetadata { #[inline] pub fn def_key(&self, index: DefIndex) -> DefKey { - self.def_path_table.def_key(index) + let mut key = self.def_path_table.def_key(index); + if self.is_proc_macro(index) { + let name = self.raw_proc_macro(index).name(); + key.disambiguated_data.data = DefPathData::MacroNs(InternedString::intern(name)); + } + key } // Returns the path leading to the thing with this `id`. pub fn def_path(&self, id: DefIndex) -> DefPath { debug!("def_path(cnum={:?}, id={:?})", self.cnum, id); - DefPath::make(self.cnum, id, |parent| self.def_path_table.def_key(parent)) + DefPath::make(self.cnum, id, |parent| self.def_key(parent)) } #[inline] @@ -1302,3 +1366,13 @@ impl<'a, 'tcx> CrateMetadata { self.source_map_import_info.borrow() } } + +// Cannot be implemented on 'ProcMacro', as libproc_macro +// does not depend on libsyntax +fn macro_kind(raw: &ProcMacro) -> MacroKind { + match raw { + ProcMacro::CustomDerive { .. } => MacroKind::Derive, + ProcMacro::Attr { .. } => MacroKind::Attr, + ProcMacro::Bang { .. } => MacroKind::Bang + } +} diff --git a/src/librustc_metadata/dependency_format.rs b/src/librustc_metadata/dependency_format.rs new file mode 100644 index 0000000000000..9a30623b33d62 --- /dev/null +++ b/src/librustc_metadata/dependency_format.rs @@ -0,0 +1,370 @@ +//! Resolution of mixing rlibs and dylibs +//! +//! When producing a final artifact, such as a dynamic library, the compiler has +//! a choice between linking an rlib or linking a dylib of all upstream +//! dependencies. The linking phase must guarantee, however, that a library only +//! show up once in the object file. For example, it is illegal for library A to +//! be statically linked to B and C in separate dylibs, and then link B and C +//! into a crate D (because library A appears twice). +//! +//! The job of this module is to calculate what format each upstream crate +//! should be used when linking each output type requested in this session. This +//! generally follows this set of rules: +//! +//! 1. Each library must appear exactly once in the output. +//! 2. Each rlib contains only one library (it's just an object file) +//! 3. Each dylib can contain more than one library (due to static linking), +//! and can also bring in many dynamic dependencies. +//! +//! With these constraints in mind, it's generally a very difficult problem to +//! find a solution that's not "all rlibs" or "all dylibs". I have suspicions +//! that NP-ness may come into the picture here... +//! +//! The current selection algorithm below looks mostly similar to: +//! +//! 1. If static linking is required, then require all upstream dependencies +//! to be available as rlibs. If not, generate an error. +//! 2. If static linking is requested (generating an executable), then +//! attempt to use all upstream dependencies as rlibs. If any are not +//! found, bail out and continue to step 3. +//! 3. Static linking has failed, at least one library must be dynamically +//! linked. Apply a heuristic by greedily maximizing the number of +//! dynamically linked libraries. +//! 4. Each upstream dependency available as a dynamic library is +//! registered. The dependencies all propagate, adding to a map. It is +//! possible for a dylib to add a static library as a dependency, but it +//! is illegal for two dylibs to add the same static library as a +//! dependency. The same dylib can be added twice. Additionally, it is +//! illegal to add a static dependency when it was previously found as a +//! dylib (and vice versa) +//! 5. After all dynamic dependencies have been traversed, re-traverse the +//! remaining dependencies and add them statically (if they haven't been +//! added already). +//! +//! While not perfect, this algorithm should help support use-cases such as leaf +//! dependencies being static while the larger tree of inner dependencies are +//! all dynamic. This isn't currently very well battle tested, so it will likely +//! fall short in some use cases. +//! +//! Currently, there is no way to specify the preference of linkage with a +//! particular library (other than a global dynamic/static switch). +//! Additionally, the algorithm is geared towards finding *any* solution rather +//! than finding a number of solutions (there are normally quite a few). + +use rustc::hir::def_id::CrateNum; +use rustc::middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic}; +use rustc::middle::cstore::{self, DepKind}; +use rustc::middle::dependency_format::{DependencyList, Dependencies, Linkage}; +use rustc::session::config; +use rustc::ty::TyCtxt; +use rustc::util::nodemap::FxHashMap; +use rustc_target::spec::PanicStrategy; + +pub fn calculate(tcx: TyCtxt<'_>) -> Dependencies { + tcx.sess.crate_types.borrow().iter().map(|&ty| { + let linkage = calculate_type(tcx, ty); + verify_ok(tcx, &linkage); + (ty, linkage) + }).collect::>() +} + +fn calculate_type(tcx: TyCtxt<'_>, ty: config::CrateType) -> DependencyList { + let sess = &tcx.sess; + + if !sess.opts.output_types.should_codegen() { + return Vec::new(); + } + + let preferred_linkage = match ty { + // cdylibs must have all static dependencies. + config::CrateType::Cdylib => Linkage::Static, + + // Generating a dylib without `-C prefer-dynamic` means that we're going + // to try to eagerly statically link all dependencies. This is normally + // done for end-product dylibs, not intermediate products. + config::CrateType::Dylib if !sess.opts.cg.prefer_dynamic => Linkage::Static, + config::CrateType::Dylib => Linkage::Dynamic, + + // If the global prefer_dynamic switch is turned off, or the final + // executable will be statically linked, prefer static crate linkage. + config::CrateType::Executable if !sess.opts.cg.prefer_dynamic || + sess.crt_static() => Linkage::Static, + config::CrateType::Executable => Linkage::Dynamic, + + // proc-macro crates are mostly cdylibs, but we also need metadata. + config::CrateType::ProcMacro => Linkage::Static, + + // No linkage happens with rlibs, we just needed the metadata (which we + // got long ago), so don't bother with anything. + config::CrateType::Rlib => Linkage::NotLinked, + + // staticlibs must have all static dependencies. + config::CrateType::Staticlib => Linkage::Static, + }; + + if preferred_linkage == Linkage::NotLinked { + // If the crate is not linked, there are no link-time dependencies. + return Vec::new(); + } + + if preferred_linkage == Linkage::Static { + // Attempt static linkage first. For dylibs and executables, we may be + // able to retry below with dynamic linkage. + if let Some(v) = attempt_static(tcx) { + return v; + } + + // Staticlibs, cdylibs, and static executables must have all static + // dependencies. If any are not found, generate some nice pretty errors. + if ty == config::CrateType::Cdylib || ty == config::CrateType::Staticlib || + (ty == config::CrateType::Executable && sess.crt_static() && + !sess.target.target.options.crt_static_allows_dylibs) { + for &cnum in tcx.crates().iter() { + if tcx.dep_kind(cnum).macros_only() { continue } + let src = tcx.used_crate_source(cnum); + if src.rlib.is_some() { continue } + sess.err(&format!("crate `{}` required to be available in rlib format, \ + but was not found in this form", + tcx.crate_name(cnum))); + } + return Vec::new(); + } + } + + let mut formats = FxHashMap::default(); + + // Sweep all crates for found dylibs. Add all dylibs, as well as their + // dependencies, ensuring there are no conflicts. The only valid case for a + // dependency to be relied upon twice is for both cases to rely on a dylib. + for &cnum in tcx.crates().iter() { + if tcx.dep_kind(cnum).macros_only() { continue } + let name = tcx.crate_name(cnum); + let src = tcx.used_crate_source(cnum); + if src.dylib.is_some() { + log::info!("adding dylib: {}", name); + add_library(tcx, cnum, RequireDynamic, &mut formats); + let deps = tcx.dylib_dependency_formats(cnum); + for &(depnum, style) in deps.iter() { + log::info!("adding {:?}: {}", style, tcx.crate_name(depnum)); + add_library(tcx, depnum, style, &mut formats); + } + } + } + + // Collect what we've got so far in the return vector. + let last_crate = tcx.crates().len(); + let mut ret = (1..last_crate+1).map(|cnum| { + match formats.get(&CrateNum::new(cnum)) { + Some(&RequireDynamic) => Linkage::Dynamic, + Some(&RequireStatic) => Linkage::IncludedFromDylib, + None => Linkage::NotLinked, + } + }).collect::>(); + + // Run through the dependency list again, and add any missing libraries as + // static libraries. + // + // If the crate hasn't been included yet and it's not actually required + // (e.g., it's an allocator) then we skip it here as well. + for &cnum in tcx.crates().iter() { + let src = tcx.used_crate_source(cnum); + if src.dylib.is_none() && + !formats.contains_key(&cnum) && + tcx.dep_kind(cnum) == DepKind::Explicit { + assert!(src.rlib.is_some() || src.rmeta.is_some()); + log::info!("adding staticlib: {}", tcx.crate_name(cnum)); + add_library(tcx, cnum, RequireStatic, &mut formats); + ret[cnum.as_usize() - 1] = Linkage::Static; + } + } + + // We've gotten this far because we're emitting some form of a final + // artifact which means that we may need to inject dependencies of some + // form. + // + // Things like allocators and panic runtimes may not have been activated + // quite yet, so do so here. + activate_injected_dep(*sess.injected_panic_runtime.get(), &mut ret, + &|cnum| tcx.is_panic_runtime(cnum)); + + // When dylib B links to dylib A, then when using B we must also link to A. + // It could be the case, however, that the rlib for A is present (hence we + // found metadata), but the dylib for A has since been removed. + // + // For situations like this, we perform one last pass over the dependencies, + // making sure that everything is available in the requested format. + for (cnum, kind) in ret.iter().enumerate() { + let cnum = CrateNum::new(cnum + 1); + let src = tcx.used_crate_source(cnum); + match *kind { + Linkage::NotLinked | + Linkage::IncludedFromDylib => {} + Linkage::Static if src.rlib.is_some() => continue, + Linkage::Dynamic if src.dylib.is_some() => continue, + kind => { + let kind = match kind { + Linkage::Static => "rlib", + _ => "dylib", + }; + sess.err(&format!("crate `{}` required to be available in {} format, \ + but was not found in this form", + tcx.crate_name(cnum), kind)); + } + } + } + + ret +} + +fn add_library( + tcx: TyCtxt<'_>, + cnum: CrateNum, + link: LinkagePreference, + m: &mut FxHashMap, +) { + match m.get(&cnum) { + Some(&link2) => { + // If the linkages differ, then we'd have two copies of the library + // if we continued linking. If the linkages are both static, then we + // would also have two copies of the library (static from two + // different locations). + // + // This error is probably a little obscure, but I imagine that it + // can be refined over time. + if link2 != link || link == RequireStatic { + tcx.sess.struct_err(&format!("cannot satisfy dependencies so `{}` only \ + shows up once", tcx.crate_name(cnum))) + .help("having upstream crates all available in one format \ + will likely make this go away") + .emit(); + } + } + None => { m.insert(cnum, link); } + } +} + +fn attempt_static(tcx: TyCtxt<'_>) -> Option { + let sess = &tcx.sess; + let crates = cstore::used_crates(tcx, RequireStatic); + if !crates.iter().by_ref().all(|&(_, ref p)| p.is_some()) { + return None + } + + // All crates are available in an rlib format, so we're just going to link + // everything in explicitly so long as it's actually required. + let last_crate = tcx.crates().len(); + let mut ret = (1..last_crate+1).map(|cnum| { + if tcx.dep_kind(CrateNum::new(cnum)) == DepKind::Explicit { + Linkage::Static + } else { + Linkage::NotLinked + } + }).collect::>(); + + // Our allocator/panic runtime may not have been linked above if it wasn't + // explicitly linked, which is the case for any injected dependency. Handle + // that here and activate them. + activate_injected_dep(*sess.injected_panic_runtime.get(), &mut ret, + &|cnum| tcx.is_panic_runtime(cnum)); + + Some(ret) +} + +// Given a list of how to link upstream dependencies so far, ensure that an +// injected dependency is activated. This will not do anything if one was +// transitively included already (e.g., via a dylib or explicitly so). +// +// If an injected dependency was not found then we're guaranteed the +// metadata::creader module has injected that dependency (not listed as +// a required dependency) in one of the session's field. If this field is not +// set then this compilation doesn't actually need the dependency and we can +// also skip this step entirely. +fn activate_injected_dep(injected: Option, + list: &mut DependencyList, + replaces_injected: &dyn Fn(CrateNum) -> bool) { + for (i, slot) in list.iter().enumerate() { + let cnum = CrateNum::new(i + 1); + if !replaces_injected(cnum) { + continue + } + if *slot != Linkage::NotLinked { + return + } + } + if let Some(injected) = injected { + let idx = injected.as_usize() - 1; + assert_eq!(list[idx], Linkage::NotLinked); + list[idx] = Linkage::Static; + } +} + +// After the linkage for a crate has been determined we need to verify that +// there's only going to be one allocator in the output. +fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { + let sess = &tcx.sess; + if list.len() == 0 { + return + } + let mut panic_runtime = None; + for (i, linkage) in list.iter().enumerate() { + if let Linkage::NotLinked = *linkage { + continue + } + let cnum = CrateNum::new(i + 1); + + if tcx.is_panic_runtime(cnum) { + if let Some((prev, _)) = panic_runtime { + let prev_name = tcx.crate_name(prev); + let cur_name = tcx.crate_name(cnum); + sess.err(&format!("cannot link together two \ + panic runtimes: {} and {}", + prev_name, cur_name)); + } + panic_runtime = Some((cnum, tcx.panic_strategy(cnum))); + } + } + + // If we found a panic runtime, then we know by this point that it's the + // only one, but we perform validation here that all the panic strategy + // compilation modes for the whole DAG are valid. + if let Some((cnum, found_strategy)) = panic_runtime { + let desired_strategy = sess.panic_strategy(); + + // First up, validate that our selected panic runtime is indeed exactly + // our same strategy. + if found_strategy != desired_strategy { + sess.err(&format!("the linked panic runtime `{}` is \ + not compiled with this crate's \ + panic strategy `{}`", + tcx.crate_name(cnum), + desired_strategy.desc())); + } + + // Next up, verify that all other crates are compatible with this panic + // strategy. If the dep isn't linked, we ignore it, and if our strategy + // is abort then it's compatible with everything. Otherwise all crates' + // panic strategy must match our own. + for (i, linkage) in list.iter().enumerate() { + if let Linkage::NotLinked = *linkage { + continue + } + if desired_strategy == PanicStrategy::Abort { + continue + } + let cnum = CrateNum::new(i + 1); + let found_strategy = tcx.panic_strategy(cnum); + let is_compiler_builtins = tcx.is_compiler_builtins(cnum); + if is_compiler_builtins || desired_strategy == found_strategy { + continue + } + + sess.err(&format!("the crate `{}` is compiled with the \ + panic strategy `{}` which is \ + incompatible with this crate's \ + strategy of `{}`", + tcx.crate_name(cnum), + found_strategy.desc(), + desired_strategy.desc())); + } + } +} diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index d73a4966bca8c..bbfbba2e0d8f4 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -8,6 +8,7 @@ use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LocalDefId, use rustc::hir::GenericParamKind; use rustc::hir::map::definitions::DefPathTable; use rustc_data_structures::fingerprint::Fingerprint; +use rustc_index::vec::IndexVec; use rustc::middle::dependency_format::Linkage; use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel, metadata_symbol_name}; @@ -30,8 +31,9 @@ use rustc_data_structures::sync::Lrc; use std::u32; use syntax::ast; use syntax::attr; +use syntax::ext::proc_macro::is_proc_macro_attr; use syntax::source_map::Spanned; -use syntax::symbol::{kw, sym}; +use syntax::symbol::{kw, sym, Ident, Symbol}; use syntax_pos::{self, FileName, SourceFile, Span}; use log::{debug, trace}; @@ -97,17 +99,17 @@ impl<'tcx> Encoder for EncodeContext<'tcx> { impl<'tcx, T> SpecializedEncoder> for EncodeContext<'tcx> { fn specialized_encode(&mut self, lazy: &Lazy) -> Result<(), Self::Error> { - self.emit_lazy_distance(lazy.position, Lazy::::min_size()) + self.emit_lazy_distance(*lazy) } } -impl<'tcx, T> SpecializedEncoder> for EncodeContext<'tcx> { - fn specialized_encode(&mut self, seq: &LazySeq) -> Result<(), Self::Error> { - self.emit_usize(seq.len)?; - if seq.len == 0 { +impl<'tcx, T> SpecializedEncoder> for EncodeContext<'tcx> { + fn specialized_encode(&mut self, lazy: &Lazy<[T]>) -> Result<(), Self::Error> { + self.emit_usize(lazy.meta)?; + if lazy.meta == 0 { return Ok(()); } - self.emit_lazy_distance(seq.position, LazySeq::::min_size(seq.len)) + self.emit_lazy_distance(*lazy) } } @@ -173,6 +175,13 @@ impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { } } +impl SpecializedEncoder for EncodeContext<'tcx> { + fn specialized_encode(&mut self, ident: &Ident) -> Result<(), Self::Error> { + // FIXME(jseyfried): intercrate hygiene + ident.name.encode(self) + } +} + impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { #[inline] fn specialized_encode(&mut self, def_id: &LocalDefId) -> Result<(), Self::Error> { @@ -231,21 +240,38 @@ impl<'tcx> TyEncoder for EncodeContext<'tcx> { } } -impl<'tcx> EncodeContext<'tcx> { - fn emit_node R, R>(&mut self, f: F) -> R { - assert_eq!(self.lazy_state, LazyState::NoNode); - let pos = self.position(); - self.lazy_state = LazyState::NodeStart(pos); - let r = f(self, pos); - self.lazy_state = LazyState::NoNode; - r +/// Helper trait to allow overloading `EncodeContext::lazy` for iterators. +trait EncodeContentsForLazy { + fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'tcx>) -> T::Meta; +} + +impl EncodeContentsForLazy for &T { + fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'tcx>) { + self.encode(ecx).unwrap() } +} - fn emit_lazy_distance(&mut self, - position: usize, - min_size: usize) - -> Result<(), ::Error> { - let min_end = position + min_size; +impl EncodeContentsForLazy for T { + fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'tcx>) { + self.encode(ecx).unwrap() + } +} + +impl EncodeContentsForLazy<[T]> for I + where I: IntoIterator, + I::Item: EncodeContentsForLazy, +{ + fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'tcx>) -> usize { + self.into_iter().map(|value| value.encode_contents_for_lazy(ecx)).count() + } +} + +impl<'tcx> EncodeContext<'tcx> { + fn emit_lazy_distance( + &mut self, + lazy: Lazy, + ) -> Result<(), ::Error> { + let min_end = lazy.position + T::min_size(lazy.meta); let distance = match self.lazy_state { LazyState::NoNode => bug!("emit_lazy_distance: outside of a metadata node"), LazyState::NodeStart(start) => { @@ -254,48 +280,31 @@ impl<'tcx> EncodeContext<'tcx> { } LazyState::Previous(last_min_end) => { assert!( - last_min_end <= position, + last_min_end <= lazy.position, "make sure that the calls to `lazy*` \ are in the same order as the metadata fields", ); - position - last_min_end + lazy.position - last_min_end } }; self.lazy_state = LazyState::Previous(min_end); self.emit_usize(distance) } - pub fn lazy(&mut self, value: &T) -> Lazy { - self.emit_node(|ecx, pos| { - value.encode(ecx).unwrap(); - - assert!(pos + Lazy::::min_size() <= ecx.position()); - Lazy::with_position(pos) - }) - } - - pub fn lazy_seq(&mut self, iter: I) -> LazySeq - where I: IntoIterator, - T: Encodable - { - self.emit_node(|ecx, pos| { - let len = iter.into_iter().map(|value| value.encode(ecx).unwrap()).count(); + fn lazy( + &mut self, + value: impl EncodeContentsForLazy, + ) -> Lazy { + let pos = self.position(); - assert!(pos + LazySeq::::min_size(len) <= ecx.position()); - LazySeq::with_position_and_length(pos, len) - }) - } + assert_eq!(self.lazy_state, LazyState::NoNode); + self.lazy_state = LazyState::NodeStart(pos); + let meta = value.encode_contents_for_lazy(self); + self.lazy_state = LazyState::NoNode; - pub fn lazy_seq_ref<'b, I, T>(&mut self, iter: I) -> LazySeq - where I: IntoIterator, - T: 'b + Encodable - { - self.emit_node(|ecx, pos| { - let len = iter.into_iter().map(|value| value.encode(ecx).unwrap()).count(); + assert!(pos + ::min_size(meta) <= self.position()); - assert!(pos + LazySeq::::min_size(len) <= ecx.position()); - LazySeq::with_position_and_length(pos, len) - }) + Lazy::from_position_and_meta(pos, meta) } /// Emit the data for a `DefId` to the metadata. The function to @@ -312,7 +321,7 @@ impl<'tcx> EncodeContext<'tcx> { assert!(id.is_local()); let entry = op(self, data); - let entry = self.lazy(&entry); + let entry = self.lazy(entry); self.entries_index.record(id, entry); } @@ -333,7 +342,7 @@ impl<'tcx> EncodeContext<'tcx> { self.lazy(definitions.def_path_table()) } - fn encode_source_map(&mut self) -> LazySeq { + fn encode_source_map(&mut self) -> Lazy<[syntax_pos::SourceFile]> { let source_map = self.tcx.sess.source_map(); let all_source_files = source_map.files(); @@ -359,9 +368,9 @@ impl<'tcx> EncodeContext<'tcx> { let mut adapted = (**source_file).clone(); adapted.name = Path::new(&working_dir).join(name).into(); adapted.name_hash = { - let mut hasher: StableHasher = StableHasher::new(); + let mut hasher: StableHasher = StableHasher::new(); adapted.name.hash(&mut hasher); - hasher.finish() + hasher.finish::() }; Lrc::new(adapted) }, @@ -372,10 +381,12 @@ impl<'tcx> EncodeContext<'tcx> { }) .collect::>(); - self.lazy_seq_ref(adapted.iter().map(|rc| &**rc)) + self.lazy(adapted.iter().map(|rc| &**rc)) } fn encode_crate_root(&mut self) -> Lazy> { + let is_proc_macro = self.tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro); + let mut i = self.position(); let crate_deps = self.encode_crate_deps(); @@ -393,6 +404,11 @@ impl<'tcx> EncodeContext<'tcx> { let lang_items_missing = self.encode_lang_items_missing(); let lang_item_bytes = self.position() - i; + // Encode the diagnostic items. + i = self.position(); + let diagnostic_items = self.encode_diagnostic_items(); + let diagnostic_item_bytes = self.position() - i; + // Encode the native libraries used i = self.position(); let native_libraries = self.encode_native_libraries(); @@ -453,20 +469,26 @@ impl<'tcx> EncodeContext<'tcx> { } n = new_n; } - self.lazy_seq(interpret_alloc_index) + self.lazy(interpret_alloc_index) }; + i = self.position(); let entries_index = self.entries_index.write_index(&mut self.opaque); let entries_index_bytes = self.position() - i; + // Encode the proc macro data + i = self.position(); + let proc_macro_data = self.encode_proc_macros(); + let proc_macro_data_bytes = self.position() - i; + + let attrs = tcx.hir().krate_attrs(); - let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro); let has_default_lib_allocator = attr::contains_name(&attrs, sym::default_lib_allocator); let has_global_allocator = *tcx.sess.has_global_allocator.get(); let has_panic_handler = *tcx.sess.has_panic_handler.try_get().unwrap_or(&false); - let root = self.lazy(&CrateRoot { + let root = self.lazy(CrateRoot { name: tcx.crate_name(LOCAL_CRATE), extra_filename: tcx.sess.opts.cg.extra_filename.clone(), triple: tcx.sess.opts.target_triple.clone(), @@ -484,6 +506,7 @@ impl<'tcx> EncodeContext<'tcx> { } else { None }, + proc_macro_data, proc_macro_stability: if is_proc_macro { tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).map(|stab| stab.clone()) } else { @@ -502,6 +525,7 @@ impl<'tcx> EncodeContext<'tcx> { dylib_dependency_formats, lib_features, lang_items, + diagnostic_items, lang_items_missing, native_libraries, foreign_modules, @@ -527,11 +551,13 @@ impl<'tcx> EncodeContext<'tcx> { println!(" dep bytes: {}", dep_bytes); println!(" lib feature bytes: {}", lib_feature_bytes); println!(" lang item bytes: {}", lang_item_bytes); + println!(" diagnostic item bytes: {}", diagnostic_item_bytes); println!(" native bytes: {}", native_lib_bytes); println!(" source_map bytes: {}", source_map_bytes); println!(" impl bytes: {}", impl_bytes); println!(" exp. symbols bytes: {}", exported_symbols_bytes); println!(" def-path table bytes: {}", def_path_table_bytes); + println!(" proc-macro-data-bytes: {}", proc_macro_data_bytes); println!(" item bytes: {}", item_bytes); println!(" entries index bytes: {}", entries_index_bytes); println!(" zero bytes: {}", zero_bytes); @@ -543,17 +569,17 @@ impl<'tcx> EncodeContext<'tcx> { } impl EncodeContext<'tcx> { - fn encode_variances_of(&mut self, def_id: DefId) -> LazySeq { + fn encode_variances_of(&mut self, def_id: DefId) -> Lazy<[ty::Variance]> { debug!("EncodeContext::encode_variances_of({:?})", def_id); let tcx = self.tcx; - self.lazy_seq_ref(&tcx.variances_of(def_id)[..]) + self.lazy(&tcx.variances_of(def_id)[..]) } fn encode_item_type(&mut self, def_id: DefId) -> Lazy> { let tcx = self.tcx; let ty = tcx.type_of(def_id); debug!("EncodeContext::encode_item_type({:?}) => {:?}", def_id, ty); - self.lazy(&ty) + self.lazy(ty) } fn encode_enum_variant_info( @@ -582,11 +608,11 @@ impl EncodeContext<'tcx> { let enum_vis = &tcx.hir().expect_item(enum_id).vis; Entry { - kind: EntryKind::Variant(self.lazy(&data)), - visibility: self.lazy(&ty::Visibility::from_hir(enum_vis, enum_id, tcx)), - span: self.lazy(&tcx.def_span(def_id)), + kind: EntryKind::Variant(self.lazy(data)), + visibility: self.lazy(ty::Visibility::from_hir(enum_vis, enum_id, tcx)), + span: self.lazy(tcx.def_span(def_id)), attributes: self.encode_attributes(&tcx.get_attrs(def_id)), - children: self.lazy_seq(variant.fields.iter().map(|f| { + children: self.lazy(variant.fields.iter().map(|f| { assert!(f.did.is_local()); f.did.index })), @@ -594,17 +620,18 @@ impl EncodeContext<'tcx> { deprecation: self.encode_deprecation(def_id), ty: Some(self.encode_item_type(def_id)), - inherent_impls: LazySeq::empty(), + inherent_impls: Lazy::empty(), variances: if variant.ctor_kind == CtorKind::Fn { self.encode_variances_of(def_id) } else { - LazySeq::empty() + Lazy::empty() }, generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), predicates_defined_on: None, mir: self.encode_optimized_mir(def_id), + promoted_mir: self.encode_promoted_mir(def_id), } } @@ -623,7 +650,7 @@ impl EncodeContext<'tcx> { discr: variant.discr, ctor: Some(def_id.index), ctor_sig: if variant.ctor_kind == CtorKind::Fn { - Some(self.lazy(&tcx.fn_sig(def_id))) + Some(self.lazy(tcx.fn_sig(def_id))) } else { None } @@ -639,26 +666,27 @@ impl EncodeContext<'tcx> { } Entry { - kind: EntryKind::Variant(self.lazy(&data)), - visibility: self.lazy(&ctor_vis), - span: self.lazy(&tcx.def_span(def_id)), - attributes: LazySeq::empty(), - children: LazySeq::empty(), + kind: EntryKind::Variant(self.lazy(data)), + visibility: self.lazy(ctor_vis), + span: self.lazy(tcx.def_span(def_id)), + attributes: Lazy::empty(), + children: Lazy::empty(), stability: self.encode_stability(def_id), deprecation: self.encode_deprecation(def_id), ty: Some(self.encode_item_type(def_id)), - inherent_impls: LazySeq::empty(), + inherent_impls: Lazy::empty(), variances: if variant.ctor_kind == CtorKind::Fn { self.encode_variances_of(def_id) } else { - LazySeq::empty() + Lazy::empty() }, generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), predicates_defined_on: None, mir: self.encode_optimized_mir(def_id), + promoted_mir: self.encode_promoted_mir(def_id), } } @@ -672,30 +700,31 @@ impl EncodeContext<'tcx> { let data = ModData { reexports: match tcx.module_exports(def_id) { - Some(exports) => self.lazy_seq_ref(exports), - _ => LazySeq::empty(), + Some(exports) => self.lazy(exports), + _ => Lazy::empty(), }, }; Entry { - kind: EntryKind::Mod(self.lazy(&data)), - visibility: self.lazy(&ty::Visibility::from_hir(vis, id, tcx)), - span: self.lazy(&tcx.def_span(def_id)), + kind: EntryKind::Mod(self.lazy(data)), + visibility: self.lazy(ty::Visibility::from_hir(vis, id, tcx)), + span: self.lazy(tcx.def_span(def_id)), attributes: self.encode_attributes(attrs), - children: self.lazy_seq(md.item_ids.iter().map(|item_id| { + children: self.lazy(md.item_ids.iter().map(|item_id| { tcx.hir().local_def_id(item_id.id).index })), stability: self.encode_stability(def_id), deprecation: self.encode_deprecation(def_id), ty: None, - inherent_impls: LazySeq::empty(), - variances: LazySeq::empty(), + inherent_impls: Lazy::empty(), + variances: Lazy::empty(), generics: None, predicates: None, predicates_defined_on: None, - mir: None + mir: None, + promoted_mir: None, } } @@ -715,21 +744,22 @@ impl EncodeContext<'tcx> { Entry { kind: EntryKind::Field, - visibility: self.lazy(&field.vis), - span: self.lazy(&tcx.def_span(def_id)), + visibility: self.lazy(field.vis), + span: self.lazy(tcx.def_span(def_id)), attributes: self.encode_attributes(&variant_data.fields()[field_index].attrs), - children: LazySeq::empty(), + children: Lazy::empty(), stability: self.encode_stability(def_id), deprecation: self.encode_deprecation(def_id), ty: Some(self.encode_item_type(def_id)), - inherent_impls: LazySeq::empty(), - variances: LazySeq::empty(), + inherent_impls: Lazy::empty(), + variances: Lazy::empty(), generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), predicates_defined_on: None, mir: None, + promoted_mir: None, } } @@ -744,7 +774,7 @@ impl EncodeContext<'tcx> { discr: variant.discr, ctor: Some(def_id.index), ctor_sig: if variant.ctor_kind == CtorKind::Fn { - Some(self.lazy(&tcx.fn_sig(def_id))) + Some(self.lazy(tcx.fn_sig(def_id))) } else { None } @@ -770,26 +800,27 @@ impl EncodeContext<'tcx> { let repr_options = get_repr_options(tcx, adt_def_id); Entry { - kind: EntryKind::Struct(self.lazy(&data), repr_options), - visibility: self.lazy(&ctor_vis), - span: self.lazy(&tcx.def_span(def_id)), - attributes: LazySeq::empty(), - children: LazySeq::empty(), + kind: EntryKind::Struct(self.lazy(data), repr_options), + visibility: self.lazy(ctor_vis), + span: self.lazy(tcx.def_span(def_id)), + attributes: Lazy::empty(), + children: Lazy::empty(), stability: self.encode_stability(def_id), deprecation: self.encode_deprecation(def_id), ty: Some(self.encode_item_type(def_id)), - inherent_impls: LazySeq::empty(), + inherent_impls: Lazy::empty(), variances: if variant.ctor_kind == CtorKind::Fn { self.encode_variances_of(def_id) } else { - LazySeq::empty() + Lazy::empty() }, generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), predicates_defined_on: None, mir: self.encode_optimized_mir(def_id), + promoted_mir: self.encode_promoted_mir(def_id), } } @@ -802,13 +833,13 @@ impl EncodeContext<'tcx> { fn encode_predicates(&mut self, def_id: DefId) -> Lazy> { debug!("EncodeContext::encode_predicates({:?})", def_id); let tcx = self.tcx; - self.lazy(&tcx.predicates_of(def_id)) + self.lazy(&*tcx.predicates_of(def_id)) } fn encode_predicates_defined_on(&mut self, def_id: DefId) -> Lazy> { debug!("EncodeContext::encode_predicates_defined_on({:?})", def_id); let tcx = self.tcx; - self.lazy(&tcx.predicates_defined_on(def_id)) + self.lazy(&*tcx.predicates_defined_on(def_id)) } fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> { @@ -830,38 +861,32 @@ impl EncodeContext<'tcx> { let kind = match trait_item.kind { ty::AssocKind::Const => { - let const_qualif = - if let hir::TraitItemKind::Const(_, Some(body)) = ast_item.node { - self.const_qualif(0, body) - } else { - ConstQualif { mir: 0, ast_promotable: false } - }; - let rendered = hir::print::to_string(self.tcx.hir(), |s| s.print_trait_item(ast_item)); - let rendered_const = self.lazy(&RenderedConst(rendered)); + let rendered_const = self.lazy(RenderedConst(rendered)); - EntryKind::AssocConst(container, const_qualif, rendered_const) + EntryKind::AssocConst(container, ConstQualif { mir: 0 }, rendered_const) } ty::AssocKind::Method => { - let fn_data = if let hir::TraitItemKind::Method(_, ref m) = ast_item.node { - let arg_names = match *m { + let fn_data = if let hir::TraitItemKind::Method(method_sig, m) = &ast_item.kind { + let param_names = match *m { hir::TraitMethod::Required(ref names) => { - self.encode_fn_arg_names(names) + self.encode_fn_param_names(names) } hir::TraitMethod::Provided(body) => { - self.encode_fn_arg_names_for_body(body) + self.encode_fn_param_names_for_body(body) } }; FnData { + asyncness: method_sig.header.asyncness, constness: hir::Constness::NotConst, - arg_names, + param_names, sig: self.lazy(&tcx.fn_sig(def_id)), } } else { bug!() }; - EntryKind::Method(self.lazy(&MethodData { + EntryKind::Method(self.lazy(MethodData { fn_data, container, has_self: trait_item.method_has_self_argument, @@ -873,10 +898,10 @@ impl EncodeContext<'tcx> { Entry { kind, - visibility: self.lazy(&trait_item.vis), - span: self.lazy(&ast_item.span), + visibility: self.lazy(trait_item.vis), + span: self.lazy(ast_item.span), attributes: self.encode_attributes(&ast_item.attrs), - children: LazySeq::empty(), + children: Lazy::empty(), stability: self.encode_stability(def_id), deprecation: self.encode_deprecation(def_id), @@ -894,17 +919,18 @@ impl EncodeContext<'tcx> { } ty::AssocKind::OpaqueTy => unreachable!(), }, - inherent_impls: LazySeq::empty(), + inherent_impls: Lazy::empty(), variances: if trait_item.kind == ty::AssocKind::Method { self.encode_variances_of(def_id) } else { - LazySeq::empty() + Lazy::empty() }, generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), predicates_defined_on: None, mir: self.encode_optimized_mir(def_id), + promoted_mir: self.encode_promoted_mir(def_id), } } @@ -913,13 +939,6 @@ impl EncodeContext<'tcx> { !self.tcx.sess.opts.output_types.should_codegen() } - fn const_qualif(&self, mir: u8, body_id: hir::BodyId) -> ConstQualif { - let body_owner_def_id = self.tcx.hir().body_owner_def_id(body_id); - let ast_promotable = self.tcx.const_is_rvalue_promotable_to_static(body_owner_def_id); - - ConstQualif { mir, ast_promotable } - } - fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> { debug!("EncodeContext::encode_info_for_impl_item({:?})", def_id); let tcx = self.tcx; @@ -937,27 +956,28 @@ impl EncodeContext<'tcx> { let kind = match impl_item.kind { ty::AssocKind::Const => { - if let hir::ImplItemKind::Const(_, body_id) = ast_item.node { + if let hir::ImplItemKind::Const(_, body_id) = ast_item.kind { let mir = self.tcx.at(ast_item.span).mir_const_qualif(def_id).0; EntryKind::AssocConst(container, - self.const_qualif(mir, body_id), + ConstQualif { mir }, self.encode_rendered_const_for_body(body_id)) } else { bug!() } } ty::AssocKind::Method => { - let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node { + let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.kind { FnData { + asyncness: sig.header.asyncness, constness: sig.header.constness, - arg_names: self.encode_fn_arg_names_for_body(body), + param_names: self.encode_fn_param_names_for_body(body), sig: self.lazy(&tcx.fn_sig(def_id)), } } else { bug!() }; - EntryKind::Method(self.lazy(&MethodData { + EntryKind::Method(self.lazy(MethodData { fn_data, container, has_self: impl_item.method_has_self_argument, @@ -967,52 +987,52 @@ impl EncodeContext<'tcx> { ty::AssocKind::Type => EntryKind::AssocType(container) }; - let mir = - match ast_item.node { - hir::ImplItemKind::Const(..) => true, - hir::ImplItemKind::Method(ref sig, _) => { - let generics = self.tcx.generics_of(def_id); - let needs_inline = (generics.requires_monomorphization(self.tcx) || - tcx.codegen_fn_attrs(def_id).requests_inline()) && - !self.metadata_output_only(); - let is_const_fn = sig.header.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 - }, - hir::ImplItemKind::OpaqueTy(..) | - hir::ImplItemKind::TyAlias(..) => false, - }; + let mir = match ast_item.kind { + hir::ImplItemKind::Const(..) => true, + hir::ImplItemKind::Method(ref sig, _) => { + let generics = self.tcx.generics_of(def_id); + let needs_inline = (generics.requires_monomorphization(self.tcx) || + tcx.codegen_fn_attrs(def_id).requests_inline()) && + !self.metadata_output_only(); + let is_const_fn = sig.header.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 + }, + hir::ImplItemKind::OpaqueTy(..) | + hir::ImplItemKind::TyAlias(..) => false, + }; Entry { kind, - visibility: self.lazy(&impl_item.vis), - span: self.lazy(&ast_item.span), + visibility: self.lazy(impl_item.vis), + span: self.lazy(ast_item.span), attributes: self.encode_attributes(&ast_item.attrs), - children: LazySeq::empty(), + children: Lazy::empty(), stability: self.encode_stability(def_id), deprecation: self.encode_deprecation(def_id), ty: Some(self.encode_item_type(def_id)), - inherent_impls: LazySeq::empty(), + inherent_impls: Lazy::empty(), variances: if impl_item.kind == ty::AssocKind::Method { self.encode_variances_of(def_id) } else { - LazySeq::empty() + Lazy::empty() }, generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), predicates_defined_on: None, mir: if mir { self.encode_optimized_mir(def_id) } else { None }, + promoted_mir: if mir { self.encode_promoted_mir(def_id) } else { None }, } } - fn encode_fn_arg_names_for_body(&mut self, body_id: hir::BodyId) - -> LazySeq { + fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) + -> Lazy<[ast::Name]> { self.tcx.dep_graph.with_ignore(|| { let body = self.tcx.hir().body(body_id); - self.lazy_seq(body.arguments.iter().map(|arg| { - match arg.pat.node { + self.lazy(body.params.iter().map(|arg| { + match arg.pat.kind { PatKind::Binding(_, _, ident, _) => ident.name, _ => kw::Invalid, } @@ -1020,28 +1040,41 @@ impl EncodeContext<'tcx> { }) } - fn encode_fn_arg_names(&mut self, param_names: &[ast::Ident]) -> LazySeq { - self.lazy_seq(param_names.iter().map(|ident| ident.name)) + fn encode_fn_param_names(&mut self, param_names: &[ast::Ident]) -> Lazy<[ast::Name]> { + self.lazy(param_names.iter().map(|ident| ident.name)) } fn encode_optimized_mir(&mut self, def_id: DefId) -> Option>> { debug!("EntryBuilder::encode_mir({:?})", def_id); if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) { let mir = self.tcx.optimized_mir(def_id); - Some(self.lazy(&mir)) + Some(self.lazy(mir)) + } else { + None + } + } + + fn encode_promoted_mir( + &mut self, + def_id: DefId, + ) -> Option>>> { + debug!("EncodeContext::encode_promoted_mir({:?})", def_id); + if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) { + let promoted = self.tcx.promoted_mir(def_id); + Some(self.lazy(promoted)) } else { None } } // Encodes the inherent implementations of a structure, enumeration, or trait. - fn encode_inherent_implementations(&mut self, def_id: DefId) -> LazySeq { + fn encode_inherent_implementations(&mut self, def_id: DefId) -> Lazy<[DefIndex]> { debug!("EncodeContext::encode_inherent_implementations({:?})", def_id); let implementations = self.tcx.inherent_impls(def_id); if implementations.is_empty() { - LazySeq::empty() + Lazy::empty() } else { - self.lazy_seq(implementations.iter().map(|&def_id| { + self.lazy(implementations.iter().map(|&def_id| { assert!(def_id.is_local()); def_id.index })) @@ -1055,7 +1088,7 @@ impl EncodeContext<'tcx> { fn encode_deprecation(&mut self, def_id: DefId) -> Option> { debug!("EncodeContext::encode_deprecation({:?})", def_id); - self.tcx.lookup_deprecation(def_id).map(|depr| self.lazy(&depr)) + self.tcx.lookup_deprecation(def_id).map(|depr| self.lazy(depr)) } fn encode_rendered_const_for_body(&mut self, body_id: hir::BodyId) -> Lazy { @@ -1070,24 +1103,25 @@ impl EncodeContext<'tcx> { debug!("EncodeContext::encode_info_for_item({:?})", def_id); - let kind = match item.node { + let kind = match item.kind { hir::ItemKind::Static(_, hir::MutMutable, _) => EntryKind::MutStatic, hir::ItemKind::Static(_, hir::MutImmutable, _) => EntryKind::ImmStatic, hir::ItemKind::Const(_, body_id) => { let mir = tcx.at(item.span).mir_const_qualif(def_id).0; EntryKind::Const( - self.const_qualif(mir, body_id), + ConstQualif { mir }, self.encode_rendered_const_for_body(body_id) ) } hir::ItemKind::Fn(_, header, .., body) => { let data = FnData { + asyncness: header.asyncness, constness: header.constness, - arg_names: self.encode_fn_arg_names_for_body(body), - sig: self.lazy(&tcx.fn_sig(def_id)), + param_names: self.encode_fn_param_names_for_body(body), + sig: self.lazy(tcx.fn_sig(def_id)), }; - EntryKind::Fn(self.lazy(&data)) + EntryKind::Fn(self.lazy(data)) } hir::ItemKind::Mod(ref m) => { return self.encode_info_for_mod((item.hir_id, m, &item.attrs, &item.vis)); @@ -1108,7 +1142,7 @@ impl EncodeContext<'tcx> { let repr_options = get_repr_options(tcx, def_id); - EntryKind::Struct(self.lazy(&VariantData { + EntryKind::Struct(self.lazy(VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, ctor, @@ -1119,15 +1153,16 @@ impl EncodeContext<'tcx> { let variant = tcx.adt_def(def_id).non_enum_variant(); let repr_options = get_repr_options(tcx, def_id); - EntryKind::Union(self.lazy(&VariantData { + EntryKind::Union(self.lazy(VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, ctor: None, ctor_sig: None, }), repr_options) } - hir::ItemKind::Impl(_, polarity, defaultness, ..) => { + hir::ItemKind::Impl(_, _, defaultness, ..) => { let trait_ref = tcx.impl_trait_ref(def_id); + let polarity = tcx.impl_polarity(def_id); let parent = if let Some(trait_ref) = trait_ref { let trait_def = tcx.trait_def(trait_ref.def_id); trait_def.ancestors(tcx, def_id).nth(1).and_then(|node| { @@ -1156,10 +1191,10 @@ impl EncodeContext<'tcx> { defaultness, parent_impl: parent, coerce_unsized_info, - trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)), + trait_ref: trait_ref.map(|trait_ref| self.lazy(trait_ref)), }; - EntryKind::Impl(self.lazy(&data)) + EntryKind::Impl(self.lazy(data)) } hir::ItemKind::Trait(..) => { let trait_def = tcx.trait_def(def_id); @@ -1168,37 +1203,51 @@ impl EncodeContext<'tcx> { paren_sugar: trait_def.paren_sugar, has_auto_impl: tcx.trait_is_auto(def_id), is_marker: trait_def.is_marker, - super_predicates: self.lazy(&tcx.super_predicates_of(def_id)), + super_predicates: self.lazy(&*tcx.super_predicates_of(def_id)), }; - EntryKind::Trait(self.lazy(&data)) + EntryKind::Trait(self.lazy(data)) } hir::ItemKind::TraitAlias(..) => { let data = TraitAliasData { - super_predicates: self.lazy(&tcx.super_predicates_of(def_id)), + super_predicates: self.lazy(&*tcx.super_predicates_of(def_id)), }; - EntryKind::TraitAlias(self.lazy(&data)) + EntryKind::TraitAlias(self.lazy(data)) } hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => bug!("cannot encode info for item {:?}", item), }; + let mir = match item.kind { + hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => true, + hir::ItemKind::Fn(_, header, ..) => { + let generics = tcx.generics_of(def_id); + let needs_inline = + (generics.requires_monomorphization(tcx) || + tcx.codegen_fn_attrs(def_id).requests_inline()) && + !self.metadata_output_only(); + let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; + needs_inline || header.constness == hir::Constness::Const || always_encode_mir + } + _ => false, + }; + Entry { kind, - visibility: self.lazy(&ty::Visibility::from_hir(&item.vis, item.hir_id, tcx)), - span: self.lazy(&item.span), + visibility: self.lazy(ty::Visibility::from_hir(&item.vis, item.hir_id, tcx)), + span: self.lazy(item.span), attributes: self.encode_attributes(&item.attrs), - children: match item.node { + children: match item.kind { hir::ItemKind::ForeignMod(ref fm) => { - self.lazy_seq(fm.items + self.lazy(fm.items .iter() .map(|foreign_item| tcx.hir().local_def_id( foreign_item.hir_id).index)) } hir::ItemKind::Enum(..) => { let def = self.tcx.adt_def(def_id); - self.lazy_seq(def.variants.iter().map(|v| { + self.lazy(def.variants.iter().map(|v| { assert!(v.def_id.is_local()); v.def_id.index })) @@ -1206,24 +1255,24 @@ impl EncodeContext<'tcx> { hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => { let def = self.tcx.adt_def(def_id); - self.lazy_seq(def.non_enum_variant().fields.iter().map(|f| { + self.lazy(def.non_enum_variant().fields.iter().map(|f| { assert!(f.did.is_local()); f.did.index })) } hir::ItemKind::Impl(..) | hir::ItemKind::Trait(..) => { - self.lazy_seq(tcx.associated_item_def_ids(def_id).iter().map(|&def_id| { + self.lazy(tcx.associated_item_def_ids(def_id).iter().map(|&def_id| { assert!(def_id.is_local()); def_id.index })) } - _ => LazySeq::empty(), + _ => Lazy::empty(), }, stability: self.encode_stability(def_id), deprecation: self.encode_deprecation(def_id), - ty: match item.node { + ty: match item.kind { hir::ItemKind::Static(..) | hir::ItemKind::Const(..) | hir::ItemKind::Fn(..) | @@ -1236,14 +1285,14 @@ impl EncodeContext<'tcx> { _ => None, }, inherent_impls: self.encode_inherent_implementations(def_id), - variances: match item.node { + variances: match item.kind { hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | hir::ItemKind::Fn(..) => self.encode_variances_of(def_id), - _ => LazySeq::empty(), + _ => Lazy::empty(), }, - generics: match item.node { + generics: match item.kind { hir::ItemKind::Static(..) | hir::ItemKind::Const(..) | hir::ItemKind::Fn(..) | @@ -1257,7 +1306,7 @@ impl EncodeContext<'tcx> { hir::ItemKind::TraitAlias(..) => Some(self.encode_generics(def_id)), _ => None, }, - predicates: match item.node { + predicates: match item.kind { hir::ItemKind::Static(..) | hir::ItemKind::Const(..) | hir::ItemKind::Fn(..) | @@ -1277,35 +1326,14 @@ impl EncodeContext<'tcx> { // so only encode it in that case as an efficiency // hack. (No reason not to expand it in the future if // necessary.) - predicates_defined_on: match item.node { + predicates_defined_on: match item.kind { hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => Some(self.encode_predicates_defined_on(def_id)), _ => None, // not *wrong* for other kinds of items, but not needed }, - mir: match item.node { - hir::ItemKind::Static(..) => { - self.encode_optimized_mir(def_id) - } - hir::ItemKind::Const(..) => self.encode_optimized_mir(def_id), - hir::ItemKind::Fn(_, header, ..) => { - let generics = tcx.generics_of(def_id); - let needs_inline = - (generics.requires_monomorphization(tcx) || - tcx.codegen_fn_attrs(def_id).requests_inline()) && - !self.metadata_output_only(); - let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; - if needs_inline - || header.constness == hir::Constness::Const - || always_encode_mir - { - self.encode_optimized_mir(def_id) - } else { - None - } - } - _ => None, - }, + mir: if mir { self.encode_optimized_mir(def_id) } else { None }, + promoted_mir: if mir { self.encode_promoted_mir(def_id) } else { None }, } } @@ -1314,24 +1342,25 @@ impl EncodeContext<'tcx> { use syntax::print::pprust; let def_id = self.tcx.hir().local_def_id(macro_def.hir_id); Entry { - kind: EntryKind::MacroDef(self.lazy(&MacroDef { - body: pprust::tokens_to_string(macro_def.body.clone()), + kind: EntryKind::MacroDef(self.lazy(MacroDef { + body: pprust::tts_to_string(macro_def.body.clone()), legacy: macro_def.legacy, })), - visibility: self.lazy(&ty::Visibility::Public), - span: self.lazy(¯o_def.span), + visibility: self.lazy(ty::Visibility::Public), + span: self.lazy(macro_def.span), attributes: self.encode_attributes(¯o_def.attrs), stability: self.encode_stability(def_id), deprecation: self.encode_deprecation(def_id), - children: LazySeq::empty(), + children: Lazy::empty(), ty: None, - inherent_impls: LazySeq::empty(), - variances: LazySeq::empty(), + inherent_impls: Lazy::empty(), + variances: Lazy::empty(), generics: None, predicates: None, predicates_defined_on: None, mir: None, + promoted_mir: None, } } @@ -1344,20 +1373,21 @@ impl EncodeContext<'tcx> { let tcx = self.tcx; Entry { kind: entry_kind, - visibility: self.lazy(&ty::Visibility::Public), - span: self.lazy(&tcx.def_span(def_id)), - attributes: LazySeq::empty(), - children: LazySeq::empty(), + visibility: self.lazy(ty::Visibility::Public), + span: self.lazy(tcx.def_span(def_id)), + attributes: Lazy::empty(), + children: Lazy::empty(), stability: None, deprecation: None, ty: if encode_type { Some(self.encode_item_type(def_id)) } else { None }, - inherent_impls: LazySeq::empty(), - variances: LazySeq::empty(), + inherent_impls: Lazy::empty(), + variances: Lazy::empty(), generics: None, predicates: None, predicates_defined_on: None, mir: None, + promoted_mir: None, } } @@ -1383,19 +1413,19 @@ impl EncodeContext<'tcx> { let tables = self.tcx.typeck_tables_of(def_id); let hir_id = self.tcx.hir().as_local_hir_id(def_id).unwrap(); - let kind = match tables.node_type(hir_id).sty { + let kind = match tables.node_type(hir_id).kind { ty::Generator(def_id, ..) => { let layout = self.tcx.generator_layout(def_id); let data = GeneratorData { layout: layout.clone(), }; - EntryKind::Generator(self.lazy(&data)) + EntryKind::Generator(self.lazy(data)) } ty::Closure(def_id, substs) => { - let sig = substs.closure_sig(def_id, self.tcx); - let data = ClosureData { sig: self.lazy(&sig) }; - EntryKind::Closure(self.lazy(&data)) + let sig = substs.as_closure().sig(def_id, self.tcx); + let data = ClosureData { sig: self.lazy(sig) }; + EntryKind::Closure(self.lazy(data)) } _ => bug!("closure that is neither generator nor closure") @@ -1403,21 +1433,22 @@ impl EncodeContext<'tcx> { Entry { kind, - visibility: self.lazy(&ty::Visibility::Public), - span: self.lazy(&tcx.def_span(def_id)), + visibility: self.lazy(ty::Visibility::Public), + span: self.lazy(tcx.def_span(def_id)), attributes: self.encode_attributes(&tcx.get_attrs(def_id)), - children: LazySeq::empty(), + children: Lazy::empty(), stability: None, deprecation: None, ty: Some(self.encode_item_type(def_id)), - inherent_impls: LazySeq::empty(), - variances: LazySeq::empty(), + inherent_impls: Lazy::empty(), + variances: Lazy::empty(), generics: Some(self.encode_generics(def_id)), predicates: None, predicates_defined_on: None, mir: self.encode_optimized_mir(def_id), + promoted_mir: self.encode_promoted_mir(def_id), } } @@ -1430,40 +1461,57 @@ impl EncodeContext<'tcx> { let mir = tcx.mir_const_qualif(def_id).0; Entry { - kind: EntryKind::Const(self.const_qualif(mir, body_id), const_data), - visibility: self.lazy(&ty::Visibility::Public), - span: self.lazy(&tcx.def_span(def_id)), - attributes: LazySeq::empty(), - children: LazySeq::empty(), + kind: EntryKind::Const(ConstQualif { mir }, const_data), + visibility: self.lazy(ty::Visibility::Public), + span: self.lazy(tcx.def_span(def_id)), + attributes: Lazy::empty(), + children: Lazy::empty(), stability: None, deprecation: None, ty: Some(self.encode_item_type(def_id)), - inherent_impls: LazySeq::empty(), - variances: LazySeq::empty(), + inherent_impls: Lazy::empty(), + variances: Lazy::empty(), generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), predicates_defined_on: None, mir: self.encode_optimized_mir(def_id), + promoted_mir: self.encode_promoted_mir(def_id), } } - fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq { - self.lazy_seq_ref(attrs) + fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> Lazy<[ast::Attribute]> { + self.lazy(attrs) } - fn encode_native_libraries(&mut self) -> LazySeq { + fn encode_native_libraries(&mut self) -> Lazy<[NativeLibrary]> { let used_libraries = self.tcx.native_libraries(LOCAL_CRATE); - self.lazy_seq(used_libraries.iter().cloned()) + self.lazy(used_libraries.iter().cloned()) } - fn encode_foreign_modules(&mut self) -> LazySeq { + fn encode_foreign_modules(&mut self) -> Lazy<[ForeignModule]> { let foreign_modules = self.tcx.foreign_modules(LOCAL_CRATE); - self.lazy_seq(foreign_modules.iter().cloned()) + self.lazy(foreign_modules.iter().cloned()) } - fn encode_crate_deps(&mut self) -> LazySeq { + fn encode_proc_macros(&mut self) -> Option> { + let is_proc_macro = self.tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro); + if is_proc_macro { + let tcx = self.tcx; + Some(self.lazy(tcx.hir().krate().items.values().filter_map(|item| { + if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) { + Some(item.hir_id.owner) + } else { + None + } + }))) + } else { + None + } + } + + fn encode_crate_deps(&mut self) -> Lazy<[CrateDep]> { let crates = self.tcx.crates(); let mut deps = crates @@ -1494,20 +1542,26 @@ impl EncodeContext<'tcx> { // the assumption that they are numbered 1 to n. // FIXME (#2166): This is not nearly enough to support correct versioning // but is enough to get transitive crate dependencies working. - self.lazy_seq_ref(deps.iter().map(|&(_, ref dep)| dep)) + self.lazy(deps.iter().map(|&(_, ref dep)| dep)) } - fn encode_lib_features(&mut self) -> LazySeq<(ast::Name, Option)> { + fn encode_lib_features(&mut self) -> Lazy<[(ast::Name, Option)]> { let tcx = self.tcx; let lib_features = tcx.lib_features(); - self.lazy_seq(lib_features.to_vec()) + self.lazy(lib_features.to_vec()) + } + + fn encode_diagnostic_items(&mut self) -> Lazy<[(Symbol, DefIndex)]> { + let tcx = self.tcx; + let diagnostic_items = tcx.diagnostic_items(LOCAL_CRATE); + self.lazy(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index))) } - fn encode_lang_items(&mut self) -> LazySeq<(DefIndex, usize)> { + fn encode_lang_items(&mut self) -> Lazy<[(DefIndex, usize)]> { let tcx = self.tcx; let lang_items = tcx.lang_items(); let lang_items = lang_items.items().iter(); - self.lazy_seq(lang_items.enumerate().filter_map(|(i, &opt_def_id)| { + self.lazy(lang_items.enumerate().filter_map(|(i, &opt_def_id)| { if let Some(def_id) = opt_def_id { if def_id.is_local() { return Some((def_id.index, i)); @@ -1517,13 +1571,13 @@ impl EncodeContext<'tcx> { })) } - fn encode_lang_items_missing(&mut self) -> LazySeq { + fn encode_lang_items_missing(&mut self) -> Lazy<[lang_items::LangItem]> { let tcx = self.tcx; - self.lazy_seq_ref(&tcx.lang_items().missing) + self.lazy(&tcx.lang_items().missing) } /// Encodes an index, mapping each trait to its (local) implementations. - fn encode_impls(&mut self) -> LazySeq { + fn encode_impls(&mut self) -> Lazy<[TraitImpls]> { debug!("EncodeContext::encode_impls()"); let tcx = self.tcx; let mut visitor = ImplVisitor { @@ -1549,12 +1603,12 @@ impl EncodeContext<'tcx> { TraitImpls { trait_id: (trait_def_id.krate.as_u32(), trait_def_id.index), - impls: self.lazy_seq_ref(&impls), + impls: self.lazy(&impls), } }) .collect(); - self.lazy_seq_ref(&all_impls) + self.lazy(&all_impls) } // Encodes all symbols exported from this crate into the metadata. @@ -1565,12 +1619,12 @@ impl EncodeContext<'tcx> { // definition (as that's not defined in this crate). fn encode_exported_symbols(&mut self, exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportLevel)]) - -> LazySeq<(ExportedSymbol<'tcx>, SymbolExportLevel)> { + -> Lazy<[(ExportedSymbol<'tcx>, SymbolExportLevel)]> { // The metadata symbol name is special. It should not show up in // downstream crates. let metadata_symbol_name = SymbolName::new(&metadata_symbol_name(self.tcx)); - self.lazy_seq(exported_symbols + self.lazy(exported_symbols .iter() .filter(|&&(ref exported_symbol, _)| { match *exported_symbol { @@ -1583,21 +1637,23 @@ impl EncodeContext<'tcx> { .cloned()) } - fn encode_dylib_dependency_formats(&mut self) -> LazySeq> { - match self.tcx.sess.dependency_formats.borrow().get(&config::CrateType::Dylib) { - Some(arr) => { - self.lazy_seq(arr.iter().map(|slot| { - match *slot { - Linkage::NotLinked | - Linkage::IncludedFromDylib => None, - - Linkage::Dynamic => Some(LinkagePreference::RequireDynamic), - Linkage::Static => Some(LinkagePreference::RequireStatic), - } - })) + fn encode_dylib_dependency_formats(&mut self) -> Lazy<[Option]> { + let formats = self.tcx.dependency_formats(LOCAL_CRATE); + for (ty, arr) in formats.iter() { + if *ty != config::CrateType::Dylib { + continue; } - None => LazySeq::empty(), + return self.lazy(arr.iter().map(|slot| { + match *slot { + Linkage::NotLinked | + Linkage::IncludedFromDylib => None, + + Linkage::Dynamic => Some(LinkagePreference::RequireDynamic), + Linkage::Static => Some(LinkagePreference::RequireStatic), + } + })); } + Lazy::empty() } fn encode_info_for_foreign_item(&mut self, @@ -1607,14 +1663,15 @@ impl EncodeContext<'tcx> { debug!("EncodeContext::encode_info_for_foreign_item({:?})", def_id); - let kind = match nitem.node { + let kind = match nitem.kind { hir::ForeignItemKind::Fn(_, ref names, _) => { let data = FnData { + asyncness: hir::IsAsync::NotAsync, constness: hir::Constness::NotConst, - arg_names: self.encode_fn_arg_names(names), - sig: self.lazy(&tcx.fn_sig(def_id)), + param_names: self.encode_fn_param_names(names), + sig: self.lazy(tcx.fn_sig(def_id)), }; - EntryKind::ForeignFn(self.lazy(&data)) + EntryKind::ForeignFn(self.lazy(data)) } hir::ForeignItemKind::Static(_, hir::MutMutable) => EntryKind::ForeignMutStatic, hir::ForeignItemKind::Static(_, hir::MutImmutable) => EntryKind::ForeignImmStatic, @@ -1623,24 +1680,25 @@ impl EncodeContext<'tcx> { Entry { kind, - visibility: self.lazy(&ty::Visibility::from_hir(&nitem.vis, nitem.hir_id, tcx)), - span: self.lazy(&nitem.span), + visibility: self.lazy(ty::Visibility::from_hir(&nitem.vis, nitem.hir_id, tcx)), + span: self.lazy(nitem.span), attributes: self.encode_attributes(&nitem.attrs), - children: LazySeq::empty(), + children: Lazy::empty(), stability: self.encode_stability(def_id), deprecation: self.encode_deprecation(def_id), ty: Some(self.encode_item_type(def_id)), - inherent_impls: LazySeq::empty(), - variances: match nitem.node { + inherent_impls: Lazy::empty(), + variances: match nitem.kind { hir::ForeignItemKind::Fn(..) => self.encode_variances_of(def_id), - _ => LazySeq::empty(), + _ => Lazy::empty(), }, generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), predicates_defined_on: None, mir: None, + promoted_mir: None, } } } @@ -1656,7 +1714,7 @@ impl Visitor<'tcx> for EncodeContext<'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { intravisit::walk_item(self, item); let def_id = self.tcx.hir().local_def_id(item.hir_id); - match item.node { + match item.kind { hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => {} // ignore these _ => self.record(def_id, EncodeContext::encode_info_for_item, (def_id, item)), @@ -1676,7 +1734,7 @@ impl Visitor<'tcx> for EncodeContext<'tcx> { id: hir::HirId) { intravisit::walk_variant(self, v, g, id); - if let Some(ref discr) = v.node.disr_expr { + if let Some(ref discr) = v.disr_expr { let def_id = self.tcx.hir().local_def_id(discr.hir_id); self.record(def_id, EncodeContext::encode_info_for_anon_const, def_id); } @@ -1727,7 +1785,7 @@ impl EncodeContext<'tcx> { } fn encode_info_for_ty(&mut self, ty: &hir::Ty) { - match ty.node { + match ty.kind { hir::TyKind::Array(_, ref length) => { let def_id = self.tcx.hir().local_def_id(length.hir_id); self.record(def_id, EncodeContext::encode_info_for_anon_const, def_id); @@ -1737,7 +1795,7 @@ impl EncodeContext<'tcx> { } fn encode_info_for_expr(&mut self, expr: &hir::Expr) { - match expr.node { + match expr.kind { hir::ExprKind::Closure(..) => { let def_id = self.tcx.hir().local_def_id(expr.hir_id); self.record(def_id, EncodeContext::encode_info_for_closure, def_id); @@ -1752,7 +1810,7 @@ impl EncodeContext<'tcx> { /// normally in the visitor walk. fn encode_addl_info_for_item(&mut self, item: &hir::Item) { let def_id = self.tcx.hir().local_def_id(item.hir_id); - match item.node { + match item.kind { hir::ItemKind::Static(..) | hir::ItemKind::Const(..) | hir::ItemKind::Fn(..) | @@ -1821,7 +1879,7 @@ struct ImplVisitor<'tcx> { impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> { fn visit_item(&mut self, item: &hir::Item) { - if let hir::ItemKind::Impl(..) = item.node { + if let hir::ItemKind::Impl(..) = item.kind { let impl_id = self.tcx.hir().local_def_id(item.hir_id); if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_id) { self.impls @@ -1906,7 +1964,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata { pub fn get_repr_options(tcx: TyCtxt<'_>, did: DefId) -> ReprOptions { let ty = tcx.type_of(did); - match ty.sty { + match ty.kind { ty::Adt(ref def, _) => return def.repr, _ => bug!("{} is not an ADT", ty), } diff --git a/src/librustc_metadata/error_codes.rs b/src/librustc_metadata/error_codes.rs index 0708a6243bf29..cd8e95e6c3a11 100644 --- a/src/librustc_metadata/error_codes.rs +++ b/src/librustc_metadata/error_codes.rs @@ -1,6 +1,4 @@ -use syntax::{register_diagnostics, register_long_diagnostics}; - -register_long_diagnostics! { +syntax::register_diagnostics! { E0454: r##" A link name was given with an empty name. Erroneous code example: @@ -84,10 +82,7 @@ You need to link your code to the relevant crate in order to be able to use it (through Cargo or the `-L` option of rustc example). Plugins are crates as well, and you link to them the same way. "##, - -} - -register_diagnostics! { +; E0456, // plugin `..` is not available for triple `..` E0457, // plugin `..` only found in rlib format, but must be available... E0514, // metadata version mismatch @@ -97,5 +92,6 @@ register_diagnostics! { E0464, // multiple matching crates for `..` E0465, // multiple .. candidates for `..` found E0519, // local crate and dependency have same (crate-name, disambiguator) - E0523, // two dependencies have same (crate-name, disambiguator) but different SVH + // two dependencies have same (crate-name, disambiguator) but different SVH + E0523, } diff --git a/src/librustc_metadata/foreign_modules.rs b/src/librustc_metadata/foreign_modules.rs index b2e40282d9332..8a4f6e6f17a51 100644 --- a/src/librustc_metadata/foreign_modules.rs +++ b/src/librustc_metadata/foreign_modules.rs @@ -19,7 +19,7 @@ struct Collector<'tcx> { impl ItemLikeVisitor<'tcx> for Collector<'tcx> { fn visit_item(&mut self, it: &'tcx hir::Item) { - let fm = match it.node { + let fm = match it.kind { hir::ItemKind::ForeignMod(ref fm) => fm, _ => return, }; diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs index dd2f59922ef92..6f248f22cf252 100644 --- a/src/librustc_metadata/index.rs +++ b/src/librustc_metadata/index.rs @@ -108,18 +108,18 @@ impl Index<'tcx> { position.write_to_bytes_at(positions, array_index) } - pub fn write_index(&self, buf: &mut Encoder) -> LazySeq { + pub fn write_index(&self, buf: &mut Encoder) -> Lazy<[Self]> { let pos = buf.position(); // First we write the length of the lower range ... buf.emit_raw_bytes(&(self.positions.len() as u32 / 4).to_le_bytes()); // ... then the values. buf.emit_raw_bytes(&self.positions); - LazySeq::with_position_and_length(pos as usize, self.positions.len() / 4 + 1) + Lazy::from_position_and_meta(pos as usize, self.positions.len() / 4 + 1) } } -impl LazySeq> { +impl Lazy<[Index<'tcx>]> { /// Given the metadata, extract out the offset of a particular /// DefIndex (if any). #[inline(never)] @@ -127,7 +127,7 @@ impl LazySeq> { let bytes = &bytes[self.position..]; debug!("Index::lookup: index={:?} len={:?}", def_index, - self.len); + self.meta); let position = u32::read_from_bytes_at(bytes, 1 + def_index.index()); if position == u32::MAX { @@ -135,7 +135,7 @@ impl LazySeq> { None } else { debug!("Index::lookup: position={:?}", position); - Some(Lazy::with_position(position as usize)) + Some(Lazy::from_position(position as usize)) } } } diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index c96d02d9b37de..9273b064ba9ce 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -8,7 +8,6 @@ #![feature(nll)] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] -#![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(slice_patterns)] #![feature(specialization)] @@ -23,7 +22,7 @@ extern crate rustc; #[macro_use] extern crate rustc_data_structures; -mod error_codes; +pub mod error_codes; mod index; mod encoder; @@ -33,6 +32,7 @@ mod schema; mod native_libs; mod link_args; mod foreign_modules; +mod dependency_format; pub mod creader; pub mod cstore; @@ -68,5 +68,3 @@ pub fn validate_crate_name( sess.unwrap().abort_if_errors(); } } - -__build_diagnostic_array! { librustc_metadata, DIAGNOSTICS } diff --git a/src/librustc_metadata/link_args.rs b/src/librustc_metadata/link_args.rs index 728fd004fcb69..527d4421fca65 100644 --- a/src/librustc_metadata/link_args.rs +++ b/src/librustc_metadata/link_args.rs @@ -27,7 +27,7 @@ struct Collector { impl<'tcx> ItemLikeVisitor<'tcx> for Collector { fn visit_item(&mut self, it: &'tcx hir::Item) { - let fm = match it.node { + let fm = match it.kind { hir::ItemKind::ForeignMod(ref fm) => fm, _ => return, }; diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index 3832c8ee227de..8df236c41cfb8 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -254,7 +254,6 @@ pub struct CrateMismatch { pub struct Context<'a> { pub sess: &'a Session, pub span: Span, - pub ident: Symbol, pub crate_name: Symbol, pub hash: Option<&'a Svh>, pub extra_filename: Option<&'a str>, @@ -262,7 +261,7 @@ pub struct Context<'a> { pub target: &'a Target, pub triple: TargetTriple, pub filesearch: FileSearch<'a>, - pub root: &'a Option, + pub root: Option<&'a CratePaths>, pub rejected_via_hash: Vec, pub rejected_via_triple: Vec, pub rejected_via_kind: Vec, @@ -323,8 +322,8 @@ impl<'a> Context<'a> { pub fn report_errs(self) -> ! { let add = match self.root { - &None => String::new(), - &Some(ref r) => format!(" which `{}` depends on", r.ident), + None => String::new(), + Some(r) => format!(" which `{}` depends on", r.ident), }; let mut msg = "the following crate versions were found:".to_string(); let mut err = if !self.rejected_via_hash.is_empty() { @@ -332,16 +331,16 @@ impl<'a> Context<'a> { self.span, E0460, "found possibly newer version of crate `{}`{}", - self.ident, + self.crate_name, add); err.note("perhaps that crate needs to be recompiled?"); let mismatches = self.rejected_via_hash.iter(); for &CrateMismatch { ref path, .. } in mismatches { - msg.push_str(&format!("\ncrate `{}`: {}", self.ident, path.display())); + msg.push_str(&format!("\ncrate `{}`: {}", self.crate_name, path.display())); } match self.root { - &None => {} - &Some(ref r) => { + None => {} + Some(r) => { for path in r.paths().iter() { msg.push_str(&format!("\ncrate `{}`: {}", r.ident, path.display())); } @@ -355,13 +354,13 @@ impl<'a> Context<'a> { E0461, "couldn't find crate `{}` \ with expected target triple {}{}", - self.ident, + self.crate_name, self.triple, add); let mismatches = self.rejected_via_triple.iter(); for &CrateMismatch { ref path, ref got } in mismatches { msg.push_str(&format!("\ncrate `{}`, target triple {}: {}", - self.ident, + self.crate_name, got, path.display())); } @@ -372,12 +371,12 @@ impl<'a> Context<'a> { self.span, E0462, "found staticlib `{}` instead of rlib or dylib{}", - self.ident, + self.crate_name, add); err.help("please recompile that crate using --crate-type lib"); let mismatches = self.rejected_via_kind.iter(); for &CrateMismatch { ref path, .. } in mismatches { - msg.push_str(&format!("\ncrate `{}`: {}", self.ident, path.display())); + msg.push_str(&format!("\ncrate `{}`: {}", self.crate_name, path.display())); } err.note(&msg); err @@ -387,14 +386,14 @@ impl<'a> Context<'a> { E0514, "found crate `{}` compiled by an incompatible version \ of rustc{}", - self.ident, + self.crate_name, add); err.help(&format!("please recompile that crate using this compiler ({})", rustc_version())); let mismatches = self.rejected_via_version.iter(); for &CrateMismatch { ref path, ref got } in mismatches { msg.push_str(&format!("\ncrate `{}` compiled by {}: {}", - self.ident, + self.crate_name, got, path.display())); } @@ -405,10 +404,10 @@ impl<'a> Context<'a> { self.span, E0463, "can't find crate for `{}`{}", - self.ident, + self.crate_name, add); - if (self.ident == sym::std || self.ident == sym::core) + if (self.crate_name == sym::std || self.crate_name == sym::core) && self.triple != TargetTriple::from_triple(config::host_triple()) { err.note(&format!("the `{}` target may not be installed", self.triple)); } @@ -716,7 +715,9 @@ impl<'a> Context<'a> { let root = metadata.get_root(); if let Some(is_proc_macro) = self.is_proc_macro { - if root.proc_macro_decls_static.is_some() != is_proc_macro { + if root.proc_macro_data.is_some() != is_proc_macro { + info!("Rejecting via proc macro: expected {} got {}", + is_proc_macro, root.proc_macro_data.is_some()); return None; } } diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index 66971bb6f8b1c..24ed8fcd8dd09 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -8,7 +8,7 @@ use rustc_target::spec::abi::Abi; use syntax::attr; use syntax::source_map::Span; use syntax::feature_gate::{self, GateIssue}; -use syntax::symbol::{Symbol, sym}; +use syntax::symbol::{kw, sym, Symbol}; use syntax::{span_err, struct_span_err}; pub fn collect(tcx: TyCtxt<'_>) -> Vec { @@ -35,7 +35,7 @@ struct Collector<'tcx> { impl ItemLikeVisitor<'tcx> for Collector<'tcx> { fn visit_item(&mut self, it: &'tcx hir::Item) { - let fm = match it.node { + let fm = match it.kind { hir::ItemKind::ForeignMod(ref fm) => fm, _ => return, }; @@ -73,6 +73,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { "static-nobundle" => cstore::NativeStaticNobundle, "dylib" => cstore::NativeUnknown, "framework" => cstore::NativeFramework, + "raw-dylib" => cstore::NativeRawDylib, k => { struct_span_err!(self.tcx.sess, item.span(), E0458, "unknown kind: `{}`", k) @@ -132,7 +133,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { impl Collector<'tcx> { fn register_native_lib(&mut self, span: Option, lib: NativeLibrary) { - if lib.name.as_ref().map(|s| s.as_str().is_empty()).unwrap_or(false) { + if lib.name.as_ref().map(|&s| s == kw::Invalid).unwrap_or(false) { match span { Some(span) => { struct_span_err!(self.tcx.sess, span, E0454, @@ -159,7 +160,7 @@ impl Collector<'tcx> { sym::link_cfg, span.unwrap(), GateIssue::Language, - "is feature gated"); + "is unstable"); } if lib.kind == cstore::NativeStaticNobundle && !self.tcx.features().static_nobundle { @@ -167,7 +168,15 @@ impl Collector<'tcx> { sym::static_nobundle, span.unwrap_or_else(|| syntax_pos::DUMMY_SP), GateIssue::Language, - "kind=\"static-nobundle\" is feature gated"); + "kind=\"static-nobundle\" is unstable"); + } + if lib.kind == cstore::NativeRawDylib && + !self.tcx.features().raw_dylib { + feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, + sym::raw_dylib, + span.unwrap_or_else(|| syntax_pos::DUMMY_SP), + GateIssue::Language, + "kind=\"raw-dylib\" is unstable"); } self.libs.push(lib); } diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index c0ac69159330e..4fe9c466cb6da 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -11,6 +11,7 @@ use rustc::session::CrateDisambiguator; use rustc::session::config::SymbolManglingVersion; use rustc::ty::{self, Ty, ReprOptions}; use rustc_target::spec::{PanicStrategy, TargetTriple}; +use rustc_index::vec::IndexVec; use rustc_data_structures::svh::Svh; use syntax::{ast, attr}; @@ -41,6 +42,33 @@ pub const METADATA_VERSION: u8 = 4; pub const METADATA_HEADER: &[u8; 12] = &[0, 0, 0, 0, b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION]; +/// Additional metadata for a `Lazy` where `T` may not be `Sized`, +/// e.g. for `Lazy<[T]>`, this is the length (count of `T` values). +pub trait LazyMeta { + type Meta: Copy + 'static; + + /// Returns the minimum encoded size. + // FIXME(eddyb) Give better estimates for certain types. + fn min_size(meta: Self::Meta) -> usize; +} + +impl LazyMeta for T { + type Meta = (); + + fn min_size(_: ()) -> usize { + assert_ne!(std::mem::size_of::(), 0); + 1 + } +} + +impl LazyMeta for [T] { + type Meta = usize; + + fn min_size(len: usize) -> usize { + len * T::min_size(()) + } +} + /// A value of type T referred to by its absolute position /// in the metadata, and which can be decoded lazily. /// @@ -56,40 +84,8 @@ pub const METADATA_HEADER: &[u8; 12] = /// Distances start at 1, as 0-byte nodes are invalid. /// Also invalid are nodes being referred in a different /// order than they were encoded in. -#[must_use] -pub struct Lazy { - pub position: usize, - _marker: PhantomData, -} - -impl Lazy { - pub fn with_position(position: usize) -> Lazy { - Lazy { - position, - _marker: PhantomData, - } - } - - /// Returns the minimum encoded size of a value of type `T`. - // FIXME(eddyb) Give better estimates for certain types. - pub fn min_size() -> usize { - 1 - } -} - -impl Copy for Lazy {} -impl Clone for Lazy { - fn clone(&self) -> Self { - *self - } -} - -impl rustc_serialize::UseSpecializedEncodable for Lazy {} -impl rustc_serialize::UseSpecializedDecodable for Lazy {} - -/// A sequence of type T referred to by its absolute position -/// in the metadata and length, and which can be decoded lazily. -/// The sequence is a single node for the purposes of `Lazy`. +/// +/// # Sequences (`Lazy<[T]>`) /// /// Unlike `Lazy>`, the length is encoded next to the /// position, not at the position, which means that the length @@ -100,54 +96,62 @@ impl rustc_serialize::UseSpecializedDecodable for Lazy {} /// the minimal distance the length of the sequence, i.e. /// it's assumed there's no 0-byte element in the sequence. #[must_use] -pub struct LazySeq { - pub len: usize, +// FIXME(#59875) the `Meta` parameter only exists to dodge +// invariance wrt `T` (coming from the `meta: T::Meta` field). +pub struct Lazy::Meta> + where T: ?Sized + LazyMeta, + Meta: 'static + Copy, +{ pub position: usize, + pub meta: Meta, _marker: PhantomData, } -impl LazySeq { - pub fn empty() -> LazySeq { - LazySeq::with_position_and_length(0, 0) - } - - pub fn with_position_and_length(position: usize, len: usize) -> LazySeq { - LazySeq { - len, +impl Lazy { + pub fn from_position_and_meta(position: usize, meta: T::Meta) -> Lazy { + Lazy { position, + meta, _marker: PhantomData, } } +} - /// Returns the minimum encoded size of `length` values of type `T`. - pub fn min_size(length: usize) -> usize { - length +impl Lazy { + pub fn from_position(position: usize) -> Lazy { + Lazy::from_position_and_meta(position, ()) } } -impl Copy for LazySeq {} -impl Clone for LazySeq { +impl Lazy<[T]> { + pub fn empty() -> Lazy<[T]> { + Lazy::from_position_and_meta(0, 0) + } +} + +impl Copy for Lazy {} +impl Clone for Lazy { fn clone(&self) -> Self { *self } } -impl rustc_serialize::UseSpecializedEncodable for LazySeq {} -impl rustc_serialize::UseSpecializedDecodable for LazySeq {} +impl rustc_serialize::UseSpecializedEncodable for Lazy {} +impl rustc_serialize::UseSpecializedDecodable for Lazy {} -/// Encoding / decoding state for `Lazy` and `LazySeq`. +/// Encoding / decoding state for `Lazy`. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum LazyState { /// Outside of a metadata node. NoNode, - /// Inside a metadata node, and before any `Lazy` or `LazySeq`. + /// Inside a metadata node, and before any `Lazy`. /// The position is that of the node itself. NodeStart(usize), - /// Inside a metadata node, with a previous `Lazy` or `LazySeq`. + /// Inside a metadata node, with a previous `Lazy`. /// The position is a conservative estimate of where that - /// previous `Lazy` / `LazySeq` would end (see their comments). + /// previous `Lazy` would end (see their comments). Previous(usize), } @@ -167,20 +171,25 @@ pub struct CrateRoot<'tcx> { pub proc_macro_decls_static: Option, pub proc_macro_stability: Option, - pub crate_deps: LazySeq, - pub dylib_dependency_formats: LazySeq>, - pub lib_features: LazySeq<(Symbol, Option)>, - pub lang_items: LazySeq<(DefIndex, usize)>, - pub lang_items_missing: LazySeq, - pub native_libraries: LazySeq, - pub foreign_modules: LazySeq, - pub source_map: LazySeq, + pub crate_deps: Lazy<[CrateDep]>, + pub dylib_dependency_formats: Lazy<[Option]>, + pub lib_features: Lazy<[(Symbol, Option)]>, + pub lang_items: Lazy<[(DefIndex, usize)]>, + pub lang_items_missing: Lazy<[lang_items::LangItem]>, + pub diagnostic_items: Lazy<[(Symbol, DefIndex)]>, + pub native_libraries: Lazy<[NativeLibrary]>, + pub foreign_modules: Lazy<[ForeignModule]>, + pub source_map: Lazy<[syntax_pos::SourceFile]>, pub def_path_table: Lazy, - pub impls: LazySeq, - pub exported_symbols: LazySeq<(ExportedSymbol<'tcx>, SymbolExportLevel)>, - pub interpret_alloc_index: LazySeq, + pub impls: Lazy<[TraitImpls]>, + pub exported_symbols: Lazy<[(ExportedSymbol<'tcx>, SymbolExportLevel)]>, + pub interpret_alloc_index: Lazy<[u32]>, + + pub entries_index: Lazy<[index::Index<'tcx>]>, - pub entries_index: LazySeq>, + /// The DefIndex's of any proc macros delcared by + /// this crate + pub proc_macro_data: Option>, pub compiler_builtins: bool, pub needs_allocator: bool, @@ -203,7 +212,7 @@ pub struct CrateDep { #[derive(RustcEncodable, RustcDecodable)] pub struct TraitImpls { pub trait_id: (u32, DefIndex), - pub impls: LazySeq, + pub impls: Lazy<[DefIndex]>, } #[derive(RustcEncodable, RustcDecodable)] @@ -211,19 +220,20 @@ pub struct Entry<'tcx> { pub kind: EntryKind<'tcx>, pub visibility: Lazy, pub span: Lazy, - pub attributes: LazySeq, - pub children: LazySeq, + pub attributes: Lazy<[ast::Attribute]>, + pub children: Lazy<[DefIndex]>, pub stability: Option>, pub deprecation: Option>, pub ty: Option>>, - pub inherent_impls: LazySeq, - pub variances: LazySeq, + pub inherent_impls: Lazy<[DefIndex]>, + pub variances: Lazy<[ty::Variance]>, pub generics: Option>, pub predicates: Option>>, pub predicates_defined_on: Option>>, pub mir: Option>>, + pub promoted_mir: Option>>>, } #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] @@ -264,7 +274,6 @@ pub enum EntryKind<'tcx> { #[derive(Clone, Copy, RustcEncodable, RustcDecodable)] pub struct ConstQualif { pub mir: u8, - pub ast_promotable: bool, } /// Contains a constant which has been rendered to a String. @@ -274,7 +283,7 @@ pub struct RenderedConst(pub String); #[derive(RustcEncodable, RustcDecodable)] pub struct ModData { - pub reexports: LazySeq>, + pub reexports: Lazy<[def::Export]>, } #[derive(RustcEncodable, RustcDecodable)] @@ -285,8 +294,9 @@ pub struct MacroDef { #[derive(RustcEncodable, RustcDecodable)] pub struct FnData<'tcx> { + pub asyncness: hir::IsAsync, pub constness: hir::Constness, - pub arg_names: LazySeq, + pub param_names: Lazy<[ast::Name]>, pub sig: Lazy>, } @@ -317,7 +327,7 @@ pub struct TraitAliasData<'tcx> { #[derive(RustcEncodable, RustcDecodable)] pub struct ImplData<'tcx> { - pub polarity: hir::ImplPolarity, + pub polarity: ty::ImplPolarity, pub defaultness: hir::Defaultness, pub parent_impl: Option, diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index 21008c737289f..f0cdcf2136bfa 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -15,14 +15,15 @@ either = "1.5.0" dot = { path = "../libgraphviz", package = "graphviz" } log = "0.4" log_settings = "0.1.1" -polonius-engine = "0.9.0" +polonius-engine = "0.10.0" rustc = { path = "../librustc" } rustc_target = { path = "../librustc_target" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_index = { path = "../librustc_index" } rustc_errors = { path = "../librustc_errors" } +rustc_lexer = { path = "../librustc_lexer" } rustc_serialize = { path = "../libserialize", package = "serialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -byteorder = { version = "1.1", features = ["i128"] } rustc_apfloat = { path = "../librustc_apfloat" } smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index c9e6e7f70a2b4..7dd1db3b7bdbc 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -8,8 +8,8 @@ use rustc::mir::visit::{PlaceContext, Visitor, NonUseContext, MutatingUseContext use rustc::mir::{self, Location, Body, Local}; use rustc::ty::{RegionVid, TyCtxt}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use rustc_data_structures::indexed_vec::IndexVec; -use rustc_data_structures::bit_set::BitSet; +use rustc_index::vec::IndexVec; +use rustc_index::bit_set::BitSet; use std::fmt; use std::ops::Index; @@ -317,7 +317,7 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> { // so extract `temp`. let temp = if let &mir::Place { base: mir::PlaceBase::Local(temp), - projection: None, + projection: box [], } = assigned_place { temp } else { diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index 4217a29bc663c..098258994f4e2 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -1,13 +1,14 @@ use rustc::hir; use rustc::hir::def_id::DefId; +use rustc::hir::{AsyncGeneratorKind, GeneratorKind}; use rustc::mir::{ self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, Local, - LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, Projection, PlaceRef, - ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm, + LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue, + Statement, StatementKind, TerminatorKind, VarBindingForm, }; use rustc::ty::{self, Ty}; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use rustc_errors::{Applicability, DiagnosticBuilder}; use syntax_pos::Span; use syntax::source_map::DesugaringKind; @@ -98,16 +99,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self.describe_place_with_options(moved_place, IncludingDowncast(true)) .unwrap_or_else(|| "_".to_owned()), ); - err.span_label(span, format!("use of possibly uninitialized {}", item_msg)); + err.span_label(span, format!("use of possibly-uninitialized {}", item_msg)); use_spans.var_span_label( &mut err, format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()), ); - // This error should not be downgraded to a warning, - // even in migrate mode. - self.disable_error_downgrading(); err.buffer(&mut self.errors_buffer); } else { if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) { @@ -180,7 +178,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } if Some(DesugaringKind::ForLoop) == move_span.desugaring_kind() { - if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { + let sess = self.infcx.tcx.sess; + if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) { err.span_suggestion( move_span, "consider borrowing to avoid moving into the for loop", @@ -210,7 +209,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let ty = Place::ty_from(used_place.base, used_place.projection, self.body, self.infcx.tcx) .ty; - let needs_note = match ty.sty { + let needs_note = match ty.kind { ty::Closure(id, _) => { let tables = self.infcx.tcx.typeck_tables_of(id); let hir_id = self.infcx.tcx.hir().as_local_hir_id(id).unwrap(); @@ -231,7 +230,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some(ref name) => format!("`{}`", name), None => "value".to_owned(), }; - if let ty::Param(param_ty) = ty.sty { + if let ty::Param(param_ty) = ty.kind { let tcx = self.infcx.tcx; let generics = tcx.generics_of(self.mir_def_id); let def_id = generics.type_param(¶m_ty, tcx).def_id; @@ -244,7 +243,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } let span = if let Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } = place { let decl = &self.body.local_decls[*local]; Some(decl.source_info.span) @@ -614,17 +613,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { projection, } = first_borrowed_place; - let mut current = projection; + let mut cursor = &**projection; + while let [proj_base @ .., elem] = cursor { + cursor = proj_base; - while let Some(box Projection { base: base_proj, elem }) = current { match elem { - ProjectionElem::Field(field, _) if union_ty(base, base_proj).is_some() => { + ProjectionElem::Field(field, _) if union_ty(base, proj_base).is_some() => { return Some((PlaceRef { base: base, - projection: base_proj, + projection: proj_base, }, field)); }, - _ => current = base_proj, + _ => {}, } } None @@ -637,9 +637,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { projection, } = second_borrowed_place; - let mut current = projection; + let mut cursor = &**projection; + while let [proj_base @ .., elem] = cursor { + cursor = proj_base; - while let Some(box Projection { base: proj_base, elem }) = current { if let ProjectionElem::Field(field, _) = elem { if let Some(union_ty) = union_ty(base, proj_base) { if field != target_field @@ -660,8 +661,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } } - - current = proj_base; } None }) @@ -707,7 +706,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let borrow_spans = self.retrieve_borrow_spans(borrow); let borrow_span = borrow_spans.var_or_use(); - assert!(root_place.projection.is_none()); + assert!(root_place.projection.is_empty()); let proper_span = match root_place.base { PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span, _ => drop_span, @@ -716,7 +715,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if self.access_place_error_reported .contains(&(Place { base: root_place.base.clone(), - projection: root_place.projection.clone(), + projection: root_place.projection.to_vec().into_boxed_slice(), }, borrow_span)) { debug!( @@ -729,7 +728,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.access_place_error_reported .insert((Place { base: root_place.base.clone(), - projection: root_place.projection.clone(), + projection: root_place.projection.to_vec().into_boxed_slice(), }, borrow_span)); if let StorageDeadOrDrop::Destructor(dropped_ty) = @@ -752,6 +751,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0)); let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place); + debug!( + "report_borrowed_value_does_not_live_long_enough(place_desc: {:?}, explanation: {:?})", + place_desc, + explanation + ); let err = match (place_desc, explanation) { (Some(_), _) if self.is_place_thread_local(root_place) => { self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span) @@ -785,7 +789,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .. }, ) if borrow_spans.for_closure() => self.report_escaping_closure_capture( - borrow_spans.args_or_use(), + borrow_spans, + borrow_span, + region_name, + category, + span, + &format!("`{}`", name), + ), + ( + Some(ref name), + BorrowExplanation::MustBeValidFor { + category: category @ ConstraintCategory::OpaqueType, + from_closure: false, + ref region_name, + span, + .. + }, + + ) if borrow_spans.for_generator() => self.report_escaping_closure_capture( + borrow_spans, borrow_span, region_name, category, @@ -1107,7 +1129,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let local_kind = match borrow.borrowed_place { Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } => { match self.body.local_kind(local) { LocalKind::ReturnPointer @@ -1136,7 +1158,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .unwrap(); let local = if let PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } = root_place { local } else { @@ -1174,7 +1196,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn report_escaping_closure_capture( &mut self, - args_span: Span, + use_span: UseSpans, var_span: Span, fr_name: &RegionName, category: ConstraintCategory, @@ -1182,7 +1204,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { captured_var: &str, ) -> DiagnosticBuilder<'cx> { let tcx = self.infcx.tcx; - + let args_span = use_span.args_or_use(); let mut err = self.cannot_capture_in_long_lived_closure( args_span, captured_var, @@ -1190,15 +1212,37 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); let suggestion = match tcx.sess.source_map().span_to_snippet(args_span) { - Ok(string) => format!("move {}", string), + Ok(mut string) => { + if string.starts_with("async ") { + string.insert_str(6, "move "); + } else if string.starts_with("async|") { + string.insert_str(5, " move"); + } else { + string.insert_str(0, "move "); + }; + string + }, Err(_) => "move || ".to_string() }; - + let kind = match use_span.generator_kind() { + Some(generator_kind) => match generator_kind { + GeneratorKind::Async(async_kind) => match async_kind { + AsyncGeneratorKind::Block => "async block", + AsyncGeneratorKind::Closure => "async closure", + _ => bug!("async block/closure expected, but async funtion found."), + }, + GeneratorKind::Gen => "generator", + } + None => "closure", + }; err.span_suggestion( args_span, - &format!("to force the closure to take ownership of {} (and any \ - other referenced variables), use the `move` keyword", - captured_var), + &format!( + "to force the {} to take ownership of {} (and any \ + other referenced variables), use the `move` keyword", + kind, + captured_var + ), suggestion, Applicability::MachineApplicable, ); @@ -1207,6 +1251,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ConstraintCategory::Return => { err.span_note(constraint_span, "closure is returned here"); } + ConstraintCategory::OpaqueType => { + err.span_note(constraint_span, "generator is returned here"); + } ConstraintCategory::CallArgument => { fr_name.highlight_region_name(&mut err); err.span_note( @@ -1233,7 +1280,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let escapes_from = if tcx.is_closure(self.mir_def_id) { let tables = tcx.typeck_tables_of(self.mir_def_id); let mir_hir_id = tcx.hir().def_index_to_hir_id(self.mir_def_id.index); - match tables.node_type(mir_hir_id).sty { + match tables.node_type(mir_hir_id).kind { ty::Closure(..) => "closure", ty::Generator(..) => "generator", _ => bug!("Closure body doesn't have a closure or generator type"), @@ -1437,7 +1484,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) { let (from_arg, local_decl) = if let Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } = *err_place { if let LocalKind::Arg = self.body.local_kind(local) { (true, Some(&self.body.local_decls[local])) @@ -1510,20 +1557,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOrDrop<'tcx> { let tcx = self.infcx.tcx; match place.projection { - None => { + [] => { StorageDeadOrDrop::LocalStorageDead } - Some(box Projection { ref base, ref elem }) => { + [proj_base @ .., elem] => { + // FIXME(spastorino) make this iterate let base_access = self.classify_drop_access_kind(PlaceRef { base: place.base, - projection: base, + projection: proj_base, }); match elem { ProjectionElem::Deref => match base_access { StorageDeadOrDrop::LocalStorageDead | StorageDeadOrDrop::BoxedStorageDead => { assert!( - Place::ty_from(&place.base, base, self.body, tcx).ty.is_box(), + Place::ty_from(&place.base, proj_base, self.body, tcx).ty.is_box(), "Drop of value behind a reference or raw pointer" ); StorageDeadOrDrop::BoxedStorageDead @@ -1531,8 +1579,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { StorageDeadOrDrop::Destructor(_) => base_access, }, ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { - let base_ty = Place::ty_from(&place.base, base, self.body, tcx).ty; - match base_ty.sty { + let base_ty = Place::ty_from(&place.base, proj_base, self.body, tcx).ty; + match base_ty.kind { ty::Adt(def, _) if def.has_dtor(tcx) => { // Report the outermost adt with a destructor match base_access { @@ -1568,7 +1616,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { None } else { let ty = self.infcx.tcx.type_of(self.mir_def_id); - match ty.sty { + match ty.kind { ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig( self.mir_def_id, self.infcx.tcx.fn_sig(self.mir_def_id), @@ -1589,7 +1637,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "annotate_argument_and_return_for_borrow: location={:?}", location ); - if let Some(&Statement { kind: StatementKind::Assign(ref reservation, _), ..}) + if let Some(&Statement { kind: StatementKind::Assign(box(ref reservation, _)), ..}) = &self.body[location.block].statements.get(location.statement_index) { debug!( @@ -1600,7 +1648,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut target = *match reservation { Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } if self.body.local_kind(*local) == LocalKind::Temp => local, _ => return None, }; @@ -1614,11 +1662,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { target, stmt ); if let StatementKind::Assign( - Place { - base: PlaceBase::Local(assigned_to), - projection: None, - }, - box rvalue + box( + Place { + base: PlaceBase::Local(assigned_to), + projection: box [], + }, + rvalue + ) ) = &stmt.kind { debug!( "annotate_argument_and_return_for_borrow: assigned_to={:?} \ @@ -1744,7 +1794,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let TerminatorKind::Call { destination: Some((Place { base: PlaceBase::Local(assigned_to), - projection: None, + projection: box [], }, _)), args, .. @@ -1821,18 +1871,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // 3. The return type is not a reference. In this case, we don't highlight // anything. let return_ty = sig.output(); - match return_ty.skip_binder().sty { + match return_ty.skip_binder().kind { ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => { // This is case 1 from above, return type is a named reference so we need to // search for relevant arguments. let mut arguments = Vec::new(); for (index, argument) in sig.inputs().skip_binder().iter().enumerate() { - if let ty::Ref(argument_region, _, _) = argument.sty { + if let ty::Ref(argument_region, _, _) = argument.kind { if argument_region == return_region { // Need to use the `rustc::ty` types to compare against the // `return_region`. Then use the `rustc::hir` type to get only // the lifetime span. - if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].node { + if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].kind { // With access to the lifetime, we can get // the span of it. arguments.push((*argument, lifetime.span)); @@ -1853,7 +1903,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let return_ty = *sig.output().skip_binder(); let mut return_span = fn_decl.output.span(); if let hir::FunctionRetTy::Return(ty) = &fn_decl.output { - if let hir::TyKind::Rptr(lifetime, _) = ty.node { + if let hir::TyKind::Rptr(lifetime, _) = ty.kind { return_span = lifetime.span; } } @@ -1873,9 +1923,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Closure arguments are wrapped in a tuple, so we need to get the first // from that. - if let ty::Tuple(elems) = argument_ty.sty { + if let ty::Tuple(elems) = argument_ty.kind { let argument_ty = elems.first()?.expect_ty(); - if let ty::Ref(_, _, _) = argument_ty.sty { + if let ty::Ref(_, _, _) = argument_ty.kind { return Some(AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span, @@ -1895,7 +1945,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let return_ty = *sig.output().skip_binder(); // We expect the first argument to be a reference. - match argument_ty.sty { + match argument_ty.kind { ty::Ref(_, _, _) => {} _ => return None, } diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 99899aa390c4a..5e0727d51579f 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -1,6 +1,7 @@ use rustc::hir; use rustc::hir::def::Namespace; use rustc::hir::def_id::DefId; +use rustc::hir::GeneratorKind; use rustc::mir::{ AggregateKind, Constant, Field, Local, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, @@ -14,7 +15,7 @@ use syntax_pos::Span; use syntax::symbol::sym; use super::borrow_set::BorrowData; -use super::{MirBorrowckCtxt}; +use super::MirBorrowckCtxt; use crate::dataflow::move_paths::{InitLocation, LookupResult}; pub(super) struct IncludingDowncast(pub(super) bool); @@ -41,7 +42,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut target = place.local_or_deref_local(); for stmt in &self.body[location.block].statements[location.statement_index..] { debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target); - if let StatementKind::Assign(into, box Rvalue::Use(from)) = &stmt.kind { + if let StatementKind::Assign(box(into, Rvalue::Use(from))) = &stmt.kind { debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from); match from { Operand::Copy(ref place) | @@ -58,7 +59,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let TerminatorKind::Call { func: Operand::Constant(box Constant { literal: ty::Const { - ty: &ty::TyS { sty: ty::FnDef(id, _), .. }, + ty: &ty::TyS { kind: ty::FnDef(id, _), .. }, .. }, .. @@ -76,7 +77,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }; debug!("add_moved_or_invoked_closure_note: closure={:?}", closure); - if let ty::Closure(did, _) = self.body.local_decls[closure].ty.sty { + if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind { let hir_id = self.infcx.tcx.hir().as_local_hir_id(did).unwrap(); if let Some((span, name)) = self.infcx.tcx.typeck_tables_of(did) @@ -99,7 +100,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Check if we are just moving a closure after it has been invoked. if let Some(target) = target { - if let ty::Closure(did, _) = self.body.local_decls[target].ty.sty { + if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind { let hir_id = self.infcx.tcx.hir().as_local_hir_id(did).unwrap(); if let Some((span, name)) = self.infcx.tcx.typeck_tables_of(did) @@ -152,35 +153,36 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { match place { PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } => { self.append_local_to_string(*local, buf)?; } PlaceRef { base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(_), + kind: StaticKind::Promoted(..), .. }), - projection: None, + projection: [], } => { buf.push_str("promoted"); } PlaceRef { base: PlaceBase::Static(box Static { - kind: StaticKind::Static(def_id), + kind: StaticKind::Static, + def_id, .. }), - projection: None, + projection: [], } => { buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string()); } PlaceRef { base, - projection: Some(ref proj), + projection: [proj_base @ .., elem], } => { - match proj.elem { + match elem { ProjectionElem::Deref => { let upvar_field_projection = self.is_upvar_field_projection(place); @@ -198,20 +200,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.append_place_to_string( PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, buf, autoderef, &including_downcast, )?; } else { - match (&proj.base, base) { - (None, PlaceBase::Local(local)) => { + match (proj_base, base) { + ([], PlaceBase::Local(local)) => { if self.body.local_decls[*local].is_ref_for_guard() { self.append_place_to_string( PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, buf, autoderef, @@ -223,7 +225,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.append_place_to_string( PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, buf, autoderef, @@ -237,7 +239,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.append_place_to_string( PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, buf, autoderef, @@ -252,7 +254,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.append_place_to_string( PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, buf, autoderef, @@ -274,12 +276,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else { let field_name = self.describe_field(PlaceRef { base, - projection: &proj.base, - }, field); + projection: proj_base, + }, *field); self.append_place_to_string( PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, buf, autoderef, @@ -294,14 +296,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.append_place_to_string( PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, buf, autoderef, &including_downcast, )?; buf.push_str("["); - if self.append_local_to_string(index, buf).is_err() { + if self.append_local_to_string(*index, buf).is_err() { buf.push_str("_"); } buf.push_str("]"); @@ -314,7 +316,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.append_place_to_string( PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, buf, autoderef, @@ -335,7 +337,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let local = &self.body.local_decls[local_index]; match local.name { Some(name) if !local.from_compiler_desugaring() => { - buf.push_str(name.as_str().get()); + buf.push_str(&name.as_str()); Ok(()) } _ => Err(()), @@ -348,28 +350,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { match place { PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } => { let local = &self.body.local_decls[*local]; self.describe_field_from_ty(&local.ty, field, None) } PlaceRef { base: PlaceBase::Static(static_), - projection: None, + projection: [], } => self.describe_field_from_ty(&static_.ty, field, None), PlaceRef { base, - projection: Some(proj), - } => match proj.elem { - ProjectionElem::Deref => self.describe_field(PlaceRef { - base, - projection: &proj.base, - }, field), + projection: [proj_base @ .., elem], + } => match elem { + ProjectionElem::Deref => { + self.describe_field(PlaceRef { + base, + projection: proj_base, + }, field) + } ProjectionElem::Downcast(_, variant_index) => { let base_ty = Place::ty_from(place.base, place.projection, self.body, self.infcx.tcx).ty; - self.describe_field_from_ty(&base_ty, field, Some(variant_index)) + self.describe_field_from_ty(&base_ty, field, Some(*variant_index)) } ProjectionElem::Field(_, field_type) => { self.describe_field_from_ty(&field_type, field, None) @@ -379,7 +383,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | ProjectionElem::Subslice { .. } => { self.describe_field(PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, field) } }, @@ -397,7 +401,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // If the type is a box, the field is described from the boxed type self.describe_field_from_ty(&ty.boxed_ty(), field, variant_index) } else { - match ty.sty { + match ty.kind { ty::Adt(def, _) => { let variant = if let Some(idx) = variant_index { assert!(def.is_enum()); @@ -440,10 +444,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { pub fn is_place_thread_local(&self, place_ref: PlaceRef<'cx, 'tcx>) -> bool { if let PlaceRef { base: PlaceBase::Static(box Static { - kind: StaticKind::Static(def_id), + kind: StaticKind::Static, + def_id, .. }), - projection: None, + projection: [], } = place_ref { let attrs = self.infcx.tcx.get_attrs(*def_id); let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local)); @@ -554,7 +559,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // We need to add synthesized lifetimes where appropriate. We do // this by hooking into the pretty printer and telling it to label the // lifetimes without names with the value `'0`. - match ty.sty { + match ty.kind { ty::Ref(ty::RegionKind::ReLateBound(_, br), _, _) | ty::Ref( ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }), @@ -574,7 +579,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut s = String::new(); let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS); - let region = match ty.sty { + let region = match ty.kind { ty::Ref(region, _, _) => { match region { ty::RegionKind::ReLateBound(_, br) @@ -600,7 +605,7 @@ pub(super) enum UseSpans { // The access is caused by capturing a variable for a closure. ClosureUse { // This is true if the captured variable was from a generator. - is_generator: bool, + generator_kind: Option, // The span of the args of the closure, including the `move` keyword if // it's present. args_span: Span, @@ -627,6 +632,13 @@ impl UseSpans { } } + pub(super) fn generator_kind(self) -> Option { + match self { + UseSpans::ClosureUse { generator_kind, .. } => generator_kind, + _ => None, + } + } + // Add a span label to the arguments of the closure, if it exists. pub(super) fn args_span_label( self, @@ -652,7 +664,7 @@ impl UseSpans { /// Returns `false` if this place is not used in a closure. pub(super) fn for_closure(&self) -> bool { match *self { - UseSpans::ClosureUse { is_generator, .. } => !is_generator, + UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_none(), _ => false, } } @@ -660,7 +672,7 @@ impl UseSpans { /// Returns `false` if this place is not used in a generator. pub(super) fn for_generator(&self) -> bool { match *self { - UseSpans::ClosureUse { is_generator, .. } => is_generator, + UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_some(), _ => false, } } @@ -668,7 +680,7 @@ impl UseSpans { /// Describe the span associated with a use of a place. pub(super) fn describe(&self) -> String { match *self { - UseSpans::ClosureUse { is_generator, .. } => if is_generator { + UseSpans::ClosureUse { generator_kind, .. } => if generator_kind.is_some() { " in generator".to_string() } else { " in closure".to_string() @@ -750,7 +762,7 @@ impl BorrowedContentSource<'tcx> { } fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option { - match func.sty { + match func.kind { ty::FnDef(def_id, substs) => { let trait_id = tcx.trait_of_item(def_id)?; @@ -788,22 +800,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt); if let StatementKind::Assign( - _, - box Rvalue::Aggregate(ref kind, ref places) + box(_, Rvalue::Aggregate(ref kind, ref places)) ) = stmt.kind { - let (def_id, is_generator) = match kind { - box AggregateKind::Closure(def_id, _) => (def_id, false), - box AggregateKind::Generator(def_id, _, _) => (def_id, true), + let def_id = match kind { + box AggregateKind::Closure(def_id, _) + | box AggregateKind::Generator(def_id, _, _) => def_id, _ => return OtherUse(stmt.source_info.span), }; debug!( - "move_spans: def_id={:?} is_generator={:?} places={:?}", - def_id, is_generator, places + "move_spans: def_id={:?} places={:?}", + def_id, places ); - if let Some((args_span, var_span)) = self.closure_span(*def_id, moved_place, places) { + if let Some((args_span, generator_kind, var_span)) + = self.closure_span(*def_id, moved_place, places) { return ClosureUse { - is_generator, + generator_kind, args_span, var_span, }; @@ -826,10 +838,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .get(location.statement_index) { Some(&Statement { - kind: StatementKind::Assign(Place { + kind: StatementKind::Assign(box(Place { base: PlaceBase::Local(local), - projection: None, - }, _), + projection: box [], + }, _)), .. }) => local, _ => return OtherUse(use_span), @@ -842,7 +854,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { for stmt in &self.body[location.block].statements[location.statement_index + 1..] { if let StatementKind::Assign( - _, box Rvalue::Aggregate(ref kind, ref places) + box(_, Rvalue::Aggregate(ref kind, ref places)) ) = stmt.kind { let (def_id, is_generator) = match kind { box AggregateKind::Closure(def_id, _) => (def_id, false), @@ -854,11 +866,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "borrow_spans: def_id={:?} is_generator={:?} places={:?}", def_id, is_generator, places ); - if let Some((args_span, var_span)) = self.closure_span( + if let Some((args_span, generator_kind, var_span)) = self.closure_span( *def_id, Place::from(target).as_ref(), places ) { return ClosureUse { - is_generator, + generator_kind, args_span, var_span, }; @@ -881,23 +893,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { def_id: DefId, target_place: PlaceRef<'cx, 'tcx>, places: &Vec>, - ) -> Option<(Span, Span)> { + ) -> Option<(Span, Option, Span)> { debug!( "closure_span: def_id={:?} target_place={:?} places={:?}", def_id, target_place, places ); let hir_id = self.infcx.tcx.hir().as_local_hir_id(def_id)?; - let expr = &self.infcx.tcx.hir().expect_expr(hir_id).node; + let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); if let hir::ExprKind::Closure( - .., args_span, _ + .., body_id, args_span, _ ) = expr { for (upvar, place) in self.infcx.tcx.upvars(def_id)?.values().zip(places) { match place { Operand::Copy(place) | Operand::Move(place) if target_place == place.as_ref() => { debug!("closure_span: found captured local {:?}", place); - return Some((*args_span, upvar.span)); + let body = self.infcx.tcx.hir().body(*body_id); + let generator_kind = body.generator_kind(); + return Some((*args_span, generator_kind, upvar.span)); }, _ => {} } diff --git a/src/librustc_mir/borrow_check/flows.rs b/src/librustc_mir/borrow_check/flows.rs index bb217a1f965e2..ce5d2a14bd122 100644 --- a/src/librustc_mir/borrow_check/flows.rs +++ b/src/librustc_mir/borrow_check/flows.rs @@ -5,14 +5,14 @@ use rustc::mir::{BasicBlock, Local, Location}; use rustc::ty::RegionVid; -use rustc_data_structures::bit_set::BitIter; +use rustc_index::bit_set::BitIter; use crate::borrow_check::location::LocationIndex; use polonius_engine::Output; use crate::dataflow::indexes::BorrowIndex; -use crate::dataflow::move_paths::HasMoveData; +use crate::dataflow::move_paths::{HasMoveData, MovePathIndex}; use crate::dataflow::Borrows; use crate::dataflow::EverInitializedPlaces; use crate::dataflow::MaybeUninitializedPlaces; @@ -21,9 +21,8 @@ use either::Either; use std::fmt; use std::rc::Rc; -crate type PoloniusOutput = Output; +crate type PoloniusOutput = Output; -// (forced to be `pub` due to its use as an associated type below.) crate struct Flows<'b, 'tcx> { borrows: FlowAtLocation<'tcx, Borrows<'b, 'tcx>>, pub uninits: FlowAtLocation<'tcx, MaybeUninitializedPlaces<'b, 'tcx>>, diff --git a/src/librustc_mir/borrow_check/location.rs b/src/librustc_mir/borrow_check/location.rs index cc44dc3f5d46b..9e94317b87e54 100644 --- a/src/librustc_mir/borrow_check/location.rs +++ b/src/librustc_mir/borrow_check/location.rs @@ -1,5 +1,5 @@ use rustc::mir::{BasicBlock, Location, Body}; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_index::vec::{Idx, IndexVec}; /// Maps between a MIR Location, which identifies a particular /// statement within a basic block, to a "rich location", which @@ -17,7 +17,7 @@ crate struct LocationTable { statements_before_block: IndexVec, } -newtype_index! { +rustc_index::newtype_index! { pub struct LocationIndex { DEBUG_FORMAT = "LocationIndex({})" } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index de27aec2b2990..75d4b56fdb7c2 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -7,21 +7,21 @@ use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; use rustc::lint::builtin::UNUSED_MUT; use rustc::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT}; -use rustc::middle::borrowck::SignalledError; use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc::mir::{ - ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceRef, - Static, StaticKind + ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceElem, + PlaceRef, Static, StaticKind }; -use rustc::mir::{Field, Projection, ProjectionElem, Rvalue, Statement, StatementKind}; +use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; use rustc::mir::{Terminator, TerminatorKind}; use rustc::ty::query::Providers; use rustc::ty::{self, TyCtxt}; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, Level}; -use rustc_data_structures::bit_set::BitSet; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder}; +use rustc_index::bit_set::BitSet; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::dominators::Dominators; +use rustc_index::vec::IndexVec; use smallvec::SmallVec; use std::collections::BTreeMap; @@ -86,12 +86,13 @@ pub fn provide(providers: &mut Providers<'_>) { } fn mir_borrowck(tcx: TyCtxt<'_>, def_id: DefId) -> BorrowCheckResult<'_> { - let input_body = tcx.mir_validated(def_id); + let (input_body, promoted) = tcx.mir_validated(def_id); debug!("run query mir_borrowck: {}", tcx.def_path_str(def_id)); let opt_closure_req = tcx.infer_ctxt().enter(|infcx| { let input_body: &Body<'_> = &input_body.borrow(); - do_mir_borrowck(&infcx, input_body, def_id) + let promoted: &IndexVec<_, _> = &promoted.borrow(); + do_mir_borrowck(&infcx, input_body, promoted, def_id) }); debug!("mir_borrowck done"); @@ -101,6 +102,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def_id: DefId) -> BorrowCheckResult<'_> { fn do_mir_borrowck<'a, 'tcx>( infcx: &InferCtxt<'a, 'tcx>, input_body: &Body<'tcx>, + input_promoted: &IndexVec>, def_id: DefId, ) -> BorrowCheckResult<'tcx> { debug!("do_mir_borrowck(def_id = {:?})", def_id); @@ -147,7 +149,9 @@ fn do_mir_borrowck<'a, 'tcx>( // be modified (in place) to contain non-lexical lifetimes. It // will have a lifetime tied to the inference context. let mut body: Body<'tcx> = input_body.clone(); - let free_regions = nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body); + let mut promoted: IndexVec> = input_promoted.clone(); + let free_regions = + nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body, &mut promoted); let body = &body; // no further changes let location_table = &LocationTable::new(body); @@ -159,8 +163,8 @@ fn do_mir_borrowck<'a, 'tcx>( }; let mdpe = MoveDataParamEnv { - move_data: move_data, - param_env: param_env, + move_data, + param_env, }; let dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); @@ -184,6 +188,7 @@ fn do_mir_borrowck<'a, 'tcx>( def_id, free_regions, body, + &promoted, &upvars, location_table, param_env, @@ -230,7 +235,7 @@ fn do_mir_borrowck<'a, 'tcx>( let movable_generator = match tcx.hir().get(id) { Node::Expr(&hir::Expr { - node: hir::ExprKind::Closure(.., Some(hir::GeneratorMovability::Static)), + kind: hir::ExprKind::Closure(.., Some(hir::GeneratorMovability::Static)), .. }) => false, _ => true, @@ -253,7 +258,6 @@ fn do_mir_borrowck<'a, 'tcx>( move_error_reported: BTreeMap::new(), uninitialized_error_reported: Default::default(), errors_buffer, - disable_error_downgrading: false, nonlexical_regioncx: regioncx, used_mut: Default::default(), used_mut_upvars: SmallVec::new(), @@ -365,35 +369,8 @@ fn do_mir_borrowck<'a, 'tcx>( if !mbcx.errors_buffer.is_empty() { mbcx.errors_buffer.sort_by_key(|diag| diag.span.primary_span()); - if !mbcx.disable_error_downgrading && tcx.migrate_borrowck() { - // When borrowck=migrate, check if AST-borrowck would - // error on the given code. - - // rust-lang/rust#55492, rust-lang/rust#58776 check the base def id - // for errors. AST borrowck is responsible for aggregating - // `signalled_any_error` from all of the nested closures here. - let base_def_id = tcx.closure_base_def_id(def_id); - - match tcx.borrowck(base_def_id).signalled_any_error { - SignalledError::NoErrorsSeen => { - // if AST-borrowck signalled no errors, then - // downgrade all the buffered MIR-borrowck errors - // to warnings. - - for err in mbcx.errors_buffer.iter_mut() { - downgrade_if_error(err); - } - } - SignalledError::SawSomeError => { - // if AST-borrowck signalled a (cancelled) error, - // then we will just emit the buffered - // MIR-borrowck errors as normal. - } - } - } - for diag in mbcx.errors_buffer.drain(..) { - DiagnosticBuilder::new_diagnostic(mbcx.infcx.tcx.sess.diagnostic(), diag).emit(); + mbcx.infcx.tcx.sess.diagnostic().emit_diagnostic(&diag); } } @@ -407,21 +384,6 @@ fn do_mir_borrowck<'a, 'tcx>( result } -fn downgrade_if_error(diag: &mut Diagnostic) { - if diag.is_error() { - diag.level = Level::Warning; - diag.warn( - "this error has been downgraded to a warning for backwards \ - compatibility with previous releases", - ).warn( - "this represents potential undefined behavior in your code and \ - this warning will become a hard error in the future", - ).note( - "for more information, try `rustc --explain E0729`" - ); - } -} - crate struct MirBorrowckCtxt<'cx, 'tcx> { crate infcx: &'cx InferCtxt<'cx, 'tcx>, body: &'cx Body<'tcx>, @@ -482,9 +444,6 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> { uninitialized_error_reported: FxHashSet>, /// Errors to be reported buffer errors_buffer: Vec, - /// If there are no errors reported by the HIR borrow checker, we downgrade - /// all NLL errors to warnings. Setting this flag disables downgrading. - disable_error_downgrading: bool, /// This field keeps track of all the local variables that are declared mut and are mutated. /// Used for the warning issued by an unused mutable local variable. used_mut: FxHashSet, @@ -537,7 +496,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx self.check_activations(location, span, flow_state); match stmt.kind { - StatementKind::Assign(ref lhs, ref rhs) => { + StatementKind::Assign(box(ref lhs, ref rhs)) => { self.consume_rvalue( location, (rhs, span), @@ -552,7 +511,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx flow_state, ); } - StatementKind::FakeRead(_, ref place) => { + StatementKind::FakeRead(_, box ref place) => { // Read for match doesn't access any memory and is used to // assert that a place is safe and live. So we don't have to // do any checks here. @@ -662,7 +621,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx target: _, unwind: _, } => { - let gcx = self.infcx.tcx.global_tcx(); + let tcx = self.infcx.tcx; // Compute the type with accurate region information. let drop_place_ty = drop_place.ty(self.body, self.infcx.tcx); @@ -670,10 +629,10 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx // Erase the regions. let drop_place_ty = self.infcx.tcx.erase_regions(&drop_place_ty).ty; - // "Lift" into the gcx -- once regions are erased, this type should be in the + // "Lift" into the tcx -- once regions are erased, this type should be in the // global arenas; this "lift" operation basically just asserts that is true, but // that is useful later. - gcx.lift_to_global(&drop_place_ty).unwrap(); + tcx.lift(&drop_place_ty).unwrap(); debug!("visit_terminator_drop \ loc: {:?} term: {:?} drop_place: {:?} drop_place_ty: {:?} span: {:?}", @@ -896,7 +855,7 @@ enum InitializationRequiringAction { struct RootPlace<'d, 'tcx> { place_base: &'d PlaceBase<'tcx>, - place_projection: &'d Option>>, + place_projection: &'d [PlaceElem<'tcx>], is_local_mutation_allowed: LocalMutationIsAllowed, } @@ -925,12 +884,6 @@ impl InitializationRequiringAction { } impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - /// If there are no errors reported by the HIR borrow checker, we downgrade - /// all NLL errors to warnings. Calling this disables downgrading. - crate fn disable_error_downgrading(&mut self) { - self.disable_error_downgrading = true; - } - /// Checks an access to the given place to see if it is allowed. Examines the set of borrows /// that are in scope, as well as which paths have been initialized, to ensure that (a) the /// place is initialized and (b) it is not borrowed in some way that would prevent this @@ -1182,7 +1135,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // before (at this point in the flow). if let Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } = place_span.0 { if let Mutability::Not = self.body.local_decls[*local].mutability { // check for reassignments to immutable local variables @@ -1322,7 +1275,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) { let propagate_closure_used_mut_place = |this: &mut Self, place: &Place<'tcx>| { - if place.projection.is_some() { + if !place.projection.is_empty() { if let Some(field) = this.is_upvar_field_projection(place.as_ref()) { this.used_mut_upvars.push(field); } @@ -1337,11 +1290,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { match *operand { Operand::Move(Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }) | Operand::Copy(Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }) if self.body.local_decls[local].is_user_variable.is_none() => { if self.body.local_decls[local].ty.is_mutable_ptr() { // The variable will be marked as mutable by the borrow. @@ -1378,7 +1331,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let stmt = &bbd.statements[loc.statement_index]; debug!("temporary assigned in: stmt={:?}", stmt); - if let StatementKind::Assign(_, box Rvalue::Ref(_, _, ref source)) = stmt.kind { + if let StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref source))) = stmt.kind { propagate_closure_used_mut_place(self, source); } else { bug!("closures should only capture user variables \ @@ -1459,16 +1412,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // // FIXME: allow thread-locals to borrow other thread locals? - assert!(root_place.projection.is_none()); + assert!(root_place.projection.is_empty()); let (might_be_alive, will_be_dropped) = match root_place.base { PlaceBase::Static(box Static { - kind: StaticKind::Promoted(_), + kind: StaticKind::Promoted(..), .. }) => { (true, false) } PlaceBase::Static(box Static { - kind: StaticKind::Static(_), + kind: StaticKind::Static, .. }) => { // Thread-locals might be dropped after the function exits, but @@ -1747,13 +1700,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { flow_state: &Flows<'cx, 'tcx>, ) { debug!("check_if_assigned_path_is_moved place: {:?}", place); - // recur down place; dispatch to external checks when necessary - let mut place_projection = &place.projection; // None case => assigning to `x` does not require `x` be initialized. - while let Some(proj) = place_projection { - let Projection { ref base, ref elem } = **proj; - match *elem { + let mut cursor = &*place.projection; + while let [proj_base @ .., elem] = cursor { + cursor = proj_base; + + match elem { ProjectionElem::Index(_/*operand*/) | ProjectionElem::ConstantIndex { .. } | // assigning to P[i] requires P to be valid. @@ -1769,7 +1722,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location, InitializationRequiringAction::Use, (PlaceRef { base: &place.base, - projection: base, + projection: proj_base, }, span), flow_state); // (base initialized; no need to // recur further) @@ -1786,14 +1739,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // assigning to `P.f` requires `P` itself // be already initialized let tcx = self.infcx.tcx; - let base_ty = Place::ty_from(&place.base, base, self.body, tcx).ty; - match base_ty.sty { + let base_ty = Place::ty_from(&place.base, proj_base, self.body, tcx).ty; + match base_ty.kind { ty::Adt(def, _) if def.has_dtor(tcx) => { self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Assignment, (PlaceRef { base: &place.base, - projection: base, + projection: proj_base, }, span), flow_state); // (base initialized; no need to @@ -1806,7 +1759,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ty::Adt(..) | ty::Tuple(..) => { check_parent_of_field(self, location, PlaceRef { base: &place.base, - projection: base, + projection: proj_base, }, span, flow_state); if let PlaceBase::Local(local) = place.base { @@ -1826,8 +1779,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } } - - place_projection = base; } fn check_parent_of_field<'cx, 'tcx>( @@ -1895,7 +1846,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // of the union - we should error in that case. let tcx = this.infcx.tcx; if let ty::Adt(def, _) = - Place::ty_from(base.base, base.projection, this.body, tcx).ty.sty + Place::ty_from(base.base, base.projection, this.body, tcx).ty.kind { if def.is_union() { if this.move_data.path_map[mpi].iter().any(|moi| { @@ -1981,48 +1932,28 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - Reservation(wk @ WriteKind::Move) - | Write(wk @ WriteKind::Move) - | Reservation(wk @ WriteKind::StorageDeadOrDrop) - | Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) - | Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Shallow)) - | Write(wk @ WriteKind::StorageDeadOrDrop) - | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) - | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shallow)) => { - if let (Err(place_err), true) = ( + Reservation(WriteKind::Move) + | Write(WriteKind::Move) + | Reservation(WriteKind::StorageDeadOrDrop) + | Reservation(WriteKind::MutableBorrow(BorrowKind::Shared)) + | Reservation(WriteKind::MutableBorrow(BorrowKind::Shallow)) + | Write(WriteKind::StorageDeadOrDrop) + | Write(WriteKind::MutableBorrow(BorrowKind::Shared)) + | Write(WriteKind::MutableBorrow(BorrowKind::Shallow)) => { + if let (Err(_), true) = ( self.is_mutable(place.as_ref(), is_local_mutation_allowed), self.errors_buffer.is_empty() ) { - if self.infcx.tcx.migrate_borrowck() { - // rust-lang/rust#46908: In pure NLL mode this - // code path should be unreachable (and thus - // we signal an ICE in the else branch - // here). But we can legitimately get here - // under borrowck=migrate mode, so instead of - // ICE'ing we instead report a legitimate - // error (which will then be downgraded to a - // warning by the migrate machinery). - error_access = match wk { - WriteKind::MutableBorrow(_) => AccessKind::MutableBorrow, - WriteKind::Move => AccessKind::Move, - WriteKind::StorageDeadOrDrop | - WriteKind::Mutate => AccessKind::Mutate, - }; - self.report_mutability_error( - place, - span, - place_err, - error_access, - location, - ); - } else { - span_bug!( - span, - "Accessing `{:?}` with the kind `{:?}` shouldn't be possible", - place, - kind, - ); - } + // rust-lang/rust#46908: In pure NLL mode this code path should be + // unreachable, but we use `delay_span_bug` because we can hit this when + // dereferencing a non-Copy raw pointer *and* have `-Ztreat-err-as-bug` + // enabled. We don't want to ICE for that case, as other errors will have + // been emitted (#52262). + self.infcx.tcx.sess.delay_span_bug(span, &format!( + "Accessing `{:?}` with the kind `{:?}` shouldn't be possible", + place, + kind, + )); } return false; } @@ -2075,7 +2006,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { match root_place { RootPlace { place_base: PlaceBase::Local(local), - place_projection: None, + place_projection: [], is_local_mutation_allowed, } => { // If the local may have been initialized, and it is now currently being @@ -2094,7 +2025,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } => {} RootPlace { place_base, - place_projection: place_projection @ Some(_), + place_projection: place_projection @ [.., _], is_local_mutation_allowed: _, } => { if let Some(field) = self.is_upvar_field_projection(PlaceRef { @@ -2106,7 +2037,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } RootPlace { place_base: PlaceBase::Static(..), - place_projection: None, + place_projection: [], is_local_mutation_allowed: _, } => {} } @@ -2122,7 +2053,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { match place { PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } => { let local = &self.body.local_decls[*local]; match local.mutability { @@ -2150,10 +2081,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // `Place::Promoted` if the promotion weren't 100% legal. So we just forward this PlaceRef { base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(_), + kind: StaticKind::Promoted(..), .. }), - projection: None, + projection: [], } => Ok(RootPlace { place_base: place.base, @@ -2162,10 +2093,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }), PlaceRef { base: PlaceBase::Static(box Static { - kind: StaticKind::Static(def_id), + kind: StaticKind::Static, + def_id, .. }), - projection: None, + projection: [], } => { if !self.infcx.tcx.is_mutable_static(*def_id) { Err(place) @@ -2179,15 +2111,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } PlaceRef { base: _, - projection: Some(proj), + projection: [proj_base @ .., elem], } => { - match proj.elem { + match elem { ProjectionElem::Deref => { let base_ty = - Place::ty_from(place.base, &proj.base, self.body, self.infcx.tcx).ty; + Place::ty_from(place.base, proj_base, self.body, self.infcx.tcx).ty; // Check the kind of deref to decide - match base_ty.sty { + match base_ty.kind { ty::Ref(_, _, mutbl) => { match mutbl { // Shared borrowed data is never mutable @@ -2206,7 +2138,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.is_mutable(PlaceRef { base: place.base, - projection: &proj.base, + projection: proj_base, }, mode) } } @@ -2230,7 +2162,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { _ if base_ty.is_box() => { self.is_mutable(PlaceRef { base: place.base, - projection: &proj.base, + projection: proj_base, }, is_local_mutation_allowed) } // Deref should only be for reference, pointers or boxes @@ -2287,7 +2219,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // ``` let _ = self.is_mutable(PlaceRef { base: place.base, - projection: &proj.base, + projection: proj_base, }, is_local_mutation_allowed)?; Ok(RootPlace { place_base: place.base, @@ -2299,7 +2231,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else { self.is_mutable(PlaceRef { base: place.base, - projection: &proj.base, + projection: proj_base, }, is_local_mutation_allowed) } } @@ -2316,21 +2248,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut place_projection = place_ref.projection; let mut by_ref = false; - if let Some(box Projection { - base, - elem: ProjectionElem::Deref, - }) = place_projection { - place_projection = &base; + if let [proj_base @ .., ProjectionElem::Deref] = place_projection { + place_projection = proj_base; by_ref = true; } match place_projection { - Some(box Projection { - base, - elem: ProjectionElem::Field(field, _ty), - }) => { + [base @ .., ProjectionElem::Field(field, _ty)] => { let tcx = self.infcx.tcx; - let base_ty = Place::ty_from(place_ref.base, &base, self.body, tcx).ty; + let base_ty = Place::ty_from(place_ref.base, base, self.body, tcx).ty; if (base_ty.is_closure() || base_ty.is_generator()) && (!by_ref || self.upvars[field.index()].by_ref) { diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index 738a091b0dd76..431361fa5a87b 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -1,5 +1,3 @@ -use core::unicode::property::Pattern_White_Space; - use rustc::mir::*; use rustc::ty; use rustc_errors::{DiagnosticBuilder,Applicability}; @@ -91,11 +89,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // If that ever stops being the case, then the ever initialized // flow could be used. if let Some(StatementKind::Assign( - Place { - base: PlaceBase::Local(local), - projection: None, - }, - box Rvalue::Use(Operand::Move(move_from)), + box( + Place { + base: PlaceBase::Local(local), + projection: box [], + }, + Rvalue::Use(Operand::Move(move_from)) + ) )) = self.body.basic_blocks()[location.block] .statements .get(location.statement_index) @@ -276,16 +276,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { place: &Place<'tcx>, span: Span ) -> DiagnosticBuilder<'a> { - let description = if place.projection.is_none() { + let description = if place.projection.is_empty() { format!("static item `{}`", self.describe_place(place.as_ref()).unwrap()) } else { - let mut base_static = &place.projection; - while let Some(box Projection { base: Some(ref proj), .. }) = base_static { - base_static = &proj.base; - } let base_static = PlaceRef { base: &place.base, - projection: base_static, + projection: &place.projection[..1], }; format!( @@ -311,17 +307,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All) .find_map(|p| self.is_upvar_field_projection(p)); - let deref_base = match deref_target_place.projection { - Some(box Projection { ref base, elem: ProjectionElem::Deref }) => PlaceRef { - base: &deref_target_place.base, - projection: base, - }, + let deref_base = match &deref_target_place.projection { + box [proj_base @ .., ProjectionElem::Deref] => { + PlaceRef { + base: &deref_target_place.base, + projection: proj_base, + } + } _ => bug!("deref_target_place is not a deref projection"), }; if let PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } = deref_base { let decl = &self.body.local_decls[*local]; if decl.is_ref_for_guard() { @@ -337,13 +335,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } debug!("report: ty={:?}", ty); - let mut err = match ty.sty { + let mut err = match ty.kind { ty::Array(..) | ty::Slice(..) => self.cannot_move_out_of_interior_noncopy(span, ty, None), ty::Closure(def_id, closure_substs) if def_id == self.mir_def_id && upvar_field.is_some() => { - let closure_kind_ty = closure_substs.closure_kind_ty(def_id, self.infcx.tcx); + let closure_kind_ty = closure_substs + .as_closure().kind_ty(def_id, self.infcx.tcx); let closure_kind = closure_kind_ty.to_opt_closure_kind(); let capture_description = match closure_kind { Some(ty::ClosureKind::Fn) => { @@ -415,20 +414,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { "{:?}", move_place.ty(self.body, self.infcx.tcx).ty, ); - let snippet = self.infcx.tcx.sess.source_map().span_to_snippet(span).unwrap(); - let is_option = move_ty.starts_with("std::option::Option"); - let is_result = move_ty.starts_with("std::result::Result"); - if is_option || is_result { - err.span_suggestion( - span, - &format!("consider borrowing the `{}`'s content", if is_option { - "Option" - } else { - "Result" - }), - format!("{}.as_ref()", snippet), - Applicability::MaybeIncorrect, - ); + if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { + let is_option = move_ty.starts_with("std::option::Option"); + let is_result = move_ty.starts_with("std::result::Result"); + if is_option || is_result { + err.span_suggestion( + span, + &format!("consider borrowing the `{}`'s content", if is_option { + "Option" + } else { + "Result" + }), + format!("{}.as_ref()", snippet), + Applicability::MaybeIncorrect, + ); + } } err } @@ -439,19 +439,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'a>, span: Span, ) { - let snippet = self.infcx.tcx.sess.source_map().span_to_snippet(span).unwrap(); match error { GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => { - err.span_suggestion( - span, - "consider borrowing here", - format!("&{}", snippet), - Applicability::Unspecified, - ); + if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { + err.span_suggestion( + span, + "consider borrowing here", + format!("&{}", snippet), + Applicability::Unspecified, + ); + } if binds_to.is_empty() { let place_ty = move_from.ty(self.body, self.infcx.tcx).ty; @@ -517,27 +518,27 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .. })) ) = bind_to.is_user_variable { - let pat_snippet = self.infcx.tcx.sess.source_map() - .span_to_snippet(pat_span) - .unwrap(); - if pat_snippet.starts_with('&') { - let pat_snippet = pat_snippet[1..].trim_start(); - let suggestion; - let to_remove; - if pat_snippet.starts_with("mut") - && pat_snippet["mut".len()..].starts_with(Pattern_White_Space) - { - suggestion = pat_snippet["mut".len()..].trim_start(); - to_remove = "&mut"; - } else { - suggestion = pat_snippet; - to_remove = "&"; + if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) + { + if pat_snippet.starts_with('&') { + let pat_snippet = pat_snippet[1..].trim_start(); + let suggestion; + let to_remove; + if pat_snippet.starts_with("mut") + && pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace) + { + suggestion = pat_snippet["mut".len()..].trim_start(); + to_remove = "&mut"; + } else { + suggestion = pat_snippet; + to_remove = "&"; + } + suggestions.push(( + pat_span, + to_remove, + suggestion.to_owned(), + )); } - suggestions.push(( - pat_span, - to_remove, - suggestion.to_owned(), - )); } } } diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index 937c6383be341..8ab4020394ffd 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -1,12 +1,11 @@ -use core::unicode::property::Pattern_White_Space; use rustc::hir; use rustc::hir::Node; use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Body}; use rustc::mir::{ - Mutability, Place, PlaceRef, PlaceBase, Projection, ProjectionElem, Static, StaticKind + Mutability, Place, PlaceRef, PlaceBase, ProjectionElem, Static, StaticKind }; use rustc::ty::{self, Ty, TyCtxt}; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use syntax_pos::Span; use syntax_pos::symbol::kw; @@ -19,7 +18,6 @@ use rustc_errors::Applicability; pub(super) enum AccessKind { MutableBorrow, Mutate, - Move, } impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { @@ -48,12 +46,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { match the_place_err { PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } => { item_msg = format!("`{}`", access_place_desc.unwrap()); if let Place { base: PlaceBase::Local(_), - projection: None, + projection: box [], } = access_place { reason = ", as it is not declared as mutable".to_string(); } else { @@ -66,14 +64,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: _, - projection: - Some(box Projection { - base, - elem: ProjectionElem::Field(upvar_index, _), - }), + projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)], } => { debug_assert!(is_closure_or_generator( - Place::ty_from(&the_place_err.base, &base, self.body, self.infcx.tcx).ty + Place::ty_from(&the_place_err.base, proj_base, self.body, self.infcx.tcx).ty )); item_msg = format!("`{}`", access_place_desc.unwrap()); @@ -87,14 +81,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: _, - projection: - Some(box Projection { - base, - elem: ProjectionElem::Deref, - }), + projection: [proj_base @ .., ProjectionElem::Deref], } => { if the_place_err.base == &PlaceBase::Local(Local::new(1)) && - base.is_none() && + proj_base.is_empty() && !self.upvars.is_empty() { item_msg = format!("`{}`", access_place_desc.unwrap()); debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr()); @@ -115,7 +105,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ", as `Fn` closures cannot mutate their captured variables".to_string() } } else if { - if let (PlaceBase::Local(local), None) = (&the_place_err.base, base) { + if let (PlaceBase::Local(local), []) = (&the_place_err.base, proj_base) { self.body.local_decls[*local].is_ref_for_guard() } else { false @@ -126,14 +116,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } else { let source = self.borrowed_content_source(PlaceRef { base: the_place_err.base, - projection: base, + projection: proj_base, }); let pointer_type = source.describe_for_immutable_place(); opt_source = Some(source); if let Some(desc) = access_place_desc { item_msg = format!("`{}`", desc); reason = match error_access { - AccessKind::Move | AccessKind::Mutate => format!(" which is behind {}", pointer_type), AccessKind::MutableBorrow => { format!(", as it is behind {}", pointer_type) @@ -149,23 +138,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(_), + kind: StaticKind::Promoted(..), .. }), - projection: None, + projection: [], } => unreachable!(), PlaceRef { base: PlaceBase::Static(box Static { - kind: StaticKind::Static(def_id), + kind: StaticKind::Static, + def_id, .. }), - projection: None, + projection: [], } => { if let Place { base: PlaceBase::Static(_), - projection: None, + projection: box [], } = access_place { item_msg = format!("immutable static item `{}`", access_place_desc.unwrap()); reason = String::new(); @@ -178,33 +168,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: _, - projection: - Some(box Projection { - base: _, - elem: ProjectionElem::Index(_), - }), + projection: [.., ProjectionElem::Index(_)], } | PlaceRef { base: _, - projection: - Some(box Projection { - base: _, - elem: ProjectionElem::ConstantIndex { .. }, - }), + projection: [.., ProjectionElem::ConstantIndex { .. }], } | PlaceRef { base: _, - projection: Some(box Projection { - base: _, - elem: ProjectionElem::Subslice { .. }, - }), + projection: [.., ProjectionElem::Subslice { .. }], } | PlaceRef { base: _, - projection: Some(box Projection { - base: _, - elem: ProjectionElem::Downcast(..), - }), + projection: [.., ProjectionElem::Downcast(..)], } => bug!("Unexpected immutable place."), } @@ -216,12 +192,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let acted_on; let span = match error_access { - AccessKind::Move => { - err = self.cannot_move_out_of(span, &(item_msg + &reason)); - err.span_label(span, "cannot move"); - err.buffer(&mut self.errors_buffer); - return; - } AccessKind::Mutate => { err = self.cannot_assign(span, &(item_msg + &reason)); act = "assign"; @@ -262,22 +232,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // after the field access). PlaceRef { base, - projection: Some(box Projection { - base: Some(box Projection { - base: Some(box Projection { - base: base_proj, - elem: ProjectionElem::Deref, - }), - elem: ProjectionElem::Field(field, _), - }), - elem: ProjectionElem::Deref, - }), + projection: [proj_base @ .., + ProjectionElem::Deref, + ProjectionElem::Field(field, _), + ProjectionElem::Deref, + ], } => { err.span_label(span, format!("cannot {ACT}", ACT = act)); if let Some((span, message)) = annotate_struct_field( self.infcx.tcx, - Place::ty_from(&base, &base_proj, self.body, self.infcx.tcx).ty, + Place::ty_from(base, proj_base, self.body, self.infcx.tcx).ty, field, ) { err.span_suggestion( @@ -292,7 +257,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // Suggest removing a `&mut` from the use of a mutable reference. PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } if { self.body.local_decls.get(*local).map(|local_decl| { if let ClearCrossCrate::Set( @@ -310,7 +275,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // for a `self: &mut Self` to suggest removing the `&mut`. if let ty::Ref( _, _, hir::Mutability::MutMutable - ) = local_decl.ty.sty { + ) = local_decl.ty.kind { true } else { false @@ -328,7 +293,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // variable) mutations... PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } if self.body.local_decls[*local].can_be_made_mutable() => { // ... but it doesn't make sense to suggest it on // variables that are `ref x`, `ref mut x`, `&self`, @@ -349,13 +314,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // Also suggest adding mut for upvars PlaceRef { base, - projection: Some(box Projection { - base: proj_base, - elem: ProjectionElem::Field(upvar_index, _), - }), + projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)], } => { debug_assert!(is_closure_or_generator( - Place::ty_from(&base, &proj_base, self.body, self.infcx.tcx).ty + Place::ty_from(base, proj_base, self.body, self.infcx.tcx).ty )); err.span_label(span, format!("cannot {ACT}", ACT = act)); @@ -368,7 +330,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { _, upvar_ident, _, - ) = pat.node + ) = pat.kind { err.span_suggestion( upvar_ident.span, @@ -385,7 +347,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // a local variable, then just suggest the user remove it. PlaceRef { base: PlaceBase::Local(_), - projection: None, + projection: [], } if { if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { snippet.starts_with("&mut ") @@ -400,10 +362,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: PlaceBase::Local(local), - projection: Some(box Projection { - base: None, - elem: ProjectionElem::Deref, - }), + projection: [ProjectionElem::Deref], } if { if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) = self.body.local_decls[*local].is_user_variable @@ -427,10 +386,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // arbitrary base for the projection? PlaceRef { base: PlaceBase::Local(local), - projection: Some(box Projection { - base: None, - elem: ProjectionElem::Deref, - }), + projection: [ProjectionElem::Deref], } if self.body.local_decls[*local].is_user_variable.is_some() => { let local_decl = &self.body.local_decls[*local]; @@ -510,10 +466,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base, - projection: Some(box Projection { - base: None, - elem: ProjectionElem::Deref, - }), + projection: [ProjectionElem::Deref], // FIXME document what is this 1 magic number about } if *base == PlaceBase::Local(Local::new(1)) && !self.upvars.is_empty() => @@ -527,10 +480,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: _, - projection: Some(box Projection { - base: _, - elem: ProjectionElem::Deref, - }), + projection: [.., ProjectionElem::Deref], } => { err.span_label(span, format!("cannot {ACT}", ACT = act)); @@ -672,8 +622,8 @@ fn annotate_struct_field( field: &mir::Field, ) -> Option<(Span, String)> { // Expect our local to be a reference to a struct of some kind. - if let ty::Ref(_, ty, _) = ty.sty { - if let ty::Adt(def, _) = ty.sty { + if let ty::Ref(_, ty, _) = ty.kind { + if let ty::Adt(def, _) = ty.kind { let field = def.all_fields().nth(field.index())?; // Use the HIR types to construct the diagnostic message. let hir_id = tcx.hir().as_local_hir_id(field.did)?; @@ -684,7 +634,7 @@ fn annotate_struct_field( if let hir::TyKind::Rptr(lifetime, hir::MutTy { mutbl: hir::Mutability::MutImmutable, ref ty - }) = field.ty.node { + }) = field.ty.kind { // Get the snippets in two parts - the named lifetime (if there is one) and // type being referenced, that way we can reconstruct the snippet without loss // of detail. @@ -711,10 +661,10 @@ fn annotate_struct_field( } /// If possible, suggest replacing `ref` with `ref mut`. -fn suggest_ref_mut(tcx: TyCtxt<'_>, binding_span: Span) -> Option<(String)> { - let hi_src = tcx.sess.source_map().span_to_snippet(binding_span).unwrap(); +fn suggest_ref_mut(tcx: TyCtxt<'_>, binding_span: Span) -> Option { + let hi_src = tcx.sess.source_map().span_to_snippet(binding_span).ok()?; if hi_src.starts_with("ref") - && hi_src["ref".len()..].starts_with(Pattern_White_Space) + && hi_src["ref".len()..].starts_with(rustc_lexer::is_whitespace) { let replacement = format!("ref mut{}", &hi_src["ref".len()..]); Some(replacement) diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 5c230913a0da3..b105664399a5c 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -8,12 +8,11 @@ use rustc::infer::InferCtxt; use rustc::mir::visit::TyContext; use rustc::mir::visit::Visitor; use rustc::mir::{ - BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, Projection, - ProjectionElem, Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, - UserTypeProjection, + BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, ProjectionElem, Rvalue, + SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection, }; use rustc::ty::fold::TypeFoldable; -use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty}; +use rustc::ty::{self, RegionVid, Ty}; use rustc::ty::subst::SubstsRef; pub(super) fn generate_constraints<'cx, 'tcx>( @@ -92,20 +91,6 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> { self.super_ty(ty); } - /// We sometimes have `generator_substs` within an rvalue, or within a - /// call. Make them live at the location where they appear. - fn visit_generator_substs(&mut self, substs: &GeneratorSubsts<'tcx>, location: Location) { - self.add_regular_live_constraint(*substs, location); - self.super_generator_substs(substs); - } - - /// We sometimes have `closure_substs` within an rvalue, or within a - /// call. Make them live at the location where they appear. - fn visit_closure_substs(&mut self, substs: &ClosureSubsts<'tcx>, location: Location) { - self.add_regular_live_constraint(*substs, location); - self.super_closure_substs(substs); - } - fn visit_statement( &mut self, statement: &Statement<'tcx>, @@ -229,14 +214,11 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { match place { Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } | Place { base: PlaceBase::Local(local), - projection: Some(box Projection { - base: None, - elem: ProjectionElem::Deref, - }), + projection: box [ProjectionElem::Deref], } => { debug!( "Recording `killed` facts for borrows of local={:?} at location={:?}", @@ -261,7 +243,7 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { Place { base: PlaceBase::Local(local), - projection: Some(_), + projection: box [.., _], } => { // Kill conflicting borrows of the innermost local. debug!( diff --git a/src/librustc_mir/borrow_check/nll/constraints/graph.rs b/src/librustc_mir/borrow_check/nll/constraints/graph.rs index b5630251e5830..b6a9a7ee6578f 100644 --- a/src/librustc_mir/borrow_check/nll/constraints/graph.rs +++ b/src/librustc_mir/borrow_check/nll/constraints/graph.rs @@ -4,7 +4,7 @@ use crate::borrow_check::nll::constraints::{OutlivesConstraintSet, OutlivesConst use rustc::mir::ConstraintCategory; use rustc::ty::RegionVid; use rustc_data_structures::graph; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::vec::IndexVec; use syntax_pos::DUMMY_SP; /// The construct graph organizes the constraints by their end-points. diff --git a/src/librustc_mir/borrow_check/nll/constraints/mod.rs b/src/librustc_mir/borrow_check/nll/constraints/mod.rs index 6121ed0cf0d1c..93113753c630b 100644 --- a/src/librustc_mir/borrow_check/nll/constraints/mod.rs +++ b/src/librustc_mir/borrow_check/nll/constraints/mod.rs @@ -2,7 +2,7 @@ use crate::borrow_check::nll::type_check::Locations; use rustc::mir::ConstraintCategory; use rustc::ty::RegionVid; use rustc_data_structures::graph::scc::Sccs; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_index::vec::{Idx, IndexVec}; use std::fmt; use std::ops::Index; @@ -100,13 +100,13 @@ impl fmt::Debug for OutlivesConstraint { } } -newtype_index! { +rustc_index::newtype_index! { pub struct OutlivesConstraintIndex { DEBUG_FORMAT = "OutlivesConstraintIndex({})" } } -newtype_index! { +rustc_index::newtype_index! { pub struct ConstraintSccIndex { DEBUG_FORMAT = "ConstraintSccIndex({})" } diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index aba3ef1cbbfc9..5354b45f92d0a 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -17,6 +17,7 @@ use syntax_pos::Span; mod find_use; +#[derive(Debug)] pub(in crate::borrow_check) enum BorrowExplanation { UsedLater(LaterUseKind, Span), UsedLaterInLoop(LaterUseKind, Span), @@ -35,7 +36,7 @@ pub(in crate::borrow_check) enum BorrowExplanation { Unexplained, } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub(in crate::borrow_check) enum LaterUseKind { TraitCapture, ClosureCapture, @@ -95,7 +96,7 @@ impl BorrowExplanation { should_note_order, } => { let local_decl = &body.local_decls[dropped_local]; - let (dtor_desc, type_desc) = match local_decl.ty.sty { + let (dtor_desc, type_desc) = match local_decl.ty.kind { // If type is an ADT that implements Drop, then // simplify output by reporting just the ADT name. ty::Adt(adt, _substs) if adt.has_dtor(tcx) && !adt.is_box() => ( @@ -274,7 +275,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place { if let Place { base: PlaceBase::Local(borrowed_local), - projection: None, + projection: box [], } = place { if body.local_decls[*borrowed_local].name.is_some() && local != *borrowed_local @@ -495,11 +496,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Operand::Constant(c) => c.span, Operand::Copy(Place { base: PlaceBase::Local(l), - projection: None, + projection: box [], }) | Operand::Move(Place { base: PlaceBase::Local(l), - projection: None, + projection: box [], }) => { let local_decl = &self.body.local_decls[*l]; if local_decl.name.is_none() { @@ -541,10 +542,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // it which simplifies the termination logic. let mut queue = vec![location]; let mut target = if let Some(&Statement { - kind: StatementKind::Assign(Place { + kind: StatementKind::Assign(box(Place { base: PlaceBase::Local(local), - projection: None, - }, _), + projection: box [], + }, _)), .. }) = stmt { @@ -567,7 +568,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("was_captured_by_trait_object: stmt={:?}", stmt); // The only kind of statement that we care about is assignments... - if let StatementKind::Assign(place, box rvalue) = &stmt.kind { + if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind { let into = match place.local_or_deref_local() { Some(into) => into, None => { @@ -583,11 +584,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Rvalue::Use(operand) => match operand { Operand::Copy(Place { base: PlaceBase::Local(from), - projection: None, + projection: box [], }) | Operand::Move(Place { base: PlaceBase::Local(from), - projection: None, + projection: box [], }) if *from == target => { @@ -602,17 +603,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) => match operand { Operand::Copy(Place { base: PlaceBase::Local(from), - projection: None, + projection: box [], }) | Operand::Move(Place { base: PlaceBase::Local(from), - projection: None, + projection: box [], }) if *from == target => { debug!("was_captured_by_trait_object: ty={:?}", ty); // Check the type for a trait object. - return match ty.sty { + return match ty.kind { // `&dyn Trait` ty::Ref(_, ty, _) if ty.is_trait() => true, // `Box` @@ -639,7 +640,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let TerminatorKind::Call { destination: Some((Place { base: PlaceBase::Local(dest), - projection: None, + projection: box [], }, block)), args, .. @@ -653,7 +654,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let found_target = args.iter().any(|arg| { if let Operand::Move(Place { base: PlaceBase::Local(potential), - projection: None, + projection: box [], }) = arg { *potential == target } else { diff --git a/src/librustc_mir/borrow_check/nll/facts.rs b/src/librustc_mir/borrow_check/nll/facts.rs index 05451cdfb83d8..13e5769c5bea8 100644 --- a/src/librustc_mir/borrow_check/nll/facts.rs +++ b/src/librustc_mir/borrow_check/nll/facts.rs @@ -1,17 +1,17 @@ use crate::borrow_check::location::{LocationIndex, LocationTable}; -use crate::dataflow::indexes::BorrowIndex; +use crate::dataflow::indexes::{BorrowIndex, MovePathIndex}; use polonius_engine::AllFacts as PoloniusAllFacts; use polonius_engine::Atom; use rustc::mir::Local; use rustc::ty::{RegionVid, TyCtxt}; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use std::error::Error; use std::fmt::Debug; use std::fs::{self, File}; use std::io::Write; use std::path::Path; -crate type AllFacts = PoloniusAllFacts; +crate type AllFacts = PoloniusAllFacts; crate trait AllFactsExt { /// Returns `true` if there is a need to gather `AllFacts` given the @@ -58,14 +58,17 @@ impl AllFactsExt for AllFacts { cfg_edge, killed, outlives, - region_live_at, invalidates, var_used, var_defined, var_drop_used, var_uses_region, var_drops_region, - var_initialized_on_exit, + child, + path_belongs_to_var, + initialized_at, + moved_out_at, + path_accessed_at, ]) } Ok(()) @@ -84,6 +87,12 @@ impl Atom for LocationIndex { } } +impl Atom for MovePathIndex { + fn index(self) -> usize { + Idx::index(self) + } +} + struct FactWriter<'w> { location_table: &'w LocationTable, dir: &'w Path, diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index 71106af767064..1d429e3a6dee6 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -66,7 +66,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { self.check_activations(location); match statement.kind { - StatementKind::Assign(ref lhs, ref rhs) => { + StatementKind::Assign(box(ref lhs, ref rhs)) => { self.consume_rvalue( location, rhs, diff --git a/src/librustc_mir/borrow_check/nll/member_constraints.rs b/src/librustc_mir/borrow_check/nll/member_constraints.rs index b5e2e111f38e5..fd195873a55e4 100644 --- a/src/librustc_mir/borrow_check/nll/member_constraints.rs +++ b/src/librustc_mir/borrow_check/nll/member_constraints.rs @@ -2,7 +2,7 @@ use crate::rustc::ty::{self, Ty}; use rustc::hir::def_id::DefId; use rustc::infer::region_constraints::MemberConstraint; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_index::vec::{Idx, IndexVec}; use std::hash::Hash; use std::ops::Index; use syntax_pos::Span; @@ -51,7 +51,7 @@ crate struct NllMemberConstraint<'tcx> { end_index: usize, } -newtype_index! { +rustc_index::newtype_index! { crate struct NllMemberConstraintIndex { DEBUG_FORMAT = "MemberConstraintIndex({})" } diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index d65cdde303ca0..b2e5751b902e7 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -4,15 +4,17 @@ use crate::borrow_check::nll::facts::AllFactsExt; use crate::borrow_check::nll::type_check::{MirTypeckResults, MirTypeckRegionConstraints}; use crate::borrow_check::nll::region_infer::values::RegionValueElements; use crate::dataflow::indexes::BorrowIndex; -use crate::dataflow::move_paths::MoveData; +use crate::dataflow::move_paths::{InitLocation, MoveData, MovePathIndex, InitKind}; use crate::dataflow::FlowAtLocation; use crate::dataflow::MaybeInitializedPlaces; use crate::transform::MirSource; use crate::borrow_check::Upvar; use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; -use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Local, Body}; +use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, + Local, Location, Body, LocalKind, BasicBlock, Promoted}; use rustc::ty::{self, RegionKind, RegionVid}; +use rustc_index::vec::IndexVec; use rustc_errors::Diagnostic; use std::fmt::Debug; use std::env; @@ -52,6 +54,7 @@ pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>( def_id: DefId, param_env: ty::ParamEnv<'tcx>, body: &mut Body<'tcx>, + promoted: &mut IndexVec>, ) -> UniversalRegions<'tcx> { debug!("replace_regions_in_mir(def_id={:?})", def_id); @@ -59,7 +62,7 @@ pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>( let universal_regions = UniversalRegions::new(infcx, def_id, param_env); // Replace all remaining regions with fresh inference variables. - renumber::renumber_mir(infcx, body); + renumber::renumber_mir(infcx, body, promoted); let source = MirSource::item(def_id); mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, body, |_, _| Ok(())); @@ -67,6 +70,85 @@ pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>( universal_regions } + +// This function populates an AllFacts instance with base facts related to +// MovePaths and needed for the move analysis. +fn populate_polonius_move_facts( + all_facts: &mut AllFacts, + move_data: &MoveData<'_>, + location_table: &LocationTable, + body: &Body<'_>) { + all_facts + .path_belongs_to_var + .extend( + move_data + .rev_lookup + .iter_locals_enumerated() + .map(|(v, &m)| (m, v))); + + for (child, move_path) in move_data.move_paths.iter_enumerated() { + all_facts + .child + .extend( + move_path + .parents(&move_data.move_paths) + .iter() + .map(|&parent| (child, parent))); + } + + // initialized_at + for init in move_data.inits.iter() { + + match init.location { + InitLocation::Statement(location) => { + let block_data = &body[location.block]; + let is_terminator = location.statement_index == block_data.statements.len(); + + if is_terminator && init.kind == InitKind::NonPanicPathOnly { + // We are at the terminator of an init that has a panic path, + // and where the init should not happen on panic + + for &successor in block_data.terminator().successors() { + if body[successor].is_cleanup { + continue; + } + + // The initialization happened in (or rather, when arriving at) + // the successors, but not in the unwind block. + let first_statement = Location { block: successor, statement_index: 0}; + all_facts + .initialized_at + .push((init.path, location_table.start_index(first_statement))); + } + + } else { + // In all other cases, the initialization just happens at the + // midpoint, like any other effect. + all_facts.initialized_at.push((init.path, location_table.mid_index(location))); + } + }, + // Arguments are initialized on function entry + InitLocation::Argument(local) => { + assert!(body.local_kind(local) == LocalKind::Arg); + let fn_entry = Location {block: BasicBlock::from_u32(0u32), statement_index: 0 }; + all_facts.initialized_at.push((init.path, location_table.start_index(fn_entry))); + + } + } + } + + + // moved_out_at + // deinitialisation is assumed to always happen! + all_facts + .moved_out_at + .extend( + move_data + .moves + .iter() + .map(|mo| (mo.path, location_table.mid_index(mo.source)))); +} + /// Computes the (non-lexical) regions from the input MIR. /// /// This may result in errors being reported. @@ -75,6 +157,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( def_id: DefId, universal_regions: UniversalRegions<'tcx>, body: &Body<'tcx>, + promoted: &IndexVec>, upvars: &[Upvar], location_table: &LocationTable, param_env: ty::ParamEnv<'tcx>, @@ -84,7 +167,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( errors_buffer: &mut Vec, ) -> ( RegionInferenceContext<'tcx>, - Option>>, + Option>>, Option>, ) { let mut all_facts = if AllFacts::enabled(infcx.tcx) { @@ -105,6 +188,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( infcx, param_env, body, + promoted, def_id, &universal_regions, location_table, @@ -119,6 +203,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( all_facts .universal_region .extend(universal_regions.universal_regions()); + populate_polonius_move_facts(all_facts, move_data, location_table, body); } // Create the region inference context, taking ownership of the diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs index efa18587b7ddb..7362ae9c638b1 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs @@ -1,5 +1,4 @@ use crate::borrow_check::nll::constraints::OutlivesConstraint; -use crate::borrow_check::nll::region_infer::AppliedMemberConstraint; use crate::borrow_check::nll::region_infer::RegionInferenceContext; use crate::borrow_check::nll::type_check::Locations; use crate::borrow_check::nll::universal_regions::DefiningTy; @@ -12,8 +11,8 @@ use rustc::infer::InferCtxt; use rustc::infer::NLLRegionVariableOrigin; use rustc::mir::{ConstraintCategory, Location, Body}; use rustc::ty::{self, RegionVid}; -use rustc_data_structures::indexed_vec::IndexVec; -use rustc_errors::{Diagnostic, DiagnosticBuilder}; +use rustc_index::vec::IndexVec; +use rustc_errors::DiagnosticBuilder; use std::collections::VecDeque; use syntax::errors::Applicability; use syntax::symbol::kw; @@ -22,7 +21,7 @@ use syntax_pos::Span; mod region_name; mod var_name; -crate use self::region_name::{RegionName, RegionNameSource}; +crate use self::region_name::{RegionName, RegionNameSource, RegionErrorNamingCtx}; impl ConstraintDescription for ConstraintCategory { fn description(&self) -> &'static str { @@ -54,6 +53,39 @@ enum Trace { NotVisited, } +/// Various pieces of state used when reporting borrow checker errors. +pub struct ErrorReportingCtx<'a, 'b, 'tcx> { + /// The region inference context used for borrow chekcing this MIR body. + #[allow(dead_code)] // FIXME(mark-i-m): used by outlives suggestions + region_infcx: &'b RegionInferenceContext<'tcx>, + + /// The inference context used for type checking. + infcx: &'b InferCtxt<'a, 'tcx>, + + /// The MIR def we are reporting errors on. + mir_def_id: DefId, + + /// The MIR body we are reporting errors on (for convenience). + body: &'b Body<'tcx>, + + /// Any upvars for the MIR body we have kept track of during borrow checking. + upvars: &'b [Upvar], +} + +/// Information about the various region constraints involved in a borrow checker error. +#[derive(Clone, Debug)] +pub struct ErrorConstraintInfo { + // fr: outlived_fr + fr: RegionVid, + fr_is_local: bool, + outlived_fr: RegionVid, + outlived_fr_is_local: bool, + + // Category and span for best blame constraint + category: ConstraintCategory, + span: Span, +} + impl<'tcx> RegionInferenceContext<'tcx> { /// Tries to find the best constraint to blame for the fact that /// `R: from_region`, where `R` is some region that meets @@ -65,9 +97,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, body: &Body<'tcx>, from_region: RegionVid, + from_region_origin: NLLRegionVariableOrigin, target_test: impl Fn(RegionVid) -> bool, ) -> (ConstraintCategory, bool, Span) { - debug!("best_blame_constraint(from_region={:?})", from_region); + debug!("best_blame_constraint(from_region={:?}, from_region_origin={:?})", + from_region, from_region_origin); // Find all paths let (path, target_region) = @@ -120,19 +154,85 @@ impl<'tcx> RegionInferenceContext<'tcx> { // we still want to screen for an "interesting" point to // highlight (e.g., a call site or something). let target_scc = self.constraint_sccs.scc(target_region); - let best_choice = (0..path.len()).rev().find(|&i| { - let constraint = path[i]; + let mut range = 0..path.len(); + + // As noted above, when reporting an error, there is typically a chain of constraints + // leading from some "source" region which must outlive some "target" region. + // In most cases, we prefer to "blame" the constraints closer to the target -- + // but there is one exception. When constraints arise from higher-ranked subtyping, + // we generally prefer to blame the source value, + // as the "target" in this case tends to be some type annotation that the user gave. + // Therefore, if we find that the region origin is some instantiation + // of a higher-ranked region, we start our search from the "source" point + // rather than the "target", and we also tweak a few other things. + // + // An example might be this bit of Rust code: + // + // ```rust + // let x: fn(&'static ()) = |_| {}; + // let y: for<'a> fn(&'a ()) = x; + // ``` + // + // In MIR, this will be converted into a combination of assignments and type ascriptions. + // In particular, the 'static is imposed through a type ascription: + // + // ```rust + // x = ...; + // AscribeUserType(x, fn(&'static ()) + // y = x; + // ``` + // + // We wind up ultimately with constraints like + // + // ```rust + // !a: 'temp1 // from the `y = x` statement + // 'temp1: 'temp2 + // 'temp2: 'static // from the AscribeUserType + // ``` + // + // and here we prefer to blame the source (the y = x statement). + let blame_source = match from_region_origin { + NLLRegionVariableOrigin::FreeRegion + | NLLRegionVariableOrigin::Existential { from_forall: false } => { + true + } + NLLRegionVariableOrigin::Placeholder(_) + | NLLRegionVariableOrigin::Existential { from_forall: true } => { + false + } + }; + + let find_region = |i: &usize| { + let constraint = path[*i]; let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup); - match categorized_path[i].0 { - ConstraintCategory::OpaqueType | ConstraintCategory::Boring | - ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal => false, - ConstraintCategory::TypeAnnotation | ConstraintCategory::Return | - ConstraintCategory::Yield => true, - _ => constraint_sup_scc != target_scc, + if blame_source { + match categorized_path[*i].0 { + ConstraintCategory::OpaqueType | ConstraintCategory::Boring | + ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal => false, + ConstraintCategory::TypeAnnotation | ConstraintCategory::Return | + ConstraintCategory::Yield => true, + _ => constraint_sup_scc != target_scc, + } + } else { + match categorized_path[*i].0 { + ConstraintCategory::OpaqueType | ConstraintCategory::Boring | + ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal => false, + _ => true + } } - }); + }; + + let best_choice = if blame_source { + range.rev().find(find_region) + } else { + range.find(find_region) + }; + + debug!("best_blame_constraint: best_choice={:?} blame_source={}", + best_choice, blame_source); + if let Some(i) = best_choice { if let Some(next) = categorized_path.get(i + 1) { if categorized_path[i].0 == ConstraintCategory::Return @@ -220,29 +320,33 @@ impl<'tcx> RegionInferenceContext<'tcx> { let outgoing_edges_from_graph = self.constraint_graph .outgoing_edges(r, &self.constraints, fr_static); - - // But member constraints can also give rise to `'r: 'x` - // edges that were not part of the graph initially, so - // watch out for those. - let outgoing_edges_from_picks = self.applied_member_constraints(r) - .iter() - .map(|&AppliedMemberConstraint { min_choice, member_constraint_index, .. }| { - let p_c = &self.member_constraints[member_constraint_index]; - OutlivesConstraint { - sup: r, - sub: min_choice, - locations: Locations::All(p_c.definition_span), - category: ConstraintCategory::OpaqueType, - } - }); - - for constraint in outgoing_edges_from_graph.chain(outgoing_edges_from_picks) { + // Always inline this closure because it can be hot. + let mut handle_constraint = #[inline(always)] |constraint: OutlivesConstraint| { debug_assert_eq!(constraint.sup, r); let sub_region = constraint.sub; if let Trace::NotVisited = context[sub_region] { context[sub_region] = Trace::FromOutlivesConstraint(constraint); deque.push_back(sub_region); } + }; + + // This loop can be hot. + for constraint in outgoing_edges_from_graph { + handle_constraint(constraint); + } + + // Member constraints can also give rise to `'r: 'x` edges that + // were not part of the graph initially, so watch out for those. + // (But they are extremely rare; this loop is very cold.) + for constraint in self.applied_member_constraints(r) { + let p_c = &self.member_constraints[constraint.member_constraint_index]; + let constraint = OutlivesConstraint { + sup: r, + sub: constraint.min_choice, + locations: Locations::All(p_c.definition_span), + category: ConstraintCategory::OpaqueType, + }; + handle_constraint(constraint); } } @@ -257,19 +361,20 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// ``` /// /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`. - pub(super) fn report_error( - &self, + pub(super) fn report_error<'a>( + &'a self, body: &Body<'tcx>, upvars: &[Upvar], - infcx: &InferCtxt<'_, 'tcx>, + infcx: &'a InferCtxt<'a, 'tcx>, mir_def_id: DefId, fr: RegionVid, + fr_origin: NLLRegionVariableOrigin, outlived_fr: RegionVid, - errors_buffer: &mut Vec, - ) { + renctx: &mut RegionErrorNamingCtx, + ) -> DiagnosticBuilder<'a> { debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr); - let (category, _, span) = self.best_blame_constraint(body, fr, |r| { + let (category, _, span) = self.best_blame_constraint(body, fr, fr_origin, |r| { self.provides_universal_region(r, fr, outlived_fr) }); @@ -279,8 +384,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let tables = infcx.tcx.typeck_tables_of(mir_def_id); let nice = NiceRegionError::new_from_span(infcx, span, o, f, Some(tables)); if let Some(diag) = nice.try_report_from_nll() { - diag.buffer(errors_buffer); - return; + return diag; } } @@ -293,45 +397,28 @@ impl<'tcx> RegionInferenceContext<'tcx> { "report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}", fr_is_local, outlived_fr_is_local, category ); + + let errctx = ErrorReportingCtx { + region_infcx: self, + infcx, + mir_def_id, + body, + upvars, + }; + + let errci = ErrorConstraintInfo { + fr, outlived_fr, fr_is_local, outlived_fr_is_local, category, span + }; + match (category, fr_is_local, outlived_fr_is_local) { (ConstraintCategory::Return, true, false) if self.is_closure_fn_mut(infcx, fr) => { - self.report_fnmut_error( - body, - upvars, - infcx, - mir_def_id, - fr, - outlived_fr, - span, - errors_buffer, - ) + self.report_fnmut_error(&errctx, &errci, renctx) } (ConstraintCategory::Assignment, true, false) - | (ConstraintCategory::CallArgument, true, false) => self.report_escaping_data_error( - body, - upvars, - infcx, - mir_def_id, - fr, - outlived_fr, - category, - span, - errors_buffer, - ), - _ => self.report_general_error( - body, - upvars, - infcx, - mir_def_id, - fr, - fr_is_local, - outlived_fr, - outlived_fr_is_local, - category, - span, - errors_buffer, - ), - }; + | (ConstraintCategory::CallArgument, true, false) => + self.report_escaping_data_error(&errctx, &errci, renctx), + _ => self.report_general_error(&errctx, &errci, renctx), + } } /// We have a constraint `fr1: fr2` that is not satisfied, where @@ -379,19 +466,19 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// ``` fn report_fnmut_error( &self, - body: &Body<'tcx>, - upvars: &[Upvar], - infcx: &InferCtxt<'_, 'tcx>, - mir_def_id: DefId, - _fr: RegionVid, - outlived_fr: RegionVid, - span: Span, - errors_buffer: &mut Vec, - ) { - let mut diag = infcx + errctx: &ErrorReportingCtx<'_, '_, 'tcx>, + errci: &ErrorConstraintInfo, + renctx: &mut RegionErrorNamingCtx, + ) -> DiagnosticBuilder<'_> { + let ErrorConstraintInfo { + outlived_fr, span, .. + } = errci; + + let mut diag = errctx + .infcx .tcx .sess - .struct_span_err(span, "captured variable cannot escape `FnMut` closure body"); + .struct_span_err(*span, "captured variable cannot escape `FnMut` closure body"); // We should check if the return type of this closure is in fact a closure - in that // case, we can special case the error further. @@ -403,11 +490,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { "returns a reference to a captured variable which escapes the closure body" }; - diag.span_label(span, message); + diag.span_label(*span, message); - match self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_fr, &mut 1) - .unwrap().source - { + match self.give_region_a_name(errctx, renctx, *outlived_fr).unwrap().source { RegionNameSource::NamedEarlyBoundRegion(fr_span) | RegionNameSource::NamedFreeRegion(fr_span) | RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _) @@ -427,7 +512,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ); diag.note("...therefore, they cannot allow references to captured variables to escape"); - diag.buffer(errors_buffer); + diag } /// Reports a error specifically for when data is escaping a closure. @@ -444,20 +529,22 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// ``` fn report_escaping_data_error( &self, - body: &Body<'tcx>, - upvars: &[Upvar], - infcx: &InferCtxt<'_, 'tcx>, - mir_def_id: DefId, - fr: RegionVid, - outlived_fr: RegionVid, - category: ConstraintCategory, - span: Span, - errors_buffer: &mut Vec, - ) { + errctx: &ErrorReportingCtx<'_, '_, 'tcx>, + errci: &ErrorConstraintInfo, + renctx: &mut RegionErrorNamingCtx, + ) -> DiagnosticBuilder<'_> { + let ErrorReportingCtx { + infcx, body, upvars, .. + } = errctx; + + let ErrorConstraintInfo { + span, category, .. + } = errci; + let fr_name_and_span = - self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, fr); + self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, errci.fr); let outlived_fr_name_and_span = - self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, outlived_fr); + self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, errci.outlived_fr); let escapes_from = match self.universal_regions.defining_ty { DefiningTy::Closure(..) => "closure", @@ -469,27 +556,23 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Revert to the normal error in these cases. // Assignments aren't "escapes" in function items. if (fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none()) - || (category == ConstraintCategory::Assignment && escapes_from == "function") + || (*category == ConstraintCategory::Assignment && escapes_from == "function") || escapes_from == "const" { return self.report_general_error( - body, - upvars, - infcx, - mir_def_id, - fr, - true, - outlived_fr, - false, - category, - span, - errors_buffer, + errctx, + &ErrorConstraintInfo { + fr_is_local: true, + outlived_fr_is_local: false, + .. *errci + }, + renctx, ); } let mut diag = borrowck_errors::borrowed_data_escapes_closure( infcx.tcx, - span, + *span, escapes_from, ); @@ -513,12 +596,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { ); diag.span_label( - span, + *span, format!("`{}` escapes the {} body here", fr_name, escapes_from), ); } - diag.buffer(errors_buffer); + diag } /// Reports a region inference error for the general case with named/synthesized lifetimes to @@ -538,41 +621,37 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// ``` fn report_general_error( &self, - body: &Body<'tcx>, - upvars: &[Upvar], - infcx: &InferCtxt<'_, 'tcx>, - mir_def_id: DefId, - fr: RegionVid, - fr_is_local: bool, - outlived_fr: RegionVid, - outlived_fr_is_local: bool, - category: ConstraintCategory, - span: Span, - errors_buffer: &mut Vec, - ) { + errctx: &ErrorReportingCtx<'_, '_, 'tcx>, + errci: &ErrorConstraintInfo, + renctx: &mut RegionErrorNamingCtx, + ) -> DiagnosticBuilder<'_> { + let ErrorReportingCtx { + infcx, mir_def_id, .. + } = errctx; + let ErrorConstraintInfo { + fr, fr_is_local, outlived_fr, outlived_fr_is_local, span, category, .. + } = errci; + let mut diag = infcx.tcx.sess.struct_span_err( - span, + *span, "lifetime may not live long enough" ); - let counter = &mut 1; - let fr_name = self.give_region_a_name( - infcx, body, upvars, mir_def_id, fr, counter).unwrap(); - fr_name.highlight_region_name(&mut diag); - let outlived_fr_name = - self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_fr, counter).unwrap(); - outlived_fr_name.highlight_region_name(&mut diag); - - let mir_def_name = if infcx.tcx.is_closure(mir_def_id) { + let mir_def_name = if infcx.tcx.is_closure(*mir_def_id) { "closure" } else { "function" }; + let fr_name = self.give_region_a_name(errctx, renctx, *fr).unwrap(); + fr_name.highlight_region_name(&mut diag); + let outlived_fr_name = self.give_region_a_name(errctx, renctx, *outlived_fr).unwrap(); + outlived_fr_name.highlight_region_name(&mut diag); + match (category, outlived_fr_is_local, fr_is_local) { (ConstraintCategory::Return, true, _) => { diag.span_label( - span, + *span, format!( "{} was supposed to return data with lifetime `{}` but it is returning \ data with lifetime `{}`", @@ -582,7 +661,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } _ => { diag.span_label( - span, + *span, format!( "{}requires that `{}` must outlive `{}`", category.description(), @@ -593,9 +672,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - self.add_static_impl_trait_suggestion(infcx, &mut diag, fr, fr_name, outlived_fr); + self.add_static_impl_trait_suggestion(infcx, &mut diag, *fr, fr_name, *outlived_fr); - diag.buffer(errors_buffer); + diag } /// Adds a suggestion to errors where a `impl Trait` is returned. @@ -620,7 +699,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { (self.to_error_region(fr), self.to_error_region(outlived_fr)) { if let Some(ty::TyS { - sty: ty::Opaque(did, substs), + kind: ty::Opaque(did, substs), .. }) = infcx .tcx @@ -702,10 +781,17 @@ impl<'tcx> RegionInferenceContext<'tcx> { let (category, from_closure, span) = self.best_blame_constraint( body, borrow_region, + NLLRegionVariableOrigin::FreeRegion, |r| self.provides_universal_region(r, borrow_region, outlived_region) ); - let outlived_fr_name = - self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_region, &mut 1); + + let mut renctx = RegionErrorNamingCtx::new(); + let errctx = ErrorReportingCtx { + infcx, body, upvars, mir_def_id, + region_infcx: self, + }; + let outlived_fr_name = self.give_region_a_name(&errctx, &mut renctx, outlived_region); + (category, from_closure, span, outlived_fr_name) } @@ -755,11 +841,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, body: &Body<'tcx>, fr1: RegionVid, + fr1_origin: NLLRegionVariableOrigin, fr2: RegionVid, ) -> (ConstraintCategory, Span) { let (category, _, span) = self.best_blame_constraint( body, fr1, + fr1_origin, |r| self.provides_universal_region(r, fr1, fr2), ); (category, span) @@ -787,7 +875,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { if let Some(ty::ReFree(free_region)) = self.to_error_region(fr) { if let ty::BoundRegion::BrEnv = free_region.bound_region { if let DefiningTy::Closure(def_id, substs) = self.universal_regions.defining_ty { - let closure_kind_ty = substs.closure_kind_ty(def_id, infcx.tcx); + let closure_kind_ty = substs.as_closure().kind_ty(def_id, infcx.tcx); return Some(ty::ClosureKind::FnMut) == closure_kind_ty.to_opt_closure_kind(); } } @@ -812,7 +900,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { universe1.cannot_name(placeholder.universe) } - NLLRegionVariableOrigin::FreeRegion | NLLRegionVariableOrigin::Existential => false, + NLLRegionVariableOrigin::FreeRegion | NLLRegionVariableOrigin::Existential { .. } => { + false + } } } } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index 3f5b2f4bce78b..6fb976e0d84b2 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -1,5 +1,9 @@ use std::fmt::{self, Display}; -use crate::borrow_check::nll::region_infer::RegionInferenceContext; + +use crate::borrow_check::nll::region_infer::{ + RegionInferenceContext, + error_reporting::ErrorReportingCtx, +}; use crate::borrow_check::nll::universal_regions::DefiningTy; use crate::borrow_check::nll::ToRegionVid; use crate::borrow_check::Upvar; @@ -8,34 +12,80 @@ use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; use rustc::mir::Body; -use rustc::ty::subst::{SubstsRef, UnpackedKind}; +use rustc::ty::subst::{SubstsRef, GenericArgKind}; use rustc::ty::{self, RegionKind, RegionVid, Ty, TyCtxt}; use rustc::ty::print::RegionHighlightMode; use rustc_errors::DiagnosticBuilder; use syntax::symbol::kw; -use syntax_pos::Span; -use syntax_pos::symbol::InternedString; +use rustc_data_structures::fx::FxHashMap; +use syntax_pos::{Span, symbol::InternedString}; -#[derive(Debug)] +/// A name for a particular region used in emitting diagnostics. This name could be a generated +/// name like `'1`, a name used by the user like `'a`, or a name like `'static`. +#[derive(Debug, Clone)] crate struct RegionName { + /// The name of the region (interned). crate name: InternedString, + /// Where the region comes from. crate source: RegionNameSource, } -#[derive(Debug)] +/// Denotes the source of a region that is named by a `RegionName`. For example, a free region that +/// was named by the user would get `NamedFreeRegion` and `'static` lifetime would get `Static`. +/// This helps to print the right kinds of diagnostics. +#[derive(Debug, Clone)] crate enum RegionNameSource { + /// A bound (not free) region that was substituted at the def site (not an HRTB). NamedEarlyBoundRegion(Span), + /// A free region that the user has a name (`'a`) for. NamedFreeRegion(Span), + /// The `'static` region. Static, + /// The free region corresponding to the environment of a closure. SynthesizedFreeEnvRegion(Span, String), + /// The region name corresponds to a region where the type annotation is completely missing + /// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference. CannotMatchHirTy(Span, String), + /// The region name corresponds a reference that was found by traversing the type in the HIR. MatchedHirTy(Span), + /// A region name from the generics list of a struct/enum/union. MatchedAdtAndSegment(Span), + /// The region corresponding to a closure upvar. AnonRegionFromUpvar(Span, String), + /// The region corresponding to the return type of a closure. AnonRegionFromOutput(Span, String, String), AnonRegionFromYieldTy(Span, String), } +/// Records region names that have been assigned before so that we can use the same ones in later +/// diagnostics. +#[derive(Debug, Clone)] +crate struct RegionErrorNamingCtx { + /// Record the region names generated for each region in the given + /// MIR def so that we can reuse them later in help/error messages. + renctx: FxHashMap, + + /// The counter for generating new region names. + counter: usize, +} + +impl RegionErrorNamingCtx { + crate fn new() -> Self { + Self { + counter: 1, + renctx: FxHashMap::default(), + } + } + + crate fn get(&self, region: &RegionVid) -> Option<&RegionName> { + self.renctx.get(region) + } + + crate fn insert(&mut self, region: RegionVid, name: RegionName) { + self.renctx.insert(region, name); + } +} + impl RegionName { #[allow(dead_code)] crate fn was_named(&self) -> bool { @@ -63,43 +113,40 @@ impl RegionName { self.name } - crate fn highlight_region_name( - &self, - diag: &mut DiagnosticBuilder<'_> - ) { + crate fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) { match &self.source { - RegionNameSource::NamedFreeRegion(span) | - RegionNameSource::NamedEarlyBoundRegion(span) => { - diag.span_label( - *span, - format!("lifetime `{}` defined here", self), - ); - }, + RegionNameSource::NamedFreeRegion(span) + | RegionNameSource::NamedEarlyBoundRegion(span) => { + diag.span_label(*span, format!("lifetime `{}` defined here", self)); + } RegionNameSource::SynthesizedFreeEnvRegion(span, note) => { diag.span_label( *span, format!("lifetime `{}` represents this closure's body", self), ); diag.note(¬e); - }, + } RegionNameSource::CannotMatchHirTy(span, type_name) => { diag.span_label(*span, format!("has type `{}`", type_name)); - }, + } RegionNameSource::MatchedHirTy(span) => { diag.span_label( *span, format!("let's call the lifetime of this reference `{}`", self), ); - }, + } RegionNameSource::MatchedAdtAndSegment(span) => { diag.span_label(*span, format!("let's call this `{}`", self)); - }, + } RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => { diag.span_label( *span, - format!("lifetime `{}` appears in the type of `{}`", self, upvar_name), + format!( + "lifetime `{}` appears in the type of `{}`", + self, upvar_name + ), ); - }, + } RegionNameSource::AnonRegionFromOutput(span, mir_description, type_name) => { diag.span_label( *span, @@ -151,39 +198,49 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// and then return the name `'1` for us to use. crate fn give_region_a_name( &self, - infcx: &InferCtxt<'_, 'tcx>, - body: &Body<'tcx>, - upvars: &[Upvar], - mir_def_id: DefId, + errctx: &ErrorReportingCtx<'_, '_, 'tcx>, + renctx: &mut RegionErrorNamingCtx, fr: RegionVid, - counter: &mut usize, ) -> Option { - debug!("give_region_a_name(fr={:?}, counter={})", fr, counter); + let ErrorReportingCtx { + infcx, body, mir_def_id, upvars, .. + } = errctx; + + debug!("give_region_a_name(fr={:?}, counter={:?})", fr, renctx.counter); assert!(self.universal_regions.is_universal_region(fr)); - let value = self.give_name_from_error_region(infcx.tcx, mir_def_id, fr, counter) + if let Some(value) = renctx.get(&fr) { + return Some(value.clone()); + } + + let value = self + .give_name_from_error_region(infcx.tcx, *mir_def_id, fr, renctx) .or_else(|| { self.give_name_if_anonymous_region_appears_in_arguments( - infcx, body, mir_def_id, fr, counter, + infcx, body, *mir_def_id, fr, renctx, ) }) .or_else(|| { self.give_name_if_anonymous_region_appears_in_upvars( - infcx.tcx, upvars, fr, counter, + infcx.tcx, upvars, fr, renctx ) }) .or_else(|| { self.give_name_if_anonymous_region_appears_in_output( - infcx, body, mir_def_id, fr, counter, + infcx, body, *mir_def_id, fr, renctx, ) }) .or_else(|| { self.give_name_if_anonymous_region_appears_in_yield_ty( - infcx, body, mir_def_id, fr, counter, + infcx, body, *mir_def_id, fr, renctx, ) }); + if let Some(ref value) = value { + renctx.insert(fr, value.clone()); + } + debug!("give_region_a_name: gave name {:?}", value); value } @@ -197,7 +254,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { tcx: TyCtxt<'tcx>, mir_def_id: DefId, fr: RegionVid, - counter: &mut usize, + renctx: &mut RegionErrorNamingCtx, ) -> Option { let error_region = self.to_error_region(fr)?; @@ -208,7 +265,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let span = self.get_named_span(tcx, error_region, ebr.name); Some(RegionName { name: ebr.name, - source: RegionNameSource::NamedEarlyBoundRegion(span) + source: RegionNameSource::NamedEarlyBoundRegion(span), }) } else { None @@ -227,25 +284,23 @@ impl<'tcx> RegionInferenceContext<'tcx> { name, source: RegionNameSource::NamedFreeRegion(span), }) - }, + } ty::BoundRegion::BrEnv => { - let mir_hir_id = tcx.hir() - .as_local_hir_id(mir_def_id) - .expect("non-local mir"); + let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir"); let def_ty = self.universal_regions.defining_ty; if let DefiningTy::Closure(def_id, substs) = def_ty { let args_span = if let hir::ExprKind::Closure(_, _, _, span, _) = - tcx.hir().expect_expr(mir_hir_id).node + tcx.hir().expect_expr(mir_hir_id).kind { span } else { bug!("Closure is not defined by a closure expr"); }; - let region_name = self.synthesize_region_name(counter); + let region_name = self.synthesize_region_name(renctx); - let closure_kind_ty = substs.closure_kind_ty(def_id, tcx); + let closure_kind_ty = substs.as_closure().kind_ty(def_id, tcx); let note = match closure_kind_ty.to_opt_closure_kind() { Some(ty::ClosureKind::Fn) => { "closure implements `Fn`, so references to captured variables \ @@ -265,7 +320,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { name: region_name, source: RegionNameSource::SynthesizedFreeEnvRegion( args_span, - note.to_string() + note.to_string(), ), }) } else { @@ -335,7 +390,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { body: &Body<'tcx>, mir_def_id: DefId, fr: RegionVid, - counter: &mut usize, + renctx: &mut RegionErrorNamingCtx, ) -> Option { let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs(); let argument_index = self.get_argument_index_for_region(infcx.tcx, fr)?; @@ -344,50 +399,44 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.universal_regions.unnormalized_input_tys[implicit_inputs + argument_index]; if let Some(region_name) = self.give_name_if_we_can_match_hir_ty_from_argument( infcx, - body, mir_def_id, fr, arg_ty, argument_index, - counter, + renctx, ) { return Some(region_name); } - self.give_name_if_we_cannot_match_hir_ty(infcx, body, fr, arg_ty, counter) + self.give_name_if_we_cannot_match_hir_ty(infcx, body, fr, arg_ty, renctx) } fn give_name_if_we_can_match_hir_ty_from_argument( &self, infcx: &InferCtxt<'_, 'tcx>, - body: &Body<'tcx>, mir_def_id: DefId, needle_fr: RegionVid, argument_ty: Ty<'tcx>, argument_index: usize, - counter: &mut usize, + renctx: &mut RegionErrorNamingCtx, ) -> Option { let mir_hir_id = infcx.tcx.hir().as_local_hir_id(mir_def_id)?; let fn_decl = infcx.tcx.hir().fn_decl_by_hir_id(mir_hir_id)?; - let argument_hir_ty: &hir::Ty = &fn_decl.inputs[argument_index]; - match argument_hir_ty.node { + let argument_hir_ty: &hir::Ty = fn_decl.inputs.get(argument_index)?; + match argument_hir_ty.kind { // This indicates a variable with no type annotation, like // `|x|`... in that case, we can't highlight the type but // must highlight the variable. - hir::TyKind::Infer => self.give_name_if_we_cannot_match_hir_ty( - infcx, - body, - needle_fr, - argument_ty, - counter, - ), + // NOTE(eddyb) this is handled in/by the sole caller + // (`give_name_if_anonymous_region_appears_in_arguments`). + hir::TyKind::Infer => None, _ => self.give_name_if_we_can_match_hir_ty( infcx.tcx, needle_fr, argument_ty, argument_hir_ty, - counter, + renctx, ), } } @@ -409,11 +458,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { body: &Body<'tcx>, needle_fr: RegionVid, argument_ty: Ty<'tcx>, - counter: &mut usize, + renctx: &mut RegionErrorNamingCtx, ) -> Option { + let counter = renctx.counter; let mut highlight = RegionHighlightMode::default(); - highlight.highlighting_region_vid(needle_fr, *counter); - let type_name = infcx.extract_type_name(&argument_ty, Some(highlight)); + highlight.highlighting_region_vid(needle_fr, counter); + let type_name = infcx.extract_type_name(&argument_ty, Some(highlight)).0; debug!( "give_name_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", @@ -428,7 +478,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // This counter value will already have been used, so this function will increment // it so the next value will be used next and return the region name that would // have been used. - name: self.synthesize_region_name(counter), + name: self.synthesize_region_name(renctx), source: RegionNameSource::CannotMatchHirTy(span, type_name), }) } else { @@ -455,7 +505,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// type. Once we find that, we can use the span of the `hir::Ty` /// to add the highlight. /// - /// This is a somewhat imperfect process, so long the way we also + /// This is a somewhat imperfect process, so along the way we also /// keep track of the **closest** type we've found. If we fail to /// find the exact `&` or `'_` to highlight, then we may fall back /// to highlighting that closest type instead. @@ -465,13 +515,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { needle_fr: RegionVid, argument_ty: Ty<'tcx>, argument_hir_ty: &hir::Ty, - counter: &mut usize, + renctx: &mut RegionErrorNamingCtx, ) -> Option { let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty)> = &mut vec![(argument_ty, argument_hir_ty)]; while let Some((ty, hir_ty)) = search_stack.pop() { - match (&ty.sty, &hir_ty.node) { + match (&ty.kind, &hir_ty.kind) { // Check if the `argument_ty` is `&'X ..` where `'X` // is the region we are looking for -- if so, and we have a `&T` // on the RHS, then we want to highlight the `&` like so: @@ -483,7 +533,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { hir::TyKind::Rptr(_lifetime, referent_hir_ty), ) => { if region.to_region_vid() == needle_fr { - let region_name = self.synthesize_region_name(counter); + let region_name = self.synthesize_region_name(renctx); // Just grab the first character, the `&`. let source_map = tcx.sess.source_map(); @@ -515,7 +565,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { substs, needle_fr, last_segment, - counter, + renctx, search_stack, ) { return Some(name); @@ -559,18 +609,19 @@ impl<'tcx> RegionInferenceContext<'tcx> { substs: SubstsRef<'tcx>, needle_fr: RegionVid, last_segment: &'hir hir::PathSegment, - counter: &mut usize, + renctx: &mut RegionErrorNamingCtx, search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty)>, ) -> Option { // Did the user give explicit arguments? (e.g., `Foo<..>`) let args = last_segment.args.as_ref()?; - let lifetime = self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?; + let lifetime = + self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?; match lifetime.name { hir::LifetimeName::Param(_) | hir::LifetimeName::Error | hir::LifetimeName::Static | hir::LifetimeName::Underscore => { - let region_name = self.synthesize_region_name(counter); + let region_name = self.synthesize_region_name(renctx); let ampersand_span = lifetime.span; Some(RegionName { name: region_name, @@ -578,7 +629,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) } - hir::LifetimeName::Implicit => { + hir::LifetimeName::ImplicitObjectLifetimeDefault + | hir::LifetimeName::Implicit => { // In this case, the user left off the lifetime; so // they wrote something like: // @@ -609,24 +661,24 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) -> Option<&'hir hir::Lifetime> { for (kind, hir_arg) in substs.iter().zip(&args.args) { match (kind.unpack(), hir_arg) { - (UnpackedKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => { + (GenericArgKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => { if r.to_region_vid() == needle_fr { return Some(lt); } } - (UnpackedKind::Type(ty), hir::GenericArg::Type(hir_ty)) => { + (GenericArgKind::Type(ty), hir::GenericArg::Type(hir_ty)) => { search_stack.push((ty, hir_ty)); } - (UnpackedKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => { + (GenericArgKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => { // Lifetimes cannot be found in consts, so we don't need // to search anything here. } - (UnpackedKind::Lifetime(_), _) - | (UnpackedKind::Type(_), _) - | (UnpackedKind::Const(_), _) => { + (GenericArgKind::Lifetime(_), _) + | (GenericArgKind::Type(_), _) + | (GenericArgKind::Const(_), _) => { // I *think* that HIR lowering should ensure this // doesn't happen, even in erroneous // programs. Else we should use delay-span-bug. @@ -656,12 +708,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { tcx: TyCtxt<'tcx>, upvars: &[Upvar], fr: RegionVid, - counter: &mut usize, + renctx: &mut RegionErrorNamingCtx, ) -> Option { let upvar_index = self.get_upvar_index_for_region(tcx, fr)?; let (upvar_name, upvar_span) = self.get_upvar_name_and_span_for_region(tcx, upvars, upvar_index); - let region_name = self.synthesize_region_name(counter); + let region_name = self.synthesize_region_name(renctx); Some(RegionName { name: region_name, @@ -679,7 +731,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { body: &Body<'tcx>, mir_def_id: DefId, fr: RegionVid, - counter: &mut usize, + renctx: &mut RegionErrorNamingCtx, ) -> Option { let tcx = infcx.tcx; @@ -693,14 +745,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { } let mut highlight = RegionHighlightMode::default(); - highlight.highlighting_region_vid(fr, *counter); - let type_name = infcx.extract_type_name(&return_ty, Some(highlight)); + highlight.highlighting_region_vid(fr, renctx.counter); + let type_name = infcx.extract_type_name(&return_ty, Some(highlight)).0; let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir"); let (return_span, mir_description) = match tcx.hir().get(mir_hir_id) { hir::Node::Expr(hir::Expr { - node: hir::ExprKind::Closure(_, return_ty, _, span, gen_move), + kind: hir::ExprKind::Closure(_, return_ty, _, span, gen_move), .. }) => ( match return_ty.output { @@ -714,7 +766,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { }, ), hir::Node::ImplItem(hir::ImplItem { - node: hir::ImplItemKind::Method(method_sig, _), + kind: hir::ImplItemKind::Method(method_sig, _), .. }) => (method_sig.decl.output.span(), ""), _ => (body.span, ""), @@ -724,11 +776,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { // This counter value will already have been used, so this function will increment it // so the next value will be used next and return the region name that would have been // used. - name: self.synthesize_region_name(counter), + name: self.synthesize_region_name(renctx), source: RegionNameSource::AnonRegionFromOutput( return_span, mir_description.to_string(), - type_name + type_name, ), }) } @@ -739,7 +791,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { body: &Body<'tcx>, mir_def_id: DefId, fr: RegionVid, - counter: &mut usize, + renctx: &mut RegionErrorNamingCtx, ) -> Option { // Note: generators from `async fn` yield `()`, so we don't have to // worry about them here. @@ -756,14 +808,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { } let mut highlight = RegionHighlightMode::default(); - highlight.highlighting_region_vid(fr, *counter); - let type_name = infcx.extract_type_name(&yield_ty, Some(highlight)); + highlight.highlighting_region_vid(fr, renctx.counter); + let type_name = infcx.extract_type_name(&yield_ty, Some(highlight)).0; let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir"); let yield_span = match tcx.hir().get(mir_hir_id) { hir::Node::Expr(hir::Expr { - node: hir::ExprKind::Closure(_, _, _, span, _), + kind: hir::ExprKind::Closure(_, _, _, span, _), .. }) => ( tcx.sess.source_map().end_point(*span) @@ -779,16 +831,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { ); Some(RegionName { - name: self.synthesize_region_name(counter), + name: self.synthesize_region_name(renctx), source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name), }) } - /// Creates a synthetic region named `'1`, incrementing the - /// counter. - fn synthesize_region_name(&self, counter: &mut usize) -> InternedString { - let c = *counter; - *counter += 1; + /// Creates a synthetic region named `'1`, incrementing the counter. + fn synthesize_region_name(&self, renctx: &mut RegionErrorNamingCtx) -> InternedString { + let c = renctx.counter; + renctx.counter += 1; InternedString::intern(&format!("'{:?}", c)) } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs index 750a1324faeb3..7f0e97c9ae426 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs @@ -3,7 +3,7 @@ use crate::borrow_check::nll::ToRegionVid; use crate::borrow_check::Upvar; use rustc::mir::{Local, Body}; use rustc::ty::{RegionVid, TyCtxt}; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use syntax::source_map::Span; use syntax_pos::symbol::Symbol; diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 40388722bcac9..dbb810db555b4 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -1,15 +1,20 @@ -use super::universal_regions::UniversalRegions; -use crate::borrow_check::nll::constraints::graph::NormalConstraintGraph; -use crate::borrow_check::nll::constraints::{ - ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet, -}; -use crate::borrow_check::nll::member_constraints::{MemberConstraintSet, NllMemberConstraintIndex}; -use crate::borrow_check::nll::region_infer::values::{ - PlaceholderIndices, RegionElement, ToElementIndex, +use std::rc::Rc; + +use crate::borrow_check::nll::{ + constraints::{ + graph::NormalConstraintGraph, + ConstraintSccIndex, + OutlivesConstraint, + OutlivesConstraintSet, + }, + member_constraints::{MemberConstraintSet, NllMemberConstraintIndex}, + region_infer::values::{ + PlaceholderIndices, RegionElement, ToElementIndex + }, + type_check::{free_region_relations::UniversalRegionRelations, Locations}, }; -use crate::borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations; -use crate::borrow_check::nll::type_check::Locations; use crate::borrow_check::Upvar; + use rustc::hir::def_id::DefId; use rustc::infer::canonical::QueryOutlivesConstraint; use rustc::infer::opaque_types; @@ -22,25 +27,25 @@ use rustc::mir::{ use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc::util::common::ErrorReported; use rustc_data_structures::binary_search_util; -use rustc_data_structures::bit_set::BitSet; +use rustc_index::bit_set::BitSet; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::WithSuccessors; use rustc_data_structures::graph::scc::Sccs; use rustc_data_structures::graph::vec_graph::VecGraph; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::vec::IndexVec; use rustc_errors::{Diagnostic, DiagnosticBuilder}; use syntax_pos::Span; -use std::rc::Rc; +crate use self::error_reporting::{RegionName, RegionNameSource, RegionErrorNamingCtx}; +use self::values::{LivenessValues, RegionValueElements, RegionValues}; +use super::universal_regions::UniversalRegions; +use super::ToRegionVid; mod dump_mir; mod error_reporting; -crate use self::error_reporting::{RegionName, RegionNameSource}; mod graphviz; -pub mod values; -use self::values::{LivenessValues, RegionValueElements, RegionValues}; -use super::ToRegionVid; +pub mod values; pub struct RegionInferenceContext<'tcx> { /// Contains the definition for every region variable. Region @@ -401,7 +406,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - NLLRegionVariableOrigin::Existential => { + NLLRegionVariableOrigin::Existential { .. } => { // For existential, regions, nothing to do. } } @@ -487,6 +492,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { errors_buffer, ); + // If we produce any errors, we keep track of the names of all regions, so that we can use + // the same error names in any suggestions we produce. Note that we need names to be unique + // across different errors for the same MIR def so that we can make suggestions that fix + // multiple problems. + let mut region_naming = RegionErrorNamingCtx::new(); + self.check_universal_regions( infcx, body, @@ -494,6 +505,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { mir_def_id, outlives_requirements.as_mut(), errors_buffer, + &mut region_naming, ); self.check_member_constraints(infcx, mir_def_id, errors_buffer); @@ -1312,6 +1324,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { mir_def_id: DefId, mut propagated_outlives_requirements: Option<&mut Vec>>, errors_buffer: &mut Vec, + region_naming: &mut RegionErrorNamingCtx, ) { for (fr, fr_definition) in self.definitions.iter_enumerated() { match fr_definition.origin { @@ -1327,6 +1340,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fr, &mut propagated_outlives_requirements, errors_buffer, + region_naming, ); } @@ -1334,7 +1348,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_bound_universal_region(infcx, body, mir_def_id, fr, placeholder); } - NLLRegionVariableOrigin::Existential => { + NLLRegionVariableOrigin::Existential { .. } => { // nothing to check here } } @@ -1358,6 +1372,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { longer_fr: RegionVid, propagated_outlives_requirements: &mut Option<&mut Vec>>, errors_buffer: &mut Vec, + region_naming: &mut RegionErrorNamingCtx, ) { debug!("check_universal_region(fr={:?})", longer_fr); @@ -1385,6 +1400,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { mir_def_id, propagated_outlives_requirements, errors_buffer, + region_naming, ); return; } @@ -1401,8 +1417,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { mir_def_id, propagated_outlives_requirements, errors_buffer, + region_naming, ) { // continuing to iterate just reports more errors than necessary + // + // FIXME It would also allow us to report more Outlives Suggestions, though, so + // it's not clear that that's a bad thing. Somebody should try commenting out this + // line and see it is actually a regression. return; } } @@ -1418,6 +1439,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { mir_def_id: DefId, propagated_outlives_requirements: &mut Option<&mut Vec>>, errors_buffer: &mut Vec, + region_naming: &mut RegionErrorNamingCtx, ) -> Option { // If it is known that `fr: o`, carry on. if self.universal_region_relations.outlives(longer_fr, shorter_fr) { @@ -1439,7 +1461,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!("check_universal_region: fr_minus={:?}", fr_minus); let blame_span_category = - self.find_outlives_blame_span(body, longer_fr, shorter_fr); + self.find_outlives_blame_span(body, longer_fr, + NLLRegionVariableOrigin::FreeRegion,shorter_fr); // Grow `shorter_fr` until we find some non-local regions. (We // always will.) We'll call them `shorter_fr+` -- they're ever @@ -1466,7 +1489,19 @@ impl<'tcx> RegionInferenceContext<'tcx> { // // Note: in this case, we use the unapproximated regions to report the // error. This gives better error messages in some cases. - self.report_error(body, upvars, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer); + let db = self.report_error( + body, + upvars, + infcx, + mir_def_id, + longer_fr, + NLLRegionVariableOrigin::FreeRegion, + shorter_fr, + region_naming, + ); + + db.buffer(errors_buffer); + Some(ErrorReported) } @@ -1514,7 +1549,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { }; // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. - let (_, span) = self.find_outlives_blame_span(body, longer_fr, error_region); + let (_, span) = self.find_outlives_blame_span( + body, longer_fr, NLLRegionVariableOrigin::Placeholder(placeholder), error_region + ); // Obviously, this error message is far from satisfactory. // At present, though, it only appears in unit tests -- @@ -1575,7 +1612,7 @@ impl<'tcx> RegionDefinition<'tcx> { let origin = match rv_origin { RegionVariableOrigin::NLL(origin) => origin, - _ => NLLRegionVariableOrigin::Existential, + _ => NLLRegionVariableOrigin::Existential { from_forall: false }, }; Self { origin, universe, external_name: None } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index 6f9f5707935ba..6acbff76bdc90 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -1,9 +1,9 @@ use rustc::mir::{BasicBlock, Location, Body}; use rustc::ty::{self, RegionVid}; -use rustc_data_structures::bit_set::{HybridBitSet, SparseBitMatrix}; +use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::indexed_vec::Idx; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::vec::Idx; +use rustc_index::vec::IndexVec; use std::fmt::Debug; use std::rc::Rc; @@ -116,13 +116,13 @@ impl RegionValueElements { } } -newtype_index! { +rustc_index::newtype_index! { /// A single integer representing a `Location` in the MIR control-flow /// graph. Constructed efficiently from `RegionValueElements`. pub struct PointIndex { DEBUG_FORMAT = "PointIndex({})" } } -newtype_index! { +rustc_index::newtype_index! { /// A single integer representing a `ty::Placeholder`. pub struct PlaceholderIndex { DEBUG_FORMAT = "PlaceholderIndex({})" } } diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index c1d1185cf177a..88ad1fb129509 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -1,16 +1,26 @@ use rustc::ty::subst::SubstsRef; -use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable}; -use rustc::mir::{Location, Body}; +use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::mir::{Location, Body, Promoted}; use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; +use rustc_index::vec::IndexVec; /// Replaces all free regions appearing in the MIR with fresh /// inference variables, returning the number of variables created. -pub fn renumber_mir<'tcx>(infcx: &InferCtxt<'_, 'tcx>, body: &mut Body<'tcx>) { +pub fn renumber_mir<'tcx>( + infcx: &InferCtxt<'_, 'tcx>, + body: &mut Body<'tcx>, + promoted: &mut IndexVec>, +) { debug!("renumber_mir()"); debug!("renumber_mir: body.arg_count={:?}", body.arg_count); let mut visitor = NLLVisitor { infcx }; + + for body in promoted.iter_mut() { + visitor.visit_body(body); + } + visitor.visit_body(body); } @@ -25,7 +35,7 @@ where infcx .tcx .fold_regions(value, &mut false, |_region, _depth| { - let origin = NLLRegionVariableOrigin::Existential; + let origin = NLLRegionVariableOrigin::Existential { from_forall: false }; infcx.next_nll_region_var(origin) }) } @@ -44,14 +54,6 @@ impl<'a, 'tcx> NLLVisitor<'a, 'tcx> { } impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { - fn visit_body(&mut self, body: &mut Body<'tcx>) { - for promoted in body.promoted.iter_mut() { - self.visit_body(promoted); - } - - self.super_body(body); - } - fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) { debug!("visit_ty(ty={:?}, ty_context={:?})", ty, ty_context); @@ -80,30 +82,4 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _location: Location) { *constant = self.renumber_regions(&*constant); } - - fn visit_generator_substs(&mut self, - substs: &mut GeneratorSubsts<'tcx>, - location: Location) { - debug!( - "visit_generator_substs(substs={:?}, location={:?})", - substs, - location, - ); - - *substs = self.renumber_regions(substs); - - debug!("visit_generator_substs: substs={:?}", substs); - } - - fn visit_closure_substs(&mut self, substs: &mut ClosureSubsts<'tcx>, location: Location) { - debug!( - "visit_closure_substs(substs={:?}, location={:?})", - substs, - location - ); - - *substs = self.renumber_regions(substs); - - debug!("visit_closure_substs: substs={:?}", substs); - } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs index 8de014522dea7..c88f1cac35040 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs @@ -10,7 +10,7 @@ use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; use rustc::infer::region_constraints::{GenericKind, VerifyBound}; use rustc::infer::{self, InferCtxt, SubregionOrigin}; use rustc::mir::ConstraintCategory; -use rustc::ty::subst::UnpackedKind; +use rustc::ty::subst::GenericArgKind; use rustc::ty::{self, TyCtxt}; use syntax_pos::DUMMY_SP; @@ -101,13 +101,13 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { }); match k1.unpack() { - UnpackedKind::Lifetime(r1) => { + GenericArgKind::Lifetime(r1) => { let r1_vid = self.to_region_vid(r1); let r2_vid = self.to_region_vid(r2); self.add_outlives(r1_vid, r2_vid); } - UnpackedKind::Type(t1) => { + GenericArgKind::Type(t1) => { // we don't actually use this for anything, but // the `TypeOutlives` code needs an origin. let origin = infer::RelateParamBound(DUMMY_SP, t1); @@ -121,7 +121,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { ).type_must_outlive(origin, t1, r2); } - UnpackedKind::Const(_) => { + GenericArgKind::Const(_) => { // Consts cannot outlive one another, so we // don't need to handle any relations here. } diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs index 99661b1f7370a..d74dd0fc0f5f1 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs @@ -12,7 +12,7 @@ use rustc::infer::LateBoundRegionConversionTime; use rustc::mir::*; use rustc::ty::Ty; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use syntax_pos::Span; use super::{Locations, TypeChecker}; diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs index 2a066538cc234..7dee00b3eca67 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs @@ -1,8 +1,8 @@ use crate::borrow_check::nll::region_infer::values::{PointIndex, RegionValueElements}; use crate::util::liveness::{categorize, DefUse}; use rustc::mir::visit::{PlaceContext, Visitor}; -use rustc::mir::{Local, Location, Body}; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc::mir::{Body, Local, Location}; +use rustc_index::vec::{Idx, IndexVec}; use rustc_data_structures::vec_linked_list as vll; /// A map that cross references each local with the locations where it @@ -44,7 +44,7 @@ struct Appearance { next: Option, } -newtype_index! { +rustc_index::newtype_index! { pub struct AppearanceIndex { .. } } @@ -70,18 +70,16 @@ impl LocalUseMap { appearances: IndexVec::new(), }; + if live_locals.is_empty() { + return local_use_map; + } + let mut locals_with_use_data: IndexVec = IndexVec::from_elem_n(false, body.local_decls.len()); - live_locals - .iter() - .for_each(|&local| locals_with_use_data[local] = true); - - LocalUseMapBuild { - local_use_map: &mut local_use_map, - elements, - locals_with_use_data, - } - .visit_body(body); + live_locals.iter().for_each(|&local| locals_with_use_data[local] = true); + + LocalUseMapBuild { local_use_map: &mut local_use_map, elements, locals_with_use_data } + .visit_body(body); local_use_map } @@ -151,10 +149,8 @@ impl LocalUseMapBuild<'_> { location: Location, ) { let point_index = elements.point_from_location(location); - let appearance_index = appearances.push(Appearance { - point_index, - next: *first_appearance, - }); + let appearance_index = + appearances.push(Appearance { point_index, next: *first_appearance }); *first_appearance = Some(appearance_index); } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs index 8970009b6ee9f..a01b528833b2d 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs @@ -36,31 +36,39 @@ pub(super) fn generate<'tcx>( ) { debug!("liveness::generate"); - let live_locals: Vec = if AllFacts::enabled(typeck.tcx()) { - // If "dump facts from NLL analysis" was requested perform - // the liveness analysis for all `Local`s. This case opens - // the possibility of the variables being analyzed in `trace` - // to be *any* `Local`, not just the "live" ones, so we can't - // make any assumptions past this point as to the characteristics - // of the `live_locals`. - // FIXME: Review "live" terminology past this point, we should - // not be naming the `Local`s as live. - body.local_decls.indices().collect() + let free_regions = regions_that_outlive_free_regions( + typeck.infcx.num_region_vars(), + &typeck.borrowck_context.universal_regions, + &typeck.borrowck_context.constraints.outlives_constraints, + ); + let live_locals = compute_live_locals(typeck.tcx(), &free_regions, body); + let facts_enabled = AllFacts::enabled(typeck.tcx()); + + + let polonius_drop_used = if facts_enabled { + let mut drop_used = Vec::new(); + polonius::populate_access_facts( + typeck, + body, + location_table, + move_data, + &mut drop_used, + ); + Some(drop_used) } else { - let free_regions = { - regions_that_outlive_free_regions( - typeck.infcx.num_region_vars(), - &typeck.borrowck_context.universal_regions, - &typeck.borrowck_context.constraints.outlives_constraints, - ) - }; - compute_live_locals(typeck.tcx(), &free_regions, body) + None }; - if !live_locals.is_empty() { - trace::trace(typeck, body, elements, flow_inits, move_data, live_locals, location_table); - - polonius::populate_var_liveness_facts(typeck, body, location_table); + if !live_locals.is_empty() || facts_enabled { + trace::trace( + typeck, + body, + elements, + flow_inits, + move_data, + live_locals, + polonius_drop_used, + ); } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs index 20d7ec55e3e84..526ad7fb905bb 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs @@ -1,22 +1,28 @@ use crate::borrow_check::location::{LocationIndex, LocationTable}; +use crate::dataflow::indexes::MovePathIndex; +use crate::dataflow::move_paths::{LookupResult, MoveData}; use crate::util::liveness::{categorize, DefUse}; -use rustc::mir::visit::{PlaceContext, Visitor}; -use rustc::mir::{Body, Local, Location}; -use rustc::ty::subst::Kind; +use rustc::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; +use rustc::mir::{Body, Local, Location, Place}; +use rustc::ty::subst::GenericArg; use rustc::ty::Ty; use super::TypeChecker; type VarPointRelations = Vec<(Local, LocationIndex)>; +type MovePathPointRelations = Vec<(MovePathIndex, LocationIndex)>; -struct LivenessPointFactsExtractor<'me> { +struct UseFactsExtractor<'me> { var_defined: &'me mut VarPointRelations, var_used: &'me mut VarPointRelations, location_table: &'me LocationTable, + var_drop_used: &'me mut Vec<(Local, Location)>, + move_data: &'me MoveData<'me>, + path_accessed_at: &'me mut MovePathPointRelations, } // A Visitor to walk through the MIR and extract point-wise facts -impl LivenessPointFactsExtractor<'_> { +impl UseFactsExtractor<'_> { fn location_to_index(&self, location: Location) -> LocationIndex { self.location_table.mid_index(location) } @@ -30,15 +36,50 @@ impl LivenessPointFactsExtractor<'_> { debug!("LivenessFactsExtractor::insert_use()"); self.var_used.push((local, self.location_to_index(location))); } + + fn insert_drop_use(&mut self, local: Local, location: Location) { + debug!("LivenessFactsExtractor::insert_drop_use()"); + self.var_drop_used.push((local, location)); + } + + fn insert_path_access(&mut self, path: MovePathIndex, location: Location) { + debug!("LivenessFactsExtractor::insert_path_access({:?}, {:?})", path, location); + self.path_accessed_at.push((path, self.location_to_index(location))); + } + + fn place_to_mpi(&self, place: &Place<'_>) -> Option { + match self.move_data.rev_lookup.find(place.as_ref()) { + LookupResult::Exact(mpi) => Some(mpi), + LookupResult::Parent(mmpi) => mmpi, + } + } } -impl Visitor<'tcx> for LivenessPointFactsExtractor<'_> { +impl Visitor<'tcx> for UseFactsExtractor<'_> { fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) { match categorize(context) { Some(DefUse::Def) => self.insert_def(local, location), Some(DefUse::Use) => self.insert_use(local, location), + Some(DefUse::Drop) => self.insert_drop_use(local, location), + _ => (), + } + } + + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { + self.super_place(place, context, location); + match context { + PlaceContext::NonMutatingUse(_) => { + if let Some(mpi) = self.place_to_mpi(place) { + self.insert_path_access(mpi, location); + } + } + + PlaceContext::MutatingUse(MutatingUseContext::Borrow) => { + if let Some(mpi) = self.place_to_mpi(place) { + self.insert_path_access(mpi, location); + } + } _ => (), - // NOTE: Drop handling is now done in trace() } } } @@ -54,23 +95,32 @@ fn add_var_uses_regions(typeck: &mut TypeChecker<'_, 'tcx>, local: Local, ty: Ty }); } -pub(super) fn populate_var_liveness_facts( +pub(super) fn populate_access_facts( typeck: &mut TypeChecker<'_, 'tcx>, - mir: &Body<'tcx>, + body: &Body<'tcx>, location_table: &LocationTable, + move_data: &MoveData<'_>, + drop_used: &mut Vec<(Local, Location)>, ) { debug!("populate_var_liveness_facts()"); if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() { - LivenessPointFactsExtractor { + UseFactsExtractor { var_defined: &mut facts.var_defined, var_used: &mut facts.var_used, + var_drop_used: drop_used, + path_accessed_at: &mut facts.path_accessed_at, location_table, + move_data, } - .visit_body(mir); + .visit_body(body); + + facts.var_drop_used.extend(drop_used.iter().map(|&(local, location)| { + (local, location_table.mid_index(location)) + })); } - for (local, local_decl) in mir.local_decls.iter_enumerated() { + for (local, local_decl) in body.local_decls.iter_enumerated() { add_var_uses_regions(typeck, local, local_decl.ty); } } @@ -80,7 +130,7 @@ pub(super) fn populate_var_liveness_facts( pub(super) fn add_var_drops_regions( typeck: &mut TypeChecker<'_, 'tcx>, local: Local, - kind: &Kind<'tcx>, + kind: &GenericArg<'tcx>, ) { debug!("add_var_drops_region(local={:?}, kind={:?}", local, kind); let tcx = typeck.tcx(); diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs index 039ed939ada7c..eacc4d084dbb8 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs @@ -1,4 +1,3 @@ -use crate::borrow_check::location::LocationTable; use crate::borrow_check::nll::region_infer::values::{self, PointIndex, RegionValueElements}; use crate::borrow_check::nll::type_check::liveness::local_use_map::LocalUseMap; use crate::borrow_check::nll::type_check::liveness::polonius; @@ -13,8 +12,8 @@ use rustc::traits::query::dropck_outlives::DropckOutlivesResult; use rustc::traits::query::type_op::outlives::DropckOutlives; use rustc::traits::query::type_op::TypeOp; use rustc::ty::{Ty, TypeFoldable}; -use rustc_data_structures::bit_set::HybridBitSet; -use rustc_data_structures::fx::FxHashMap; +use rustc_index::bit_set::HybridBitSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use std::rc::Rc; /// This is the heart of the liveness computation. For each variable X @@ -38,7 +37,7 @@ pub(super) fn trace( flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'tcx>>, move_data: &MoveData<'tcx>, live_locals: Vec, - location_table: &LocationTable, + polonius_drop_used: Option>, ) { debug!("trace()"); @@ -52,10 +51,15 @@ pub(super) fn trace( local_use_map, move_data, drop_data: FxHashMap::default(), - location_table, }; - LivenessResults::new(cx).compute_for_all_locals(live_locals); + let mut results = LivenessResults::new(cx); + + if let Some(drop_used) = polonius_drop_used { + results.add_extra_drop_facts(drop_used, live_locals.iter().copied().collect()) + } + + results.compute_for_all_locals(live_locals); } /// Contextual state for the type-liveness generator. @@ -82,9 +86,6 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> { /// Index indicating where each variable is assigned, used, or /// dropped. local_use_map: &'me LocalUseMap, - - /// Maps between a MIR Location and a LocationIndex - location_table: &'me LocationTable, } struct DropData<'tcx> { @@ -131,12 +132,6 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> { for local in live_locals { self.reset_local_state(); self.add_defs_for(local); - - // FIXME: this is temporary until we can generate our own initialization - if self.cx.typeck.borrowck_context.all_facts.is_some() { - self.add_polonius_var_initialized_on_exit_for(local) - } - self.compute_use_live_points_for(local); self.compute_drop_live_points_for(local); @@ -157,60 +152,29 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> { } } - // WARNING: panics if self.cx.typeck.borrowck_context.all_facts != None - // - // FIXME: this analysis (the initialization tracking) should be - // done in Polonius, but isn't yet. - fn add_polonius_var_initialized_on_exit_for(&mut self, local: Local) { - let move_path = self.cx.move_data.rev_lookup.find_local(local); - let facts = self.cx.typeck.borrowck_context.all_facts.as_mut().unwrap(); - for block in self.cx.body.basic_blocks().indices() { - debug!("polonius: generating initialization facts for {:?} in {:?}", local, block); - - // iterate through the block, applying the effects of each statement - // up to and including location, and populate `var_initialized_on_exit` - self.cx.flow_inits.reset_to_entry_of(block); - let start_location = Location { block, statement_index: 0 }; - self.cx.flow_inits.apply_local_effect(start_location); - - for statement_index in 0..self.cx.body[block].statements.len() { - let current_location = Location { block, statement_index }; - - self.cx.flow_inits.reconstruct_statement_effect(current_location); - - // statement has not yet taken effect: - if self.cx.flow_inits.has_any_child_of(move_path).is_some() { - facts - .var_initialized_on_exit - .push((local, self.cx.location_table.start_index(current_location))); - } - - // statement has now taken effect - self.cx.flow_inits.apply_local_effect(current_location); - - if self.cx.flow_inits.has_any_child_of(move_path).is_some() { - facts - .var_initialized_on_exit - .push((local, self.cx.location_table.mid_index(current_location))); + /// Add extra drop facts needed for Polonius. + /// + /// Add facts for all locals with free regions, since regions may outlive + /// the function body only at certain nodes in the CFG. + fn add_extra_drop_facts( + &mut self, + drop_used: Vec<(Local, Location)>, + live_locals: FxHashSet, + ) { + let locations = HybridBitSet::new_empty(self.cx.elements.num_points()); + + for (local, location) in drop_used { + if !live_locals.contains(&local) { + let local_ty = self.cx.body.local_decls[local].ty; + if local_ty.has_free_regions() { + self.cx.add_drop_live_facts_for( + local, + local_ty, + &[location], + &locations, + ); } } - - let terminator_location = self.cx.body.terminator_loc(block); - - if self.cx.flow_inits.has_any_child_of(move_path).is_some() { - facts - .var_initialized_on_exit - .push((local, self.cx.location_table.start_index(terminator_location))); - } - - // apply the effects of the terminator and push it if needed - self.cx.flow_inits.reset_to_exit_of(block); - - if self.cx.flow_inits.has_any_child_of(move_path).is_some() { - facts - .var_initialized_on_exit - .push((local, self.cx.location_table.mid_index(terminator_location))); - } } } @@ -273,11 +237,6 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> { debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,); if self.cx.initialized_at_terminator(location.block, mpi) { - // FIXME: this analysis (the initialization tracking) should be - // done in Polonius, but isn't yet. - if let Some(facts) = self.cx.typeck.borrowck_context.all_facts { - facts.var_drop_used.push((local, self.cx.location_table.mid_index(location))); - } if self.drop_live_at.insert(drop_point) { self.drop_locations.push(location); self.stack.push(drop_point); @@ -468,13 +427,7 @@ impl LivenessContext<'_, '_, '_, 'tcx> { ) { debug!("add_use_live_facts_for(value={:?})", value); - Self::make_all_regions_live( - self.elements, - &mut self.typeck, - value, - live_at, - self.location_table, - ) + Self::make_all_regions_live(self.elements, &mut self.typeck, value, live_at) } /// Some variable with type `live_ty` is "drop live" at `location` @@ -525,13 +478,7 @@ impl LivenessContext<'_, '_, '_, 'tcx> { // All things in the `outlives` array may be touched by // the destructor and must be live at this point. for &kind in &drop_data.dropck_result.kinds { - Self::make_all_regions_live( - self.elements, - &mut self.typeck, - kind, - live_at, - self.location_table, - ); + Self::make_all_regions_live(self.elements, &mut self.typeck, kind, live_at); polonius::add_var_drops_regions(&mut self.typeck, dropped_local, &kind); } @@ -542,7 +489,6 @@ impl LivenessContext<'_, '_, '_, 'tcx> { typeck: &mut TypeChecker<'_, 'tcx>, value: impl TypeFoldable<'tcx>, live_at: &HybridBitSet, - location_table: &LocationTable, ) { debug!("make_all_regions_live(value={:?})", value); debug!( @@ -559,15 +505,6 @@ impl LivenessContext<'_, '_, '_, 'tcx> { .constraints .liveness_constraints .add_elements(live_region_vid, live_at); - - // FIXME: remove this when we can generate our own region-live-at reliably - if let Some(facts) = typeck.borrowck_context.all_facts { - for point in live_at.iter() { - let loc = elements.to_location(point); - facts.region_live_at.push((live_region_vid, location_table.start_index(loc))); - facts.region_live_at.push((live_region_vid, location_table.mid_index(loc))); - } - } }); } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 70d6c15d8e2a7..ed639e8eee774 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -36,14 +36,14 @@ use rustc::traits::query::{Fallible, NoSolution}; use rustc::traits::{self, ObligationCause, PredicateObligations}; use rustc::ty::adjustment::{PointerCast}; use rustc::ty::fold::TypeFoldable; -use rustc::ty::subst::{Subst, SubstsRef, UnpackedKind, UserSubsts}; +use rustc::ty::subst::{Subst, SubstsRef, GenericArgKind, UserSubsts}; use rustc::ty::{ self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, UserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, UserTypeAnnotationIndex, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use rustc_index::vec::{IndexVec, Idx}; use rustc::ty::layout::VariantIdx; use std::rc::Rc; use std::{fmt, iter, mem}; @@ -112,6 +112,7 @@ pub(crate) fn type_check<'tcx>( infcx: &InferCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, + promoted: &IndexVec>, mir_def_id: DefId, universal_regions: &Rc>, location_table: &LocationTable, @@ -157,6 +158,7 @@ pub(crate) fn type_check<'tcx>( mir_def_id, param_env, body, + promoted, ®ion_bound_pairs, implicit_region_bound, &mut borrowck_context, @@ -180,6 +182,7 @@ fn type_check_internal<'a, 'tcx, R>( mir_def_id: DefId, param_env: ty::ParamEnv<'tcx>, body: &'a Body<'tcx>, + promoted: &'a IndexVec>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: ty::Region<'tcx>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, @@ -197,7 +200,7 @@ fn type_check_internal<'a, 'tcx, R>( universal_region_relations, ); let errors_reported = { - let mut verifier = TypeVerifier::new(&mut checker, body); + let mut verifier = TypeVerifier::new(&mut checker, body, promoted); verifier.visit_body(body); verifier.errors_reported }; @@ -254,6 +257,7 @@ enum FieldAccessError { struct TypeVerifier<'a, 'b, 'tcx> { cx: &'a mut TypeChecker<'b, 'tcx>, body: &'b Body<'tcx>, + promoted: &'b IndexVec>, last_span: Span, mir_def_id: DefId, errors_reported: bool, @@ -272,12 +276,21 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); - self.sanitize_constant(constant, location); - self.sanitize_type(constant, constant.ty); + let ty = self.sanitize_type(constant, constant.literal.ty); + + self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| { + let live_region_vid = + self.cx.borrowck_context.universal_regions.to_region_vid(live_region); + self.cx + .borrowck_context + .constraints + .liveness_constraints + .add_element(live_region_vid, location); + }); if let Some(annotation_index) = constant.user_ty { if let Err(terr) = self.cx.relate_type_and_user_type( - constant.ty, + constant.literal.ty, ty::Variance::Invariant, &UserTypeProjection { base: annotation_index, projs: vec![], }, location.to_locations(), @@ -289,7 +302,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { constant, "bad constant user type {:?} vs {:?}: {:?}", annotation, - constant.ty, + constant.literal.ty, terr, ); } @@ -299,7 +312,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { location.to_locations(), ConstraintCategory::Boring, self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( - constant.ty, def_id, UserSubsts { substs, user_self_ty: None }, + constant.literal.ty, def_id, UserSubsts { substs, user_self_ty: None }, )), ) { span_mirbug!( @@ -311,7 +324,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { ); } } - if let ty::FnDef(def_id, substs) = constant.literal.ty.sty { + if let ty::FnDef(def_id, substs) = constant.literal.ty.kind { let tcx = self.tcx(); let instantiated_predicates = tcx @@ -339,7 +352,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { let ty = if !local_decl.is_nonref_binding() { // If we have a binding of the form `let ref x: T = ..` then remove the outermost // reference so we can check the type annotation for the remaining type. - if let ty::Ref(_, rty, _) = local_decl.ty.sty { + if let ty::Ref(_, rty, _) = local_decl.ty.kind { rty } else { bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty); @@ -381,9 +394,14 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { - fn new(cx: &'a mut TypeChecker<'b, 'tcx>, body: &'b Body<'tcx>) -> Self { + fn new( + cx: &'a mut TypeChecker<'b, 'tcx>, + body: &'b Body<'tcx>, + promoted: &'b IndexVec>, + ) -> Self { TypeVerifier { body, + promoted, mir_def_id: cx.mir_def_id, cx, last_span: body.span, @@ -403,41 +421,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } } - /// Checks that the constant's `ty` field matches up with what would be - /// expected from its literal. Unevaluated constants and well-formed - /// constraints are checked by `visit_constant`. - fn sanitize_constant(&mut self, constant: &Constant<'tcx>, location: Location) { - debug!( - "sanitize_constant(constant={:?}, location={:?})", - constant, location - ); - - let literal = constant.literal; - - if let ConstValue::Unevaluated(..) = literal.val { - return; - } - - debug!("sanitize_constant: expected_ty={:?}", literal.ty); - - if let Err(terr) = self.cx.eq_types( - literal.ty, - constant.ty, - location.to_locations(), - ConstraintCategory::Boring, - ) { - span_mirbug!( - self, - constant, - "constant {:?} should have type {:?} but has {:?} ({:?})", - constant, - literal.ty, - constant.ty, - terr, - ); - } - } - /// Checks that the types internal to the `place` match up with /// what would be expected. fn sanitize_place( @@ -448,107 +431,104 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { ) -> PlaceTy<'tcx> { debug!("sanitize_place: {:?}", place); - place.iterate(|place_base, place_projection| { - let mut place_ty = match place_base { - PlaceBase::Local(index) => - PlaceTy::from_ty(self.body.local_decls[*index].ty), - PlaceBase::Static(box Static { kind, ty: sty }) => { - let sty = self.sanitize_type(place, sty); - let check_err = - |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, - place: &Place<'tcx>, - ty, - sty| { - if let Err(terr) = verifier.cx.eq_types( - sty, - ty, - location.to_locations(), - ConstraintCategory::Boring, - ) { - span_mirbug!( - verifier, - place, - "bad promoted type ({:?}: {:?}): {:?}", - ty, - sty, - terr - ); - }; + let mut place_ty = match &place.base { + PlaceBase::Local(index) => + PlaceTy::from_ty(self.body.local_decls[*index].ty), + PlaceBase::Static(box Static { kind, ty, def_id }) => { + let san_ty = self.sanitize_type(place, ty); + let check_err = + |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, + place: &Place<'tcx>, + ty, + san_ty| { + if let Err(terr) = verifier.cx.eq_types( + san_ty, + ty, + location.to_locations(), + ConstraintCategory::Boring, + ) { + span_mirbug!( + verifier, + place, + "bad promoted type ({:?}: {:?}): {:?}", + ty, + san_ty, + terr + ); }; - match kind { - StaticKind::Promoted(promoted) => { - if !self.errors_reported { - let promoted_body = &self.body.promoted[*promoted]; - self.sanitize_promoted(promoted_body, location); - - let promoted_ty = promoted_body.return_ty(); - check_err(self, place, promoted_ty, sty); - } + }; + match kind { + StaticKind::Promoted(promoted, _) => { + if !self.errors_reported { + let promoted_body = &self.promoted[*promoted]; + self.sanitize_promoted(promoted_body, location); + + let promoted_ty = promoted_body.return_ty(); + check_err(self, place, promoted_ty, san_ty); } - StaticKind::Static(def_id) => { - let ty = self.tcx().type_of(*def_id); - let ty = self.cx.normalize(ty, location); + } + StaticKind::Static => { + let ty = self.tcx().type_of(*def_id); + let ty = self.cx.normalize(ty, location); - check_err(self, place, ty, sty); - } + check_err(self, place, ty, san_ty); } - PlaceTy::from_ty(sty) } - }; + PlaceTy::from_ty(san_ty) + } + }; - // FIXME use place_projection.is_empty() when is available - if place.projection.is_none() { - if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { - let is_promoted = match place { - Place { - base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(_), - .. - }), - projection: None, - } => true, - _ => false, - }; + if place.projection.is_empty() { + if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { + let is_promoted = match place { + Place { + base: PlaceBase::Static(box Static { + kind: StaticKind::Promoted(..), + .. + }), + projection: box [], + } => true, + _ => false, + }; - if !is_promoted { - let tcx = self.tcx(); - let trait_ref = ty::TraitRef { - def_id: tcx.lang_items().copy_trait().unwrap(), - substs: tcx.mk_substs_trait(place_ty.ty, &[]), - }; + if !is_promoted { + let tcx = self.tcx(); + let trait_ref = ty::TraitRef { + def_id: tcx.lang_items().copy_trait().unwrap(), + substs: tcx.mk_substs_trait(place_ty.ty, &[]), + }; - // In order to have a Copy operand, the type T of the - // value must be Copy. Note that we prove that T: Copy, - // rather than using the `is_copy_modulo_regions` - // test. This is important because - // `is_copy_modulo_regions` ignores the resulting region - // obligations and assumes they pass. This can result in - // bounds from Copy impls being unsoundly ignored (e.g., - // #29149). Note that we decide to use Copy before knowing - // whether the bounds fully apply: in effect, the rule is - // that if a value of some type could implement Copy, then - // it must. - self.cx.prove_trait_ref( - trait_ref, - location.to_locations(), - ConstraintCategory::CopyBound, - ); - } + // To have a `Copy` operand, the type `T` of the + // value must be `Copy`. Note that we prove that `T: Copy`, + // rather than using the `is_copy_modulo_regions` + // test. This is important because + // `is_copy_modulo_regions` ignores the resulting region + // obligations and assumes they pass. This can result in + // bounds from `Copy` impls being unsoundly ignored (e.g., + // #29149). Note that we decide to use `Copy` before knowing + // whether the bounds fully apply: in effect, the rule is + // that if a value of some type could implement `Copy`, then + // it must. + self.cx.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::CopyBound, + ); } } + } - for proj in place_projection { - if place_ty.variant_index.is_none() { - if place_ty.ty.references_error() { - assert!(self.errors_reported); - return PlaceTy::from_ty(self.tcx().types.err); - } + for elem in place.projection.iter() { + if place_ty.variant_index.is_none() { + if place_ty.ty.references_error() { + assert!(self.errors_reported); + return PlaceTy::from_ty(self.tcx().types.err); } - place_ty = self.sanitize_projection(place_ty, &proj.elem, place, location) } + place_ty = self.sanitize_projection(place_ty, elem, place, location) + } - place_ty - }) + place_ty } fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Location) { @@ -558,25 +538,37 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { let parent_body = mem::replace(&mut self.body, promoted_body); + // Use new sets of constraints and closure bounds so that we can + // modify their locations. let all_facts = &mut None; let mut constraints = Default::default(); let mut closure_bounds = Default::default(); + let mut liveness_constraints = LivenessValues::new( + Rc::new(RegionValueElements::new(promoted_body)), + ); // Don't try to add borrow_region facts for the promoted MIR - mem::swap(self.cx.borrowck_context.all_facts, all_facts); - // Use a new sets of constraints and closure bounds so that we can - // modify their locations. - mem::swap( - &mut self.cx.borrowck_context.constraints.outlives_constraints, - &mut constraints - ); - mem::swap( - &mut self.cx.borrowck_context.constraints.closure_bounds_mapping, - &mut closure_bounds - ); + let mut swap_constraints = |this: &mut Self| { + mem::swap(this.cx.borrowck_context.all_facts, all_facts); + mem::swap( + &mut this.cx.borrowck_context.constraints.outlives_constraints, + &mut constraints + ); + mem::swap( + &mut this.cx.borrowck_context.constraints.closure_bounds_mapping, + &mut closure_bounds + ); + mem::swap( + &mut this.cx.borrowck_context.constraints.liveness_constraints, + &mut liveness_constraints + ); + }; + + swap_constraints(self); self.visit_body(promoted_body); + if !self.errors_reported { // if verifier failed, don't do further checks to avoid ICEs self.cx.typeck_mir(promoted_body); @@ -584,23 +576,15 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { self.body = parent_body; // Merge the outlives constraints back in, at the given location. - mem::swap(self.cx.borrowck_context.all_facts, all_facts); - mem::swap( - &mut self.cx.borrowck_context.constraints.outlives_constraints, - &mut constraints - ); - mem::swap( - &mut self.cx.borrowck_context.constraints.closure_bounds_mapping, - &mut closure_bounds - ); + swap_constraints(self); let locations = location.to_locations(); for constraint in constraints.outlives().iter() { let mut constraint = *constraint; constraint.locations = locations; if let ConstraintCategory::Return - | ConstraintCategory::UseAsConst - | ConstraintCategory::UseAsStatic = constraint.category + | ConstraintCategory::UseAsConst + | ConstraintCategory::UseAsStatic = constraint.category { // "Returning" from a promoted is an assigment to a // temporary from the user's point of view. @@ -608,6 +592,10 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } self.cx.borrowck_context.constraints.outlives_constraints.push(constraint) } + for live_region in liveness_constraints.rows() { + self.cx.borrowck_context.constraints.liveness_constraints + .add_element(live_region, location); + } if !closure_bounds.is_empty() { let combined_bounds_mapping = closure_bounds @@ -667,7 +655,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { ) } ProjectionElem::Subslice { from, to } => PlaceTy::from_ty( - match base_ty.sty { + match base_ty.kind { ty::Array(inner, size) => { let size = size.eval_usize(tcx, self.cx.param_env); let min_size = (from as u64) + (to as u64); @@ -686,7 +674,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { _ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty), }, ), - ProjectionElem::Downcast(maybe_name, index) => match base_ty.sty { + ProjectionElem::Downcast(maybe_name, index) => match base_ty.kind { ty::Adt(adt_def, _substs) if adt_def.is_enum() => { if index.as_usize() >= adt_def.variants.len() { PlaceTy::from_ty( @@ -768,16 +756,16 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { let tcx = self.tcx(); let (variant, substs) = match base_ty { - PlaceTy { ty, variant_index: Some(variant_index) } => match ty.sty { + PlaceTy { ty, variant_index: Some(variant_index) } => match ty.kind { ty::Adt(adt_def, substs) => (&adt_def.variants[variant_index], substs), ty::Generator(def_id, substs, _) => { - let mut variants = substs.state_tys(def_id, tcx); + let mut variants = substs.as_generator().state_tys(def_id, tcx); let mut variant = match variants.nth(variant_index.into()) { Some(v) => v, None => { bug!("variant_index of generator out of range: {:?}/{:?}", variant_index, - substs.state_tys(def_id, tcx).count()) + substs.as_generator().state_tys(def_id, tcx).count()) } }; return match variant.nth(field.index()) { @@ -789,24 +777,24 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } _ => bug!("can't have downcast of non-adt non-generator type"), } - PlaceTy { ty, variant_index: None } => match ty.sty { + PlaceTy { ty, variant_index: None } => match ty.kind { ty::Adt(adt_def, substs) if !adt_def.is_enum() => (&adt_def.variants[VariantIdx::new(0)], substs), ty::Closure(def_id, substs) => { - return match substs.upvar_tys(def_id, tcx).nth(field.index()) { + return match substs.as_closure().upvar_tys(def_id, tcx).nth(field.index()) { Some(ty) => Ok(ty), None => Err(FieldAccessError::OutOfRange { - field_count: substs.upvar_tys(def_id, tcx).count(), + field_count: substs.as_closure().upvar_tys(def_id, tcx).count(), }), } } ty::Generator(def_id, substs, _) => { // Only prefix fields (upvars and current state) are // accessible without a variant index. - return match substs.prefix_tys(def_id, tcx).nth(field.index()) { + return match substs.as_generator().prefix_tys(def_id, tcx).nth(field.index()) { Some(ty) => Ok(ty), None => Err(FieldAccessError::OutOfRange { - field_count: substs.prefix_tys(def_id, tcx).count(), + field_count: substs.as_generator().prefix_tys(def_id, tcx).count(), }), } } @@ -1172,7 +1160,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { category: ConstraintCategory, ) -> Fallible<()> { if let Err(terr) = self.sub_types(sub, sup, locations, category) { - if let ty::Opaque(..) = sup.sty { + if let ty::Opaque(..) = sup.kind { // When you have `let x: impl Foo = ...` in a closure, // the resulting inferend values are stored with the // def-id of the base function. @@ -1373,7 +1361,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { debug!("check_stmt: {:?}", stmt); let tcx = self.tcx(); match stmt.kind { - StatementKind::Assign(ref place, ref rv) => { + StatementKind::Assign(box(ref place, ref rv)) => { // Assignments to temporaries are not "interesting"; // they are not caused by the user, but rather artifacts // of lowering. Assignments to other sorts of places *are* interesting @@ -1381,7 +1369,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let category = match *place { Place { base: PlaceBase::Local(RETURN_PLACE), - projection: None, + projection: box [], } => if let BorrowCheckContext { universal_regions: UniversalRegions { @@ -1400,7 +1388,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { }, Place { base: PlaceBase::Local(l), - projection: None, + projection: box [], } if !body.local_decls[l].is_user_variable.is_some() => { ConstraintCategory::Boring } @@ -1408,7 +1396,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { }; let place_ty = place.ty(body, tcx).ty; + let place_ty = self.normalize(place_ty, location); let rv_ty = rv.ty(body, tcx); + let rv_ty = self.normalize(rv_ty, location); if let Err(terr) = self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category) { @@ -1460,7 +1450,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { variant_index, } => { let place_type = place.ty(body, tcx).ty; - let adt = match place_type.sty { + let adt = match place_type.kind { ty::Adt(adt, _) if adt.is_enum() => adt, _ => { span_bug!( @@ -1480,7 +1470,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); }; } - StatementKind::AscribeUserType(ref place, variance, box ref projection) => { + StatementKind::AscribeUserType(box(ref place, ref projection), variance) => { let place_ty = place.ty(body, tcx).ty; if let Err(terr) = self.relate_type_and_user_type( place_ty, @@ -1589,7 +1579,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } => { let func_ty = func.ty(body, tcx); debug!("check_terminator: call, func_ty={:?}", func_ty); - let sig = match func_ty.sty { + let sig = match func_ty.kind { ty::FnDef(..) | ty::FnPtr(_) => func_ty.fn_sig(tcx), _ => { span_mirbug!(self, term, "call to non-function {:?}", func_ty); @@ -1684,10 +1674,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { match *destination { Some((ref dest, _target_block)) => { let dest_ty = dest.ty(body, tcx).ty; + let dest_ty = self.normalize(dest_ty, term_location); let category = match *dest { Place { base: PlaceBase::Local(RETURN_PLACE), - projection: None, + projection: box [], } => { if let BorrowCheckContext { universal_regions: @@ -1709,7 +1700,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } Place { base: PlaceBase::Local(l), - projection: None, + projection: box [], } if !body.local_decls[l].is_user_variable.is_some() => { ConstraintCategory::Boring } @@ -1756,17 +1747,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { from_hir_call: bool, ) { debug!("check_call_inputs({:?}, {:?})", sig, args); - // Do not count the `VaListImpl` argument as a "true" argument to - // a C-variadic function. - let inputs = if sig.c_variadic { - &sig.inputs()[..sig.inputs().len() - 1] - } else { - &sig.inputs()[..] - }; - if args.len() < inputs.len() || (args.len() > inputs.len() && !sig.c_variadic) { + if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) { span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); } - for (n, (fn_arg, op_arg)) in inputs.iter().zip(args).enumerate() { + for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() { let op_arg_ty = op_arg.ty(body, self.tcx()); let category = if from_hir_call { ConstraintCategory::CallArgument @@ -1924,9 +1908,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // Erase the regions from `ty` to get a global type. The // `Sized` bound in no way depends on precise regions, so this // shouldn't affect `is_sized`. - let gcx = tcx.global_tcx(); let erased_ty = tcx.erase_regions(&ty); - if !erased_ty.is_sized(gcx.at(span), self.param_env) { + if !erased_ty.is_sized(tcx.at(span), self.param_env) { // in current MIR construction, all non-control-flow rvalue // expressions evaluate through `as_temp` or `into` a return // slot or local, so to find all unsized rvalues it is enough @@ -1972,10 +1955,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } AggregateKind::Closure(def_id, substs) => { - match substs.upvar_tys(def_id, tcx).nth(field_index) { + match substs.as_closure().upvar_tys(def_id, tcx).nth(field_index) { Some(ty) => Ok(ty), None => Err(FieldAccessError::OutOfRange { - field_count: substs.upvar_tys(def_id, tcx).count(), + field_count: substs.as_closure().upvar_tys(def_id, tcx).count(), }), } } @@ -1983,10 +1966,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // It doesn't make sense to look at a field beyond the prefix; // these require a variant index, and are not initialized in // aggregate rvalues. - match substs.prefix_tys(def_id, tcx).nth(field_index) { + match substs.as_generator().prefix_tys(def_id, tcx).nth(field_index) { Some(ty) => Ok(ty), None => Err(FieldAccessError::OutOfRange { - field_count: substs.prefix_tys(def_id, tcx).count(), + field_count: substs.as_generator().prefix_tys(def_id, tcx).count(), }), } } @@ -2029,6 +2012,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ), &traits::SelectionError::Unimplemented, false, + false, ); } } @@ -2085,9 +2069,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } CastKind::Pointer(PointerCast::ClosureFnPointer(unsafety)) => { - let sig = match op.ty(body, tcx).sty { + let sig = match op.ty(body, tcx).kind { ty::Closure(def_id, substs) => { - substs.closure_sig_ty(def_id, tcx).fn_sig(tcx) + substs.as_closure().sig_ty(def_id, tcx).fn_sig(tcx) } _ => bug!(), }; @@ -2154,7 +2138,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } CastKind::Pointer(PointerCast::MutToConstPointer) => { - let ty_from = match op.ty(body, tcx).sty { + let ty_from = match op.ty(body, tcx).kind { ty::RawPtr(ty::TypeAndMut { ty: ty_from, mutbl: hir::MutMutable, @@ -2169,7 +2153,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { return; } }; - let ty_to = match ty.sty { + let ty_to = match ty.kind { ty::RawPtr(ty::TypeAndMut { ty: ty_to, mutbl: hir::MutImmutable, @@ -2202,11 +2186,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } CastKind::Misc => { - if let ty::Ref(_, mut ty_from, _) = op.ty(body, tcx).sty { + if let ty::Ref(_, mut ty_from, _) = op.ty(body, tcx).kind { let (mut ty_to, mutability) = if let ty::RawPtr(ty::TypeAndMut { ty: ty_to, mutbl, - }) = ty.sty { + }) = ty.kind { (ty_to, mutbl) } else { span_mirbug!( @@ -2221,9 +2205,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // Handle the direct cast from `&[T; N]` to `*const T` by unwrapping // any array we find. - while let ty::Array(ty_elem_from, _) = ty_from.sty { + while let ty::Array(ty_elem_from, _) = ty_from.kind { ty_from = ty_elem_from; - if let ty::Array(ty_elem_to, _) = ty_to.sty { + if let ty::Array(ty_elem_to, _) = ty_to.kind { ty_to = ty_elem_to; } else { break; @@ -2279,7 +2263,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | Rvalue::BinaryOp(BinOp::Gt, left, right) | Rvalue::BinaryOp(BinOp::Ge, left, right) => { let ty_left = left.ty(body, tcx); - if let ty::RawPtr(_) | ty::FnPtr(_) = ty_left.sty { + if let ty::RawPtr(_) | ty::FnPtr(_) = ty_left.kind { let ty_right = right.ty(body, tcx); let common_ty = self.infcx.next_ty_var( TypeVariableOrigin { @@ -2443,22 +2427,24 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // *p`, where the `p` has type `&'b mut Foo`, for example, we // need to ensure that `'b: 'a`. - let mut borrowed_projection = &borrowed_place.projection; - debug!( "add_reborrow_constraint({:?}, {:?}, {:?})", location, borrow_region, borrowed_place ); - while let Some(box proj) = borrowed_projection { - debug!("add_reborrow_constraint - iteration {:?}", borrowed_projection); - match proj.elem { + let mut cursor = &*borrowed_place.projection; + while let [proj_base @ .., elem] = cursor { + cursor = proj_base; + + debug!("add_reborrow_constraint - iteration {:?}", elem); + + match elem { ProjectionElem::Deref => { let tcx = self.infcx.tcx; - let base_ty = Place::ty_from(&borrowed_place.base, &proj.base, body, tcx).ty; + let base_ty = Place::ty_from(&borrowed_place.base, proj_base, body, tcx).ty; debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); - match base_ty.sty { + match base_ty.kind { ty::Ref(ref_region, _, mutbl) => { constraints.outlives_constraints.push(OutlivesConstraint { sup: ref_region.to_region_vid(), @@ -2517,10 +2503,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // other field access } } - - // The "propagate" case. We need to check that our base is valid - // for the borrow's lifetime. - borrowed_projection = &proj.base; } } @@ -2561,8 +2543,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // desugaring. A closure gets desugared to a struct, and // these extra requirements are basically like where // clauses on the struct. - AggregateKind::Closure(def_id, ty::ClosureSubsts { substs }) - | AggregateKind::Generator(def_id, ty::GeneratorSubsts { substs }, _) => { + AggregateKind::Closure(def_id, substs) + | AggregateKind::Generator(def_id, substs, _) => { self.prove_closure_bounds(tcx, *def_id, substs, location) } @@ -2606,7 +2588,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { }); match k1.unpack() { - UnpackedKind::Lifetime(r1) => { + GenericArgKind::Lifetime(r1) => { // constraint is r1: r2 let r1_vid = self.borrowck_context.universal_regions.to_region_vid(r1); let r2_vid = self.borrowck_context.universal_regions.to_region_vid(r2); @@ -2620,7 +2602,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ), )) } - UnpackedKind::Type(_) | UnpackedKind::Const(_) => None, + GenericArgKind::Type(_) | GenericArgKind::Const(_) => None, } }) .collect(); diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index 2549aa4fbff93..80bf0478128c7 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -66,9 +66,9 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { self.infcx.create_next_universe() } - fn next_existential_region_var(&mut self) -> ty::Region<'tcx> { + fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> { if let Some(_) = &mut self.borrowck_context { - let origin = NLLRegionVariableOrigin::Existential; + let origin = NLLRegionVariableOrigin::Existential { from_forall }; self.infcx.next_nll_region_var(origin) } else { self.infcx.tcx.lifetimes.re_erased @@ -88,7 +88,9 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { self.infcx - .next_nll_region_var_in_universe(NLLRegionVariableOrigin::Existential, universe) + .next_nll_region_var_in_universe(NLLRegionVariableOrigin::Existential { + from_forall: false + }, universe) } fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) { diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs index 3e090aed52270..5f6951856434e 100644 --- a/src/librustc_mir/borrow_check/nll/universal_regions.rs +++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs @@ -16,11 +16,12 @@ use either::Either; use rustc::hir::def_id::DefId; use rustc::hir::{self, BodyOwnerKind, HirId}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; +use rustc::middle::lang_items; use rustc::ty::fold::TypeFoldable; -use rustc::ty::subst::{InternalSubsts, SubstsRef}; -use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty, TyCtxt}; +use rustc::ty::subst::{InternalSubsts, SubstsRef, Subst}; +use rustc::ty::{self, RegionVid, Ty, TyCtxt}; use rustc::util::nodemap::FxHashMap; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_index::vec::{Idx, IndexVec}; use rustc_errors::DiagnosticBuilder; use std::iter; @@ -84,12 +85,12 @@ pub struct UniversalRegions<'tcx> { pub enum DefiningTy<'tcx> { /// The MIR is a closure. The signature is found via /// `ClosureSubsts::closure_sig_ty`. - Closure(DefId, ty::ClosureSubsts<'tcx>), + Closure(DefId, SubstsRef<'tcx>), /// The MIR is a generator. The signature is that generators take /// no parameters and return the result of /// `ClosureSubsts::generator_return_ty`. - Generator(DefId, ty::GeneratorSubsts<'tcx>, hir::GeneratorMovability), + Generator(DefId, SubstsRef<'tcx>, hir::GeneratorMovability), /// The MIR is a fn item with the given `DefId` and substs. The signature /// of the function can be bound then with the `fn_sig` query. @@ -108,9 +109,11 @@ impl<'tcx> DefiningTy<'tcx> { /// match up with the upvar order in the HIR, typesystem, and MIR. pub fn upvar_tys(self, tcx: TyCtxt<'tcx>) -> impl Iterator> + 'tcx { match self { - DefiningTy::Closure(def_id, substs) => Either::Left(substs.upvar_tys(def_id, tcx)), + DefiningTy::Closure(def_id, substs) => Either::Left( + substs.as_closure().upvar_tys(def_id, tcx) + ), DefiningTy::Generator(def_id, substs, _) => { - Either::Right(Either::Left(substs.upvar_tys(def_id, tcx))) + Either::Right(Either::Left(substs.as_generator().upvar_tys(def_id, tcx))) } DefiningTy::FnDef(..) | DefiningTy::Const(..) => { Either::Right(Either::Right(iter::empty())) @@ -311,7 +314,7 @@ impl<'tcx> UniversalRegions<'tcx> { err.note(&format!( "defining type: {:?} with closure substs {:#?}", def_id, - &substs.substs[..] + &substs[..] )); // FIXME: It'd be nice to print the late-bound regions @@ -331,7 +334,7 @@ impl<'tcx> UniversalRegions<'tcx> { err.note(&format!( "defining type: {:?} with generator substs {:#?}", def_id, - &substs.substs[..] + &substs[..] )); // FIXME: As above, we'd like to print out the region @@ -425,12 +428,33 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { .replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices); } + let (unnormalized_output_ty, mut unnormalized_input_tys) = + inputs_and_output.split_last().unwrap(); + + // C-variadic fns also have a `VaList` input that's not listed in the signature + // (as it's created inside the body itself, not passed in from outside). + if let DefiningTy::FnDef(def_id, _) = defining_ty { + if self.infcx.tcx.fn_sig(def_id).c_variadic() { + let va_list_did = self.infcx.tcx.require_lang_item( + lang_items::VaListTypeLangItem, + Some(self.infcx.tcx.def_span(self.mir_def_id),), + ); + let region = self.infcx.tcx.mk_region(ty::ReVar( + self.infcx.next_nll_region_var(FR).to_region_vid(), + )); + let va_list_ty = self.infcx.tcx.type_of(va_list_did) + .subst(self.infcx.tcx, &[region.into()]); + + unnormalized_input_tys = self.infcx.tcx.mk_type_list( + unnormalized_input_tys.iter().copied() + .chain(iter::once(va_list_ty)), + ); + } + } + let fr_fn_body = self.infcx.next_nll_region_var(FR).to_region_vid(); let num_universals = self.infcx.num_region_vars(); - let (unnormalized_output_ty, unnormalized_input_tys) = - inputs_and_output.split_last().unwrap(); - debug!( "build: global regions = {}..{}", FIRST_GLOBAL_INDEX, first_extern_index @@ -446,7 +470,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let yield_ty = match defining_ty { DefiningTy::Generator(def_id, substs, _) => { - Some(substs.yield_ty(def_id, self.infcx.tcx)) + Some(substs.as_generator().yield_ty(def_id, self.infcx.tcx)) } _ => None, }; @@ -486,7 +510,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let defining_ty = self.infcx .replace_free_regions_with_nll_infer_vars(FR, &defining_ty); - match defining_ty.sty { + match defining_ty.kind { ty::Closure(def_id, substs) => DefiningTy::Closure(def_id, substs), ty::Generator(def_id, substs, movability) => { DefiningTy::Generator(def_id, substs, movability) @@ -521,12 +545,11 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { defining_ty: DefiningTy<'tcx>, ) -> UniversalRegionIndices<'tcx> { let tcx = self.infcx.tcx; - let gcx = tcx.global_tcx(); let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id); - let identity_substs = InternalSubsts::identity_for_item(gcx, closure_base_def_id); + let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); let fr_substs = match defining_ty { - DefiningTy::Closure(_, ClosureSubsts { ref substs }) - | DefiningTy::Generator(_, GeneratorSubsts { ref substs }, _) => { + DefiningTy::Closure(_, ref substs) + | DefiningTy::Generator(_, ref substs, _) => { // In the case of closures, we rely on the fact that // the first N elements in the ClosureSubsts are // inherited from the `closure_base_def_id`. @@ -542,7 +565,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { DefiningTy::FnDef(_, substs) | DefiningTy::Const(_, substs) => substs, }; - let global_mapping = iter::once((gcx.lifetimes.re_static, fr_static)); + let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static)); let subst_mapping = identity_substs .regions() .zip(fr_substs.regions().map(|r| r.to_region_vid())); @@ -561,7 +584,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { match defining_ty { DefiningTy::Closure(def_id, substs) => { assert_eq!(self.mir_def_id, def_id); - let closure_sig = substs.closure_sig_ty(def_id, tcx).fn_sig(tcx); + let closure_sig = substs.as_closure().sig_ty(def_id, tcx).fn_sig(tcx); let inputs_and_output = closure_sig.inputs_and_output(); let closure_ty = tcx.closure_env_ty(def_id, substs).unwrap(); ty::Binder::fuse( @@ -573,7 +596,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // flattens this tuple. let (&output, tuplized_inputs) = inputs_and_output.split_last().unwrap(); assert_eq!(tuplized_inputs.len(), 1, "multiple closure inputs"); - let inputs = match tuplized_inputs[0].sty { + let inputs = match tuplized_inputs[0].kind { ty::Tuple(inputs) => inputs, _ => bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]), }; @@ -589,7 +612,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { DefiningTy::Generator(def_id, substs, movability) => { assert_eq!(self.mir_def_id, def_id); - let output = substs.return_ty(def_id, tcx); + let output = substs.as_generator().return_ty(def_id, tcx); let generator_ty = tcx.mk_generator(def_id, substs, movability); let inputs_and_output = self.infcx.tcx.intern_type_list(&[generator_ty, output]); ty::Binder::dummy(inputs_and_output) diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs index 43a012e1494f8..bac08090817d9 100644 --- a/src/librustc_mir/borrow_check/path_utils.rs +++ b/src/librustc_mir/borrow_check/path_utils.rs @@ -3,7 +3,7 @@ use crate::borrow_check::places_conflict; use crate::borrow_check::AccessDepth; use crate::dataflow::indexes::BorrowIndex; use rustc::mir::{BasicBlock, Location, Body, Place, PlaceBase}; -use rustc::mir::{ProjectionElem, BorrowKind}; +use rustc::mir::BorrowKind; use rustc::ty::{self, TyCtxt}; use rustc_data_structures::graph::dominators::Dominators; @@ -133,20 +133,11 @@ pub(super) fn is_active<'tcx>( /// Determines if a given borrow is borrowing local data /// This is called for all Yield statements on movable generators pub(super) fn borrow_of_local_data(place: &Place<'_>) -> bool { - place.iterate(|place_base, place_projection| { - match place_base { - PlaceBase::Static(..) => return false, - PlaceBase::Local(..) => {}, - } - - for proj in place_projection { - // Reborrow of already borrowed data is ignored - // Any errors will be caught on the initial borrow - if proj.elem == ProjectionElem::Deref { - return false; - } - } + match place.base { + PlaceBase::Static(_) => false, - true - }) + // Reborrow of already borrowed data is ignored + // Any errors will be caught on the initial borrow + PlaceBase::Local(_) => !place.is_indirect(), + } } diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs index 72d5588c34120..f437c7172966b 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/src/librustc_mir/borrow_check/place_ext.rs @@ -25,55 +25,54 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { body: &Body<'tcx>, locals_state_at_exit: &LocalsStateAtExit, ) -> bool { - self.iterate(|place_base, place_projection| { - let ignore = match place_base { - // If a local variable is immutable, then we only need to track borrows to guard - // against two kinds of errors: - // * The variable being dropped while still borrowed (e.g., because the fn returns - // a reference to a local variable) - // * The variable being moved while still borrowed - // - // In particular, the variable cannot be mutated -- the "access checks" will fail -- - // so we don't have to worry about mutation while borrowed. - PlaceBase::Local(index) => { - match locals_state_at_exit { - LocalsStateAtExit::AllAreInvalidated => false, - LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => { - let ignore = !has_storage_dead_or_moved.contains(*index) && - body.local_decls[*index].mutability == Mutability::Not; - debug!("ignore_borrow: local {:?} => {:?}", index, ignore); - ignore - } + let ignore = match self.base { + // If a local variable is immutable, then we only need to track borrows to guard + // against two kinds of errors: + // * The variable being dropped while still borrowed (e.g., because the fn returns + // a reference to a local variable) + // * The variable being moved while still borrowed + // + // In particular, the variable cannot be mutated -- the "access checks" will fail -- + // so we don't have to worry about mutation while borrowed. + PlaceBase::Local(index) => { + match locals_state_at_exit { + LocalsStateAtExit::AllAreInvalidated => false, + LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => { + let ignore = !has_storage_dead_or_moved.contains(index) && + body.local_decls[index].mutability == Mutability::Not; + debug!("ignore_borrow: local {:?} => {:?}", index, ignore); + ignore } } - PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) => - false, - PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => { - tcx.is_mutable_static(*def_id) - } - }; + } + PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) => + false, + PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => { + tcx.is_mutable_static(def_id) + } + }; - for proj in place_projection { - if proj.elem == ProjectionElem::Deref { - let ty = Place::ty_from(place_base, &proj.base, body, tcx).ty; - match ty.sty { - // For both derefs of raw pointers and `&T` - // references, the original path is `Copy` and - // therefore not significant. In particular, - // there is nothing the user can do to the - // original path that would invalidate the - // newly created reference -- and if there - // were, then the user could have copied the - // original path into a new variable and - // borrowed *that* one, leaving the original - // path unborrowed. - ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => return true, - _ => {} - } + for (i, elem) in self.projection.iter().enumerate() { + let proj_base = &self.projection[..i]; + + if *elem == ProjectionElem::Deref { + let ty = Place::ty_from(&self.base, proj_base, body, tcx).ty; + if let ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) = ty.kind { + // For both derefs of raw pointers and `&T` + // references, the original path is `Copy` and + // therefore not significant. In particular, + // there is nothing the user can do to the + // original path that would invalidate the + // newly created reference -- and if there + // were, then the user could have copied the + // original path into a new variable and + // borrowed *that* one, leaving the original + // path unborrowed. + return true; } } + } - ignore - }) + ignore } } diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 4dd2794f11301..9dd3e119c217a 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -3,8 +3,7 @@ use crate::borrow_check::Overlap; use crate::borrow_check::{Deep, Shallow, AccessDepth}; use rustc::hir; use rustc::mir::{ - Body, BorrowKind, Place, PlaceBase, PlaceRef, Projection, ProjectionElem, ProjectionsIter, - StaticKind, + Body, BorrowKind, Place, PlaceBase, PlaceElem, PlaceRef, ProjectionElem, StaticKind, }; use rustc::ty::{self, TyCtxt}; use std::cmp::max; @@ -67,39 +66,35 @@ pub(super) fn borrow_conflicts_with_place<'tcx>( // it's so common that it's a speed win to check for it first. if let Place { base: PlaceBase::Local(l1), - projection: None, + projection: box [], } = borrow_place { if let PlaceRef { base: PlaceBase::Local(l2), - projection: None, + projection: [], } = access_place { return l1 == l2; } } - borrow_place.iterate(|borrow_base, borrow_projections| { - access_place.iterate(|access_base, access_projections| { - place_components_conflict( - tcx, - param_env, - body, - (borrow_base, borrow_projections), - borrow_kind, - (access_base, access_projections), - access, - bias, - ) - }) - }) + place_components_conflict( + tcx, + param_env, + body, + borrow_place, + borrow_kind, + access_place, + access, + bias, + ) } fn place_components_conflict<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, - borrow_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>), + borrow_place: &Place<'tcx>, borrow_kind: BorrowKind, - access_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>), + access_place: PlaceRef<'_, 'tcx>, access: AccessDepth, bias: PlaceConflictBias, ) -> bool { @@ -145,8 +140,8 @@ fn place_components_conflict<'tcx>( // and either equal or disjoint. // - If we did run out of access, the borrow can access a part of it. - let borrow_base = borrow_projections.0; - let access_base = access_projections.0; + let borrow_base = &borrow_place.base; + let access_base = access_place.base; match place_base_conflict(tcx, param_env, borrow_base, access_base) { Overlap::Arbitrary => { @@ -163,147 +158,157 @@ fn place_components_conflict<'tcx>( } } - let mut borrow_projections = borrow_projections.1; - let mut access_projections = access_projections.1; - - loop { - // loop invariant: borrow_c is always either equal to access_c or disjoint from it. - if let Some(borrow_c) = borrow_projections.next() { - debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c); + // loop invariant: borrow_c is always either equal to access_c or disjoint from it. + for (i, (borrow_c, access_c)) in + borrow_place.projection.iter().zip(access_place.projection.iter()).enumerate() + { + debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c); + let borrow_proj_base = &borrow_place.projection[..i]; - if let Some(access_c) = access_projections.next() { - debug!("borrow_conflicts_with_place: access_c = {:?}", access_c); + debug!("borrow_conflicts_with_place: access_c = {:?}", access_c); - // Borrow and access path both have more components. - // - // Examples: - // - // - borrow of `a.(...)`, access to `a.(...)` - // - borrow of `a.(...)`, access to `b.(...)` - // - // Here we only see the components we have checked so - // far (in our examples, just the first component). We - // check whether the components being borrowed vs - // accessed are disjoint (as in the second example, - // but not the first). - match place_projection_conflict(tcx, body, borrow_base, borrow_c, access_c, bias) { - Overlap::Arbitrary => { - // We have encountered different fields of potentially - // the same union - the borrow now partially overlaps. - // - // There is no *easy* way of comparing the fields - // further on, because they might have different types - // (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and - // `.y` come from different structs). - // - // We could try to do some things here - e.g., count - // dereferences - but that's probably not a good - // idea, at least for now, so just give up and - // report a conflict. This is unsafe code anyway so - // the user could always use raw pointers. - debug!("borrow_conflicts_with_place: arbitrary -> conflict"); - return true; - } - Overlap::EqualOrDisjoint => { - // This is the recursive case - proceed to the next element. - } - Overlap::Disjoint => { - // We have proven the borrow disjoint - further - // projections will remain disjoint. - debug!("borrow_conflicts_with_place: disjoint"); - return false; - } - } - } else { - // Borrow path is longer than the access path. Examples: + // Borrow and access path both have more components. + // + // Examples: + // + // - borrow of `a.(...)`, access to `a.(...)` + // - borrow of `a.(...)`, access to `b.(...)` + // + // Here we only see the components we have checked so + // far (in our examples, just the first component). We + // check whether the components being borrowed vs + // accessed are disjoint (as in the second example, + // but not the first). + match place_projection_conflict( + tcx, + body, + borrow_base, + borrow_proj_base, + borrow_c, + access_c, + bias, + ) { + Overlap::Arbitrary => { + // We have encountered different fields of potentially + // the same union - the borrow now partially overlaps. // - // - borrow of `a.b.c`, access to `a.b` + // There is no *easy* way of comparing the fields + // further on, because they might have different types + // (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and + // `.y` come from different structs). // - // Here, we know that the borrow can access a part of - // our place. This is a conflict if that is a part our - // access cares about. + // We could try to do some things here - e.g., count + // dereferences - but that's probably not a good + // idea, at least for now, so just give up and + // report a conflict. This is unsafe code anyway so + // the user could always use raw pointers. + debug!("borrow_conflicts_with_place: arbitrary -> conflict"); + return true; + } + Overlap::EqualOrDisjoint => { + // This is the recursive case - proceed to the next element. + } + Overlap::Disjoint => { + // We have proven the borrow disjoint - further + // projections will remain disjoint. + debug!("borrow_conflicts_with_place: disjoint"); + return false; + } + } + } + + if borrow_place.projection.len() > access_place.projection.len() { + for (i, elem) in borrow_place.projection[access_place.projection.len()..].iter().enumerate() + { + // Borrow path is longer than the access path. Examples: + // + // - borrow of `a.b.c`, access to `a.b` + // + // Here, we know that the borrow can access a part of + // our place. This is a conflict if that is a part our + // access cares about. - let base = &borrow_c.base; - let elem = &borrow_c.elem; - let base_ty = Place::ty_from(borrow_base, base, body, tcx).ty; + let proj_base = &borrow_place.projection[..access_place.projection.len() + i]; + let base_ty = Place::ty_from(borrow_base, proj_base, body, tcx).ty; - match (elem, &base_ty.sty, access) { - (_, _, Shallow(Some(ArtificialField::ArrayLength))) - | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => { - // The array length is like additional fields on the - // type; it does not overlap any existing data there. - // Furthermore, if cannot actually be a prefix of any - // borrowed place (at least in MIR as it is currently.) - // - // e.g., a (mutable) borrow of `a[5]` while we read the - // array length of `a`. - debug!("borrow_conflicts_with_place: implicit field"); - return false; - } + match (elem, &base_ty.kind, access) { + (_, _, Shallow(Some(ArtificialField::ArrayLength))) + | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => { + // The array length is like additional fields on the + // type; it does not overlap any existing data there. + // Furthermore, if cannot actually be a prefix of any + // borrowed place (at least in MIR as it is currently.) + // + // e.g., a (mutable) borrow of `a[5]` while we read the + // array length of `a`. + debug!("borrow_conflicts_with_place: implicit field"); + return false; + } - (ProjectionElem::Deref, _, Shallow(None)) => { - // e.g., a borrow of `*x.y` while we shallowly access `x.y` or some - // prefix thereof - the shallow access can't touch anything behind - // the pointer. - debug!("borrow_conflicts_with_place: shallow access behind ptr"); - return false; - } - (ProjectionElem::Deref, ty::Ref(_, _, hir::MutImmutable), _) => { - // Shouldn't be tracked - bug!("Tracking borrow behind shared reference."); - } - (ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => { - // Values behind a mutable reference are not access either by dropping a - // value, or by StorageDead - debug!("borrow_conflicts_with_place: drop access behind ptr"); - return false; - } + (ProjectionElem::Deref, _, Shallow(None)) => { + // e.g., a borrow of `*x.y` while we shallowly access `x.y` or some + // prefix thereof - the shallow access can't touch anything behind + // the pointer. + debug!("borrow_conflicts_with_place: shallow access behind ptr"); + return false; + } + (ProjectionElem::Deref, ty::Ref(_, _, hir::MutImmutable), _) => { + // Shouldn't be tracked + bug!("Tracking borrow behind shared reference."); + } + (ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => { + // Values behind a mutable reference are not access either by dropping a + // value, or by StorageDead + debug!("borrow_conflicts_with_place: drop access behind ptr"); + return false; + } - (ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => { - // Drop can read/write arbitrary projections, so places - // conflict regardless of further projections. - if def.has_dtor(tcx) { - return true; - } + (ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => { + // Drop can read/write arbitrary projections, so places + // conflict regardless of further projections. + if def.has_dtor(tcx) { + return true; } + } - (ProjectionElem::Deref, _, Deep) - | (ProjectionElem::Deref, _, AccessDepth::Drop) - | (ProjectionElem::Field { .. }, _, _) - | (ProjectionElem::Index { .. }, _, _) - | (ProjectionElem::ConstantIndex { .. }, _, _) - | (ProjectionElem::Subslice { .. }, _, _) - | (ProjectionElem::Downcast { .. }, _, _) => { - // Recursive case. This can still be disjoint on a - // further iteration if this a shallow access and - // there's a deref later on, e.g., a borrow - // of `*x.y` while accessing `x`. - } + (ProjectionElem::Deref, _, Deep) + | (ProjectionElem::Deref, _, AccessDepth::Drop) + | (ProjectionElem::Field { .. }, _, _) + | (ProjectionElem::Index { .. }, _, _) + | (ProjectionElem::ConstantIndex { .. }, _, _) + | (ProjectionElem::Subslice { .. }, _, _) + | (ProjectionElem::Downcast { .. }, _, _) => { + // Recursive case. This can still be disjoint on a + // further iteration if this a shallow access and + // there's a deref later on, e.g., a borrow + // of `*x.y` while accessing `x`. } } - } else { - // Borrow path ran out but access path may not - // have. Examples: - // - // - borrow of `a.b`, access to `a.b.c` - // - borrow of `a.b`, access to `a.b` - // - // In the first example, where we didn't run out of - // access, the borrow can access all of our place, so we - // have a conflict. - // - // If the second example, where we did, then we still know - // that the borrow can access a *part* of our place that - // our access cares about, so we still have a conflict. - if borrow_kind == BorrowKind::Shallow && access_projections.next().is_some() { - debug!("borrow_conflicts_with_place: shallow borrow"); - return false; - } else { - debug!("borrow_conflicts_with_place: full borrow, CONFLICT"); - return true; - } } } + + // Borrow path ran out but access path may not + // have. Examples: + // + // - borrow of `a.b`, access to `a.b.c` + // - borrow of `a.b`, access to `a.b` + // + // In the first example, where we didn't run out of + // access, the borrow can access all of our place, so we + // have a conflict. + // + // If the second example, where we did, then we still know + // that the borrow can access a *part* of our place that + // our access cares about, so we still have a conflict. + if borrow_kind == BorrowKind::Shallow + && borrow_place.projection.len() < access_place.projection.len() + { + debug!("borrow_conflicts_with_place: shallow borrow"); + false + } else { + debug!("borrow_conflicts_with_place: full borrow, CONFLICT"); + true + } } // Given that the bases of `elem1` and `elem2` are always either equal @@ -329,11 +334,11 @@ fn place_base_conflict<'tcx>( } (PlaceBase::Static(s1), PlaceBase::Static(s2)) => { match (&s1.kind, &s2.kind) { - (StaticKind::Static(def_id_1), StaticKind::Static(def_id_2)) => { - if def_id_1 != def_id_2 { + (StaticKind::Static, StaticKind::Static) => { + if s1.def_id != s2.def_id { debug!("place_element_conflict: DISJOINT-STATIC"); Overlap::Disjoint - } else if tcx.is_mutable_static(*def_id_1) { + } else if tcx.is_mutable_static(s1.def_id) { // We ignore mutable statics - they can only be unsafe code. debug!("place_element_conflict: IGNORE-STATIC-MUT"); Overlap::Disjoint @@ -342,9 +347,9 @@ fn place_base_conflict<'tcx>( Overlap::EqualOrDisjoint } }, - (StaticKind::Promoted(promoted_1), StaticKind::Promoted(promoted_2)) => { + (StaticKind::Promoted(promoted_1, _), StaticKind::Promoted(promoted_2, _)) => { if promoted_1 == promoted_2 { - if let ty::Array(_, len) = s1.ty.sty { + if let ty::Array(_, len) = s1.ty.kind { if let Some(0) = len.try_eval_usize(tcx, param_env) { // Ignore conflicts with promoted [T; 0]. debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED"); @@ -381,11 +386,12 @@ fn place_projection_conflict<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, pi1_base: &PlaceBase<'tcx>, - pi1: &Projection<'tcx>, - pi2: &Projection<'tcx>, + pi1_proj_base: &[PlaceElem<'tcx>], + pi1_elem: &PlaceElem<'tcx>, + pi2_elem: &PlaceElem<'tcx>, bias: PlaceConflictBias, ) -> Overlap { - match (&pi1.elem, &pi2.elem) { + match (pi1_elem, pi2_elem) { (ProjectionElem::Deref, ProjectionElem::Deref) => { // derefs (e.g., `*x` vs. `*x`) - recur. debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF"); @@ -397,8 +403,8 @@ fn place_projection_conflict<'tcx>( debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); Overlap::EqualOrDisjoint } else { - let ty = Place::ty_from(pi1_base, &pi1.base, body, tcx).ty; - match ty.sty { + let ty = Place::ty_from(pi1_base, pi1_proj_base, body, tcx).ty; + match ty.kind { ty::Adt(def, _) if def.is_union() => { // Different fields of a union, we are basically stuck. debug!("place_element_conflict: STUCK-UNION"); @@ -493,7 +499,7 @@ fn place_projection_conflict<'tcx>( // element (like -1 in Python) and `min_length` the first. // Therefore, `min_length - offset_from_end` gives the minimal possible // offset from the beginning - if *offset_from_begin >= min_length - offset_from_end { + if *offset_from_begin >= *min_length - *offset_from_end { debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE"); Overlap::EqualOrDisjoint } else { @@ -538,8 +544,8 @@ fn place_projection_conflict<'tcx>( | (ProjectionElem::Subslice { .. }, _) | (ProjectionElem::Downcast(..), _) => bug!( "mismatched projections in place_element_conflict: {:?} and {:?}", - pi1, - pi2 + pi1_elem, + pi2_elem ), } } diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs index ecafd4eb1157e..a46a1cc5647a9 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/src/librustc_mir/borrow_check/prefixes.rs @@ -19,17 +19,9 @@ pub trait IsPrefixOf<'cx, 'tcx> { impl<'cx, 'tcx> IsPrefixOf<'cx, 'tcx> for PlaceRef<'cx, 'tcx> { fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool { - let mut cursor = other.projection; - loop { - if self.projection == cursor { - return self.base == other.base; - } - - match cursor { - None => return false, - Some(proj) => cursor = &proj.base, - } - } + self.base == other.base + && self.projection.len() <= other.projection.len() + && self.projection == &other.projection[..self.projection.len()] } } @@ -81,112 +73,113 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { // downcasts here, but may return a base of a downcast). 'cursor: loop { - let proj = match &cursor { + match &cursor { PlaceRef { base: PlaceBase::Local(_), - projection: None, + projection: [], } | // search yielded this leaf PlaceRef { base: PlaceBase::Static(_), - projection: None, + projection: [], } => { self.next = None; return Some(cursor); } PlaceRef { base: _, - projection: Some(proj), - } => proj, - }; - - match proj.elem { - ProjectionElem::Field(_ /*field*/, _ /*ty*/) => { - // FIXME: add union handling - self.next = Some(PlaceRef { - base: cursor.base, - projection: &proj.base, - }); - return Some(cursor); - } - ProjectionElem::Downcast(..) | - ProjectionElem::Subslice { .. } | - ProjectionElem::ConstantIndex { .. } | - ProjectionElem::Index(_) => { - cursor = PlaceRef { - base: cursor.base, - projection: &proj.base, - }; - continue 'cursor; - } - ProjectionElem::Deref => { - // (handled below) - } - } - - assert_eq!(proj.elem, ProjectionElem::Deref); - - match self.kind { - PrefixSet::Shallow => { - // shallow prefixes are found by stripping away - // fields, but stop at *any* dereference. - // So we can just stop the traversal now. - self.next = None; - return Some(cursor); - } - PrefixSet::All => { - // all prefixes: just blindly enqueue the base - // of the projection - self.next = Some(PlaceRef { - base: cursor.base, - projection: &proj.base, - }); - return Some(cursor); - } - PrefixSet::Supporting => { - // fall through! - } - } - - assert_eq!(self.kind, PrefixSet::Supporting); - // supporting prefixes: strip away fields and - // derefs, except we stop at the deref of a shared - // reference. - - let ty = Place::ty_from(cursor.base, &proj.base, self.body, self.tcx).ty; - match ty.sty { - ty::RawPtr(_) | - ty::Ref( - _, /*rgn*/ - _, /*ty*/ - hir::MutImmutable - ) => { - // don't continue traversing over derefs of raw pointers or shared borrows. - self.next = None; - return Some(cursor); - } - - ty::Ref( - _, /*rgn*/ - _, /*ty*/ - hir::MutMutable, - ) => { - self.next = Some(PlaceRef { - base: cursor.base, - projection: &proj.base, - }); - return Some(cursor); - } - - ty::Adt(..) if ty.is_box() => { - self.next = Some(PlaceRef { - base: cursor.base, - projection: &proj.base, - }); - return Some(cursor); + projection: [proj_base @ .., elem], + } => { + match elem { + ProjectionElem::Field(_ /*field*/, _ /*ty*/) => { + // FIXME: add union handling + self.next = Some(PlaceRef { + base: cursor.base, + projection: proj_base, + }); + return Some(cursor); + } + ProjectionElem::Downcast(..) | + ProjectionElem::Subslice { .. } | + ProjectionElem::ConstantIndex { .. } | + ProjectionElem::Index(_) => { + cursor = PlaceRef { + base: cursor.base, + projection: proj_base, + }; + continue 'cursor; + } + ProjectionElem::Deref => { + // (handled below) + } + } + + assert_eq!(*elem, ProjectionElem::Deref); + + match self.kind { + PrefixSet::Shallow => { + // Shallow prefixes are found by stripping away + // fields, but stop at *any* dereference. + // So we can just stop the traversal now. + self.next = None; + return Some(cursor); + } + PrefixSet::All => { + // All prefixes: just blindly enqueue the base + // of the projection. + self.next = Some(PlaceRef { + base: cursor.base, + projection: proj_base, + }); + return Some(cursor); + } + PrefixSet::Supporting => { + // Fall through! + } + } + + assert_eq!(self.kind, PrefixSet::Supporting); + // Supporting prefixes: strip away fields and + // derefs, except we stop at the deref of a shared + // reference. + + let ty = Place::ty_from(cursor.base, proj_base, self.body, self.tcx).ty; + match ty.kind { + ty::RawPtr(_) | + ty::Ref( + _, /*rgn*/ + _, /*ty*/ + hir::MutImmutable + ) => { + // don't continue traversing over derefs of raw pointers or shared + // borrows. + self.next = None; + return Some(cursor); + } + + ty::Ref( + _, /*rgn*/ + _, /*ty*/ + hir::MutMutable, + ) => { + self.next = Some(PlaceRef { + base: cursor.base, + projection: proj_base, + }); + return Some(cursor); + } + + ty::Adt(..) if ty.is_box() => { + self.next = Some(PlaceRef { + base: cursor.base, + projection: proj_base, + }); + return Some(cursor); + } + + _ => panic!("unknown type fed to Projection Deref."), + } } - - _ => panic!("unknown type fed to Projection Deref."), } } } diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs index 2587d14a73a8f..695080dfe23d9 100644 --- a/src/librustc_mir/borrow_check/used_muts.rs +++ b/src/librustc_mir/borrow_check/used_muts.rs @@ -89,7 +89,7 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc _location: Location, ) { match &statement.kind { - StatementKind::Assign(into, _) => { + StatementKind::Assign(box(into, _)) => { if let PlaceBase::Local(local) = into.base { debug!( "visit_statement: statement={:?} local={:?} \ @@ -120,7 +120,7 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc ); if let Place { base: PlaceBase::Local(user_local), - projection: None, + projection: box [], } = path.place { self.mbcx.used_mut.insert(user_local); } diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 7ea08b15b443d..7353ca9285ddb 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -98,7 +98,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { initializer, lint_level } => { - let ignores_expr_result = if let PatternKind::Wild = *pattern.kind { + let ignores_expr_result = if let PatKind::Wild = *pattern.kind { true } else { false diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 778d1e71cedfc..3ed6b4ff34678 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -37,7 +37,7 @@ impl<'tcx> CFG<'tcx> { rvalue: Rvalue<'tcx>) { self.push(block, Statement { source_info, - kind: StatementKind::Assign(place.clone(), box rvalue) + kind: StatementKind::Assign(box(place.clone(), rvalue)) }); } diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs index 5197981a85cb8..39bdc871d83c6 100644 --- a/src/librustc_mir/build/expr/as_constant.rs +++ b/src/librustc_mir/build/expr/as_constant.rs @@ -38,9 +38,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { inferred_ty: ty, }) }); + assert_eq!(literal.ty, ty); Constant { span, - ty, user_ty, literal, } diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 7005f274e0e7d..60fe37e26e9ad 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -6,13 +6,79 @@ use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::hair::*; use rustc::mir::interpret::{PanicInfo::BoundsCheck}; use rustc::mir::*; -use rustc::ty::{CanonicalUserTypeAnnotation, Variance}; +use rustc::ty::{CanonicalUserTypeAnnotation, Ty, Variance}; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; + +/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a +/// place by pushing more and more projections onto the end, and then convert the final set into a +/// place using the `into_place` method. +/// +/// This is used internally when building a place for an expression like `a.b.c`. The fields `b` +/// and `c` can be progressively pushed onto the place builder that is created when converting `a`. +#[derive(Clone)] +struct PlaceBuilder<'tcx> { + base: PlaceBase<'tcx>, + projection: Vec>, +} + +impl PlaceBuilder<'tcx> { + fn into_place(self) -> Place<'tcx> { + Place { + base: self.base, + projection: self.projection.into_boxed_slice(), + } + } + + fn field(self, f: Field, ty: Ty<'tcx>) -> Self { + self.project(PlaceElem::Field(f, ty)) + } + + fn deref(self) -> Self { + self.project(PlaceElem::Deref) + } + + fn index(self, index: Local) -> Self { + self.project(PlaceElem::Index(index)) + } + + fn project(mut self, elem: PlaceElem<'tcx>) -> Self { + self.projection.push(elem); + self + } +} + +impl From for PlaceBuilder<'tcx> { + fn from(local: Local) -> Self { + Self { + base: local.into(), + projection: Vec::new(), + } + } +} + +impl From> for PlaceBuilder<'tcx> { + fn from(base: PlaceBase<'tcx>) -> Self { + Self { + base, + projection: Vec::new(), + } + } +} impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, yielding a place that we can move from etc. - pub fn as_place(&mut self, block: BasicBlock, expr: M) -> BlockAnd> + pub fn as_place(&mut self, mut block: BasicBlock, expr: M) -> BlockAnd> + where + M: Mirror<'tcx, Output = Expr<'tcx>>, + { + let place_builder = unpack!(block = self.as_place_builder(block, expr)); + block.and(place_builder.into_place()) + } + + /// This is used when constructing a compound `Place`, so that we can avoid creating + /// intermediate `Place` values until we know the full set of projections. + fn as_place_builder(&mut self, block: BasicBlock, expr: M) -> BlockAnd> where M: Mirror<'tcx, Output = Expr<'tcx>>, { @@ -25,7 +91,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// place. The place itself may or may not be mutable: /// * If this expr is a place expr like a.b, then we will return that place. /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary. - pub fn as_read_only_place(&mut self, block: BasicBlock, expr: M) -> BlockAnd> + pub fn as_read_only_place(&mut self, mut block: BasicBlock, expr: M) -> BlockAnd> + where + M: Mirror<'tcx, Output = Expr<'tcx>>, + { + let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr)); + block.and(place_builder.into_place()) + } + + /// This is used when constructing a compound `Place`, so that we can avoid creating + /// intermediate `Place` values until we know the full set of projections. + /// Mutability note: The caller of this method promises only to read from the resulting + /// place. The place itself may or may not be mutable: + /// * If this expr is a place expr like a.b, then we will return that place. + /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary. + fn as_read_only_place_builder( + &mut self, + block: BasicBlock, + expr: M, + ) -> BlockAnd> where M: Mirror<'tcx, Output = Expr<'tcx>>, { @@ -38,7 +122,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mut block: BasicBlock, expr: Expr<'tcx>, mutability: Mutability, - ) -> BlockAnd> { + ) -> BlockAnd> { debug!( "expr_as_place(block={:?}, expr={:?}, mutability={:?})", block, expr, mutability @@ -54,25 +138,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { value, } => this.in_scope((region_scope, source_info), lint_level, |this| { if mutability == Mutability::Not { - this.as_read_only_place(block, value) + this.as_read_only_place_builder(block, value) } else { - this.as_place(block, value) + this.as_place_builder(block, value) } }), ExprKind::Field { lhs, name } => { - let place = unpack!(block = this.as_place(block, lhs)); - let place = place.field(name, expr.ty); - block.and(place) + let place_builder = unpack!(block = this.as_place_builder(block, lhs)); + block.and(place_builder.field(name, expr.ty)) } ExprKind::Deref { arg } => { - let place = unpack!(block = this.as_place(block, arg)); - let place = place.deref(); - block.and(place) + let place_builder = unpack!(block = this.as_place_builder(block, arg)); + block.and(place_builder.deref()) } ExprKind::Index { lhs, index } => { let (usize_ty, bool_ty) = (this.hir.usize_ty(), this.hir.bool_ty()); - let slice = unpack!(block = this.as_place(block, lhs)); + let place_builder = unpack!(block = this.as_place_builder(block, lhs)); // Making this a *fresh* temporary also means we do not have to worry about // the index changing later: Nothing will ever change this temporary. // The "retagging" transformation (for Stacked Borrows) relies on this. @@ -83,6 +165,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Mutability::Not, )); + let slice = place_builder.clone().into_place(); // bounds check: let (len, lt) = ( this.temp(usize_ty.clone(), expr_span), @@ -92,7 +175,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, // len = len(slice) &len, - Rvalue::Len(slice.clone()), + Rvalue::Len(slice), ); this.cfg.push_assign( block, @@ -110,29 +193,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { index: Operand::Copy(Place::from(idx)), }; let success = this.assert(block, Operand::Move(lt), true, msg, expr_span); - success.and(slice.index(idx)) + success.and(place_builder.index(idx)) } - ExprKind::SelfRef => block.and(Place::from(Local::new(1))), + ExprKind::SelfRef => block.and(PlaceBuilder::from(Local::new(1))), ExprKind::VarRef { id } => { - let place = if this.is_bound_var_in_guard(id) { + let place_builder = if this.is_bound_var_in_guard(id) { let index = this.var_local_id(id, RefWithinGuard); - Place::from(index).deref() + PlaceBuilder::from(index).deref() } else { let index = this.var_local_id(id, OutsideGuard); - Place::from(index) + PlaceBuilder::from(index) }; - block.and(place) + block.and(place_builder) } - ExprKind::StaticRef { id } => block.and(Place { - base: PlaceBase::Static(Box::new(Static { + ExprKind::StaticRef { id } => block.and(PlaceBuilder::from( + PlaceBase::Static(Box::new(Static { ty: expr.ty, - kind: StaticKind::Static(id), - })), - projection: None, - }), + kind: StaticKind::Static, + def_id: id, + })) + )), ExprKind::PlaceTypeAscription { source, user_ty } => { - let place = unpack!(block = this.as_place(block, source)); + let place_builder = unpack!(block = this.as_place_builder(block, source)); if let Some(user_ty) = user_ty { let annotation_index = this.canonical_user_type_annotations.push( CanonicalUserTypeAnnotation { @@ -141,19 +224,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { inferred_ty: expr.ty, } ); + + let place = place_builder.clone().into_place(); this.cfg.push( block, Statement { source_info, kind: StatementKind::AscribeUserType( - place.clone(), + box( + place, + UserTypeProjection { base: annotation_index, projs: vec![], } + ), Variance::Invariant, - box UserTypeProjection { base: annotation_index, projs: vec![], }, ), }, ); } - block.and(place) + block.and(place_builder) } ExprKind::ValueTypeAscription { source, user_ty } => { let source = this.hir.mirror(source); @@ -173,14 +260,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Statement { source_info, kind: StatementKind::AscribeUserType( - Place::from(temp.clone()), + box( + Place::from(temp.clone()), + UserTypeProjection { base: annotation_index, projs: vec![], }, + ), Variance::Invariant, - box UserTypeProjection { base: annotation_index, projs: vec![], }, ), }, ); } - block.and(Place::from(temp)) + block.and(PlaceBuilder::from(temp)) } ExprKind::Array { .. } @@ -216,7 +305,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }); let temp = unpack!(block = this.as_temp(block, expr.temp_lifetime, expr, mutability)); - block.and(Place::from(temp)) + block.and(PlaceBuilder::from(temp)) } } } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index ec061e7453577..87d95a751534d 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -1,7 +1,7 @@ //! See docs in `build/expr/mod.rs`. use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use crate::build::expr::category::{Category, RvalueFunc}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; @@ -128,7 +128,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr_span, scope, result, - expr.ty, ); } @@ -500,14 +499,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mutability = match arg_place { Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } => this.local_decls[local].mutability, Place { base: PlaceBase::Local(local), - projection: Some(box Projection { - base: None, - elem: ProjectionElem::Deref, - }) + projection: box [ProjectionElem::Deref], } => { debug_assert!( this.local_decls[local].is_ref_for_guard(), @@ -517,24 +513,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } Place { ref base, - projection: Some(box Projection { - base: ref base_proj, - elem: ProjectionElem::Field(upvar_index, _), - }), + projection: box [ref proj_base @ .., ProjectionElem::Field(upvar_index, _)], } | Place { ref base, - projection: Some(box Projection { - base: Some(box Projection { - base: ref base_proj, - elem: ProjectionElem::Field(upvar_index, _), - }), - elem: ProjectionElem::Deref, - }), + projection: box [ + ref proj_base @ .., + ProjectionElem::Field(upvar_index, _), + ProjectionElem::Deref + ], } => { let place = PlaceRef { base, - projection: base_proj, + projection: proj_base, }; // Not projected from the implicit `self` in a closure. @@ -577,7 +568,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { upvar_span, temp_lifetime, temp, - upvar_ty, ); } @@ -591,7 +581,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let n = (!0u128) >> (128 - bits); let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty); - self.literal_operand(span, ty, literal) + self.literal_operand(span, literal) } // Helper to get the minimum value of the appropriate type @@ -602,6 +592,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let n = 1 << (bits - 1); let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty); - self.literal_operand(span, ty, literal) + self.literal_operand(span, literal) } } diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index dbcc330eca382..18332ed68f8bd 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -103,7 +103,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr_span, temp_lifetime, temp, - expr_ty, DropKind::Storage, ); } @@ -117,7 +116,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr_span, temp_lifetime, temp, - expr_ty, DropKind::Value, ); } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 2815361a64760..8a6bc5a2a764e 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -79,17 +79,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::LogicalOp { op, lhs, rhs } => { // And: // - // [block: If(lhs)] -true-> [else_block: dest = (rhs)] - // | (false) - // [shortcurcuit_block: dest = false] + // [block: If(lhs)] -true-> [else_block: If(rhs)] -true-> [true_block] + // | | (false) + // +----------false-----------+------------------> [false_block] // // Or: // - // [block: If(lhs)] -false-> [else_block: dest = (rhs)] - // | (true) - // [shortcurcuit_block: dest = true] + // [block: If(lhs)] -false-> [else_block: If(rhs)] -true-> [true_block] + // | (true) | (false) + // [true_block] [false_block] - let (shortcircuit_block, mut else_block, join_block) = ( + let (true_block, false_block, mut else_block, join_block) = ( + this.cfg.start_new_block(), this.cfg.start_new_block(), this.cfg.start_new_block(), this.cfg.start_new_block(), @@ -97,41 +98,45 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let lhs = unpack!(block = this.as_local_operand(block, lhs)); let blocks = match op { - LogicalOp::And => (else_block, shortcircuit_block), - LogicalOp::Or => (shortcircuit_block, else_block), + LogicalOp::And => (else_block, false_block), + LogicalOp::Or => (true_block, else_block), }; let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1); this.cfg.terminate(block, source_info, term); + let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs)); + let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block); + this.cfg.terminate(else_block, source_info, term); + this.cfg.push_assign_constant( - shortcircuit_block, + true_block, source_info, destination, Constant { span: expr_span, - ty: this.hir.bool_ty(), user_ty: None, - literal: match op { - LogicalOp::And => this.hir.false_literal(), - LogicalOp::Or => this.hir.true_literal(), - }, + literal: this.hir.true_literal(), }, ); - this.cfg.terminate( - shortcircuit_block, + + this.cfg.push_assign_constant( + false_block, source_info, - TerminatorKind::Goto { target: join_block }, + destination, + Constant { + span: expr_span, + user_ty: None, + literal: this.hir.false_literal(), + }, ); - let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs)); - this.cfg.push_assign( - else_block, + this.cfg.terminate( + true_block, source_info, - destination, - Rvalue::Use(rhs), + TerminatorKind::Goto { target: join_block }, ); this.cfg.terminate( - else_block, + false_block, source_info, TerminatorKind::Goto { target: join_block }, ); @@ -191,7 +196,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { exit_block.unit() } ExprKind::Call { ty, fun, args, from_hir_call } => { - let intrinsic = match ty.sty { + let intrinsic = match ty.kind { ty::FnDef(def_id, _) => { let f = ty.fn_sig(this.hir.tcx()); if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { @@ -239,6 +244,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let success = this.cfg.start_new_block(); let cleanup = this.diverge_cleanup(); + + this.record_operands_moved(&args); + this.cfg.terminate( block, source_info, @@ -296,7 +304,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Create a "fake" temporary variable so that we check that the // value is Sized. Usually, this is caught in type checking, but // in the case of box expr there is no such check. - if destination.projection.is_some() { + if !destination.projection.is_empty() { this.local_decls .push(LocalDecl::new_temp(expr.ty, expr.span)); } diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index cf3d8778da193..0cd32acdb665b 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -159,7 +159,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let ExprKind::Block { body } = expr.kind { if let Some(tail_expr) = &body.expr { let mut expr = tail_expr; - while let rustc::hir::ExprKind::Block(subblock, _label) = &expr.node { + while let rustc::hir::ExprKind::Block(subblock, _label) = &expr.kind { if let Some(subtail_expr) = &subblock.expr { expr = subtail_expr } else { diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index d72b0addae915..2e451fc88d95c 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -15,7 +15,7 @@ use rustc::mir::*; use rustc::middle::region; use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty}; use rustc::ty::layout::VariantIdx; -use rustc_data_structures::bit_set::BitSet; +use rustc_index::bit_set::BitSet; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use syntax::ast::Name; use syntax_pos::Span; @@ -135,14 +135,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info, kind: StatementKind::FakeRead( FakeReadCause::ForMatchedPlace, - scrutinee_place.clone(), + box(scrutinee_place.clone()), ), }); // Step 2. Create the otherwise and prebinding blocks. // create binding start block for link them by false edges - let candidate_count = arms.iter().map(|c| c.patterns.len()).sum::(); + let candidate_count = arms.iter().map(|c| c.top_pats_hack().len()).sum::(); let pre_binding_blocks: Vec<_> = (0..candidate_count) .map(|_| self.cfg.start_new_block()) .collect(); @@ -159,7 +159,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .map(|arm| { let arm_has_guard = arm.guard.is_some(); match_has_guard |= arm_has_guard; - let arm_candidates: Vec<_> = arm.patterns + let arm_candidates: Vec<_> = arm.top_pats_hack() .iter() .zip(candidate_pre_binding_blocks.by_ref()) .map( @@ -238,7 +238,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let scope = this.declare_bindings( None, arm.span, - &arm.patterns[0], + &arm.top_pats_hack()[0], ArmHasGuard(arm.guard.is_some()), Some((Some(&scrutinee_place), scrutinee_span)), ); @@ -298,12 +298,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(super) fn expr_into_pattern( &mut self, mut block: BasicBlock, - irrefutable_pat: Pattern<'tcx>, + irrefutable_pat: Pat<'tcx>, initializer: ExprRef<'tcx>, ) -> BlockAnd<()> { match *irrefutable_pat.kind { // Optimize the case of `let x = ...` to write directly into `x` - PatternKind::Binding { + PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, @@ -320,7 +320,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, Statement { source_info, - kind: StatementKind::FakeRead(FakeReadCause::ForLet, place), + kind: StatementKind::FakeRead(FakeReadCause::ForLet, box(place)), }, ); @@ -336,9 +336,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // test works with uninitialized values in a rather // dubious way, so it may be that the test is kind of // broken. - PatternKind::AscribeUserType { - subpattern: Pattern { - kind: box PatternKind::Binding { + PatKind::AscribeUserType { + subpattern: Pat { + kind: box PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, @@ -362,12 +362,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, Statement { source_info: pattern_source_info, - kind: StatementKind::FakeRead(FakeReadCause::ForLet, place.clone()), + kind: StatementKind::FakeRead(FakeReadCause::ForLet, box(place.clone())), }, ); let ty_source_info = self.source_info(user_ty_span); - let user_ty = box pat_ascription_ty.user_ty( + let user_ty = pat_ascription_ty.user_ty( &mut self.canonical_user_type_annotations, place.ty(&self.local_decls, self.hir.tcx()).ty, ty_source_info.span, @@ -377,7 +377,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Statement { source_info: ty_source_info, kind: StatementKind::AscribeUserType( - place, + box( + place, + user_ty, + ), // We always use invariant as the variance here. This is because the // variance field from the ascription refers to the variance to use // when applying the type to the value being matched, but this @@ -393,7 +396,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // contrast, is intended to be used to relate `T` to the type of // ``. ty::Variance::Invariant, - user_ty, ), }, ); @@ -412,7 +414,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn place_into_pattern( &mut self, block: BasicBlock, - irrefutable_pat: Pattern<'tcx>, + irrefutable_pat: Pat<'tcx>, initializer: &Place<'tcx>, set_match_place: bool, ) -> BlockAnd<()> { @@ -484,7 +486,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, mut visibility_scope: Option, scope_span: Span, - pattern: &Pattern<'tcx>, + pattern: &Pat<'tcx>, has_guard: ArmHasGuard, opt_match_place: Option<(Option<&Place<'tcx>>, Span)>, ) -> Option { @@ -533,28 +535,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { kind: StatementKind::StorageLive(local_id), }, ); - let var_ty = self.local_decls[local_id].ty; let region_scope = self.hir.region_scope_tree.var_scope(var.local_id); - self.schedule_drop(span, region_scope, local_id, var_ty, DropKind::Storage); + self.schedule_drop(span, region_scope, local_id, DropKind::Storage); Place::from(local_id) } pub fn schedule_drop_for_binding(&mut self, var: HirId, span: Span, for_guard: ForGuard) { let local_id = self.var_local_id(var, for_guard); - let var_ty = self.local_decls[local_id].ty; let region_scope = self.hir.region_scope_tree.var_scope(var.local_id); self.schedule_drop( span, region_scope, local_id, - var_ty, DropKind::Value, ); } pub(super) fn visit_bindings( &mut self, - pattern: &Pattern<'tcx>, + pattern: &Pat<'tcx>, pattern_user_ty: UserTypeProjections, f: &mut impl FnMut( &mut Self, @@ -569,7 +568,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) { debug!("visit_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty); match *pattern.kind { - PatternKind::Binding { + PatKind::Binding { mutability, name, mode, @@ -584,12 +583,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - PatternKind::Array { + PatKind::Array { ref prefix, ref slice, ref suffix, } - | PatternKind::Slice { + | PatKind::Slice { ref prefix, ref slice, ref suffix, @@ -607,13 +606,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {} + PatKind::Constant { .. } | PatKind::Range { .. } | PatKind::Wild => {} - PatternKind::Deref { ref subpattern } => { + PatKind::Deref { ref subpattern } => { self.visit_bindings(subpattern, pattern_user_ty.deref(), f); } - PatternKind::AscribeUserType { + PatKind::AscribeUserType { ref subpattern, ascription: hair::pattern::Ascription { ref user_ty, @@ -642,7 +641,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.visit_bindings(subpattern, subpattern_user_ty, f) } - PatternKind::Leaf { ref subpatterns } => { + PatKind::Leaf { ref subpatterns } => { for subpattern in subpatterns { let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field); debug!("visit_bindings: subpattern_user_ty={:?}", subpattern_user_ty); @@ -650,13 +649,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - PatternKind::Variant { adt_def, substs: _, variant_index, ref subpatterns } => { + PatKind::Variant { adt_def, substs: _, variant_index, ref subpatterns } => { for subpattern in subpatterns { let subpattern_user_ty = pattern_user_ty.clone().variant( adt_def, variant_index, subpattern.field); self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f); } } + PatKind::Or { ref pats } => { + for pat in pats { + self.visit_bindings(&pat, pattern_user_ty.clone(), f); + } + } } } } @@ -701,7 +705,7 @@ struct Binding<'tcx> { struct Ascription<'tcx> { span: Span, source: Place<'tcx>, - user_ty: PatternTypeProjection<'tcx>, + user_ty: PatTyProj<'tcx>, variance: ty::Variance, } @@ -711,7 +715,7 @@ pub struct MatchPair<'pat, 'tcx> { place: Place<'tcx>, // ... must match this pattern. - pattern: &'pat Pattern<'tcx>, + pattern: &'pat Pat<'tcx>, } #[derive(Clone, Debug, PartialEq)] @@ -753,7 +757,7 @@ enum TestKind<'tcx> { }, /// Test whether the value falls within an inclusive or exclusive range - Range(PatternRange<'tcx>), + Range(PatRange<'tcx>), /// Test length of the slice is equal to len Len { @@ -937,16 +941,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { for Binding { source, .. } in matched_candidates.iter().flat_map(|candidate| &candidate.bindings) { - let mut cursor = &source.projection; - while let Some(box Projection { base, elem }) = cursor { - cursor = base; - if let ProjectionElem::Deref = elem { - fake_borrows.insert(Place { - base: source.base.clone(), - projection: cursor.clone(), - }); - break; - } + if let Some(i) = + source.projection.iter().rposition(|elem| *elem == ProjectionElem::Deref) + { + let proj_base = &source.projection[..i]; + + fake_borrows.insert(Place { + base: source.base.clone(), + projection: proj_base.to_vec().into_boxed_slice(), + }); } } } @@ -1290,18 +1293,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Insert a Shallow borrow of the prefixes of any fake borrows. for place in fake_borrows { - let mut prefix_cursor = &place.projection; - while let Some(box Projection { base, elem }) = prefix_cursor { + let mut cursor = &*place.projection; + while let [proj_base @ .., elem] = cursor { + cursor = proj_base; + if let ProjectionElem::Deref = elem { // Insert a shallow borrow after a deref. For other // projections the borrow of prefix_cursor will // conflict with any mutation of base. all_fake_borrows.push(PlaceRef { base: &place.base, - projection: base, + projection: proj_base, }); } - prefix_cursor = base; } all_fake_borrows.push(place.as_ref()); @@ -1332,7 +1336,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } /////////////////////////////////////////////////////////////////////////// -// Pattern binding - used for `let` and function parameters as well. +// Pat binding - used for `let` and function parameters as well. impl<'a, 'tcx> Builder<'a, 'tcx> { /// Initializes each of the bindings from the candidate by @@ -1340,13 +1344,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// any, and then branches to the arm. Returns the block for the case where /// the guard fails. /// - /// Note: we check earlier that if there is a guard, there cannot be move - /// bindings (unless feature(bind_by_move_pattern_guards) is used). This - /// isn't really important for the self-consistency of this fn, but the - /// reason for it should be clear: after we've done the assignments, if - /// there were move bindings, further tests would be a use-after-move. - /// bind_by_move_pattern_guards avoids this by only moving the binding once - /// the guard has evaluated to true (see below). + /// Note: we do not check earlier that if there is a guard, + /// there cannot be move bindings. We avoid a use-after-move by only + /// moving the binding once the guard has evaluated to true (see below). fn bind_and_guard_matched_candidate<'pat>( &mut self, candidate: Candidate<'pat, 'tcx>, @@ -1488,7 +1488,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { BorrowKind::Shallow, Place { base: place.base.clone(), - projection: place.projection.clone(), + projection: place.projection.to_vec().into_boxed_slice(), }, ); self.cfg.push_assign( @@ -1519,7 +1519,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info: guard_end, kind: StatementKind::FakeRead( FakeReadCause::ForMatchGuard, - Place::from(temp), + box(Place::from(temp)), ), }); } @@ -1569,7 +1569,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { post_guard_block, Statement { source_info: guard_end, - kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, place), + kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, box(place)), }, ); } @@ -1602,7 +1602,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ascription.user_ty, ); - let user_ty = box ascription.user_ty.clone().user_ty( + let user_ty = ascription.user_ty.clone().user_ty( &mut self.canonical_user_type_annotations, ascription.source.ty(&self.local_decls, self.hir.tcx()).ty, source_info.span @@ -1612,9 +1612,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Statement { source_info, kind: StatementKind::AscribeUserType( - ascription.source.clone(), + box( + ascription.source.clone(), + user_ty, + ), ascription.variance, - user_ty, ), }, ); diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index d9b748f71f011..3826e5e3ba5e6 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -57,7 +57,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { -> Result<(), MatchPair<'pat, 'tcx>> { let tcx = self.hir.tcx(); match *match_pair.pattern.kind { - PatternKind::AscribeUserType { + PatKind::AscribeUserType { ref subpattern, ascription: hair::pattern::Ascription { variance, @@ -79,12 +79,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Ok(()) } - PatternKind::Wild => { + PatKind::Wild => { // nothing left to do Ok(()) } - PatternKind::Binding { name, mutability, mode, var, ty, ref subpattern } => { + PatKind::Binding { name, mutability, mode, var, ty, ref subpattern } => { candidate.bindings.push(Binding { name, mutability, @@ -103,13 +103,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Ok(()) } - PatternKind::Constant { .. } => { + PatKind::Constant { .. } => { // FIXME normalize patterns when possible Err(match_pair) } - PatternKind::Range(PatternRange { lo, hi, ty, end }) => { - let (range, bias) = match ty.sty { + PatKind::Range(PatRange { lo, hi, end }) => { + let (range, bias) = match lo.ty.kind { ty::Char => { (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0) } @@ -144,7 +144,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Err(match_pair) } - PatternKind::Slice { ref prefix, ref slice, ref suffix } => { + PatKind::Slice { ref prefix, ref slice, ref suffix } => { if prefix.is_empty() && slice.is_some() && suffix.is_empty() { // irrefutable self.prefix_slice_suffix(&mut candidate.match_pairs, @@ -158,7 +158,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { + PatKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { let irrefutable = adt_def.variants.iter_enumerated().all(|(i, v)| { i == variant_index || { self.hir.tcx().features().exhaustive_patterns && @@ -174,7 +174,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - PatternKind::Array { ref prefix, ref slice, ref suffix } => { + PatKind::Array { ref prefix, ref slice, ref suffix } => { self.prefix_slice_suffix(&mut candidate.match_pairs, &match_pair.place, prefix, @@ -183,18 +183,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Ok(()) } - PatternKind::Leaf { ref subpatterns } => { + PatKind::Leaf { ref subpatterns } => { // tuple struct, match subpats (if any) candidate.match_pairs .extend(self.field_match_pairs(match_pair.place, subpatterns)); Ok(()) } - PatternKind::Deref { ref subpattern } => { + PatKind::Deref { ref subpattern } => { let place = match_pair.place.deref(); candidate.match_pairs.push(MatchPair::new(place, subpattern)); Ok(()) } + + PatKind::Or { .. } => { + Err(match_pair) + } } } } diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 1c93abd40ded2..a04c989e6e0de 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -9,9 +9,9 @@ use crate::build::Builder; use crate::build::matches::{Candidate, MatchPair, Test, TestKind}; use crate::hair::*; use crate::hair::pattern::compare_const_vals; -use rustc_data_structures::bit_set::BitSet; +use rustc_index::bit_set::BitSet; use rustc_data_structures::fx::FxHashMap; -use rustc::ty::{self, Ty, adjustment::{PointerCast}}; +use rustc::ty::{self, Ty, adjustment::PointerCast}; use rustc::ty::util::IntTypeExt; use rustc::ty::layout::VariantIdx; use rustc::mir::*; @@ -26,7 +26,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// It is a bug to call this with a simplifiable pattern. pub fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> { match *match_pair.pattern.kind { - PatternKind::Variant { ref adt_def, substs: _, variant_index: _, subpatterns: _ } => { + PatKind::Variant { ref adt_def, substs: _, variant_index: _, subpatterns: _ } => { Test { span: match_pair.pattern.span, kind: TestKind::Switch { @@ -36,7 +36,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - PatternKind::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => { + PatKind::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => { // For integers, we use a `SwitchInt` match, which allows // us to handle more cases. Test { @@ -52,7 +52,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - PatternKind::Constant { value } => { + PatKind::Constant { value } => { Test { span: match_pair.pattern.span, kind: TestKind::Eq { @@ -62,15 +62,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - PatternKind::Range(range) => { - assert!(range.ty == match_pair.pattern.ty); + PatKind::Range(range) => { + assert_eq!(range.lo.ty, match_pair.pattern.ty); + assert_eq!(range.hi.ty, match_pair.pattern.ty); Test { span: match_pair.pattern.span, kind: TestKind::Range(range), } } - PatternKind::Slice { ref prefix, ref slice, ref suffix } => { + PatKind::Slice { ref prefix, ref slice, ref suffix } => { let len = prefix.len() + suffix.len(); let op = if slice.is_some() { BinOp::Ge @@ -83,12 +84,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - PatternKind::AscribeUserType { .. } | - PatternKind::Array { .. } | - PatternKind::Wild | - PatternKind::Binding { .. } | - PatternKind::Leaf { .. } | - PatternKind::Deref { .. } => { + PatKind::AscribeUserType { .. } | + PatKind::Array { .. } | + PatKind::Wild | + PatKind::Or { .. } | + PatKind::Binding { .. } | + PatKind::Leaf { .. } | + PatKind::Deref { .. } => { self.error_simplifyable(match_pair) } } @@ -108,7 +110,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; match *match_pair.pattern.kind { - PatternKind::Constant { value } => { + PatKind::Constant { value } => { indices.entry(value) .or_insert_with(|| { options.push(value.eval_bits( @@ -118,21 +120,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }); true } - PatternKind::Variant { .. } => { + PatKind::Variant { .. } => { panic!("you should have called add_variants_to_switch instead!"); } - PatternKind::Range(range) => { + PatKind::Range(range) => { // Check that none of the switch values are in the range. self.values_not_contained_in_range(range, indices) .unwrap_or(false) } - PatternKind::Slice { .. } | - PatternKind::Array { .. } | - PatternKind::Wild | - PatternKind::Binding { .. } | - PatternKind::AscribeUserType { .. } | - PatternKind::Leaf { .. } | - PatternKind::Deref { .. } => { + PatKind::Slice { .. } | + PatKind::Array { .. } | + PatKind::Wild | + PatKind::Or { .. } | + PatKind::Binding { .. } | + PatKind::AscribeUserType { .. } | + PatKind::Leaf { .. } | + PatKind::Deref { .. } => { // don't know how to add these patterns to a switch false } @@ -151,7 +154,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; match *match_pair.pattern.kind { - PatternKind::Variant { adt_def: _ , variant_index, .. } => { + PatKind::Variant { adt_def: _ , variant_index, .. } => { // We have a pattern testing for variant `variant_index` // set the corresponding index to true variants.insert(variant_index); @@ -226,7 +229,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestKind::SwitchInt { switch_ty, ref options, indices: _ } => { let target_blocks = make_target_blocks(self); - let terminator = if switch_ty.sty == ty::Bool { + let terminator = if switch_ty.kind == ty::Bool { assert!(options.len() > 0 && options.len() <= 2); if let [first_bb, second_bb] = *target_blocks { let (true_bb, false_bb) = match options[0] { @@ -270,8 +273,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); } else { if let [success, fail] = *make_target_blocks(self) { + assert_eq!(value.ty, ty); + let expect = self.literal_operand(test.span, value); let val = Operand::Copy(place.clone()); - let expect = self.literal_operand(test.span, ty, value); self.compare(block, success, fail, source_info, BinOp::Eq, expect, val); } else { bug!("`TestKind::Eq` should have two target blocks"); @@ -279,13 +283,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - TestKind::Range(PatternRange { ref lo, ref hi, ty, ref end }) => { + TestKind::Range(PatRange { ref lo, ref hi, ref end }) => { let lower_bound_success = self.cfg.start_new_block(); let target_blocks = make_target_blocks(self); // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons. - let lo = self.literal_operand(test.span, ty, lo); - let hi = self.literal_operand(test.span, ty, hi); + let lo = self.literal_operand(test.span, lo); + let hi = self.literal_operand(test.span, hi); let val = Operand::Copy(place.clone()); if let [success, fail] = *target_blocks { @@ -387,7 +391,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) { use rustc::middle::lang_items::EqTraitLangItem; - let mut expect = self.literal_operand(source_info.span, value.ty, value); + let mut expect = self.literal_operand(source_info.span, value); let mut val = Operand::Copy(place.clone()); // If we're using `b"..."` as a pattern, we need to insert an @@ -396,8 +400,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // We want to do this even when the scrutinee is a reference to an // array, so we can call `<[u8]>::eq` rather than having to find an // `<[u8; N]>::eq`. - let unsize = |ty: Ty<'tcx>| match ty.sty { - ty::Ref(region, rty, _) => match rty.sty { + let unsize = |ty: Ty<'tcx>| match ty.kind { + ty::Ref(region, rty, _) => match rty.kind { ty::Array(inner_ty, n) => Some((region, inner_ty, n)), _ => None, }, @@ -434,13 +438,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, } - let deref_ty = match ty.sty { + let deref_ty = match ty.kind { ty::Ref(_, deref_ty, _) => deref_ty, _ => bug!("non_scalar_compare called on non-reference type: {}", ty), }; - let eq_def_id = self.hir.tcx().require_lang_item(EqTraitLangItem); - let (mty, method) = self.hir.trait_method(eq_def_id, sym::eq, deref_ty, &[deref_ty.into()]); + let eq_def_id = self.hir.tcx().require_lang_item(EqTraitLangItem, None); + let method = self.hir.trait_method(eq_def_id, sym::eq, deref_ty, &[deref_ty.into()]); let bool_ty = self.hir.bool_ty(); let eq_result = self.temp(bool_ty, source_info.span); @@ -449,7 +453,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.terminate(block, source_info, TerminatorKind::Call { func: Operand::Constant(box Constant { span: source_info.span, - ty: mty, // FIXME(#54571): This constant comes from user input (a // constant in a pattern). Are there forms where users can add @@ -530,7 +533,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // If we are performing a variant switch, then this // informs variant patterns, but nothing else. (&TestKind::Switch { adt_def: tested_adt_def, .. }, - &PatternKind::Variant { adt_def, variant_index, ref subpatterns, .. }) => { + &PatKind::Variant { adt_def, variant_index, ref subpatterns, .. }) => { assert_eq!(adt_def, tested_adt_def); self.candidate_after_variant_switch(match_pair_index, adt_def, @@ -545,10 +548,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // If we are performing a switch over integers, then this informs integer // equality, but nothing else. // - // FIXME(#29623) we could use PatternKind::Range to rule + // FIXME(#29623) we could use PatKind::Range to rule // things out here, in some cases. (&TestKind::SwitchInt { switch_ty: _, options: _, ref indices }, - &PatternKind::Constant { ref value }) + &PatKind::Constant { ref value }) if is_switch_ty(match_pair.pattern.ty) => { let index = indices[value]; self.candidate_without_match_pair(match_pair_index, candidate); @@ -556,7 +559,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } (&TestKind::SwitchInt { switch_ty: _, ref options, ref indices }, - &PatternKind::Range(range)) => { + &PatKind::Range(range)) => { let not_contained = self .values_not_contained_in_range(range, indices) .unwrap_or(false); @@ -574,7 +577,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (&TestKind::SwitchInt { .. }, _) => None, (&TestKind::Len { len: test_len, op: BinOp::Eq }, - &PatternKind::Slice { ref prefix, ref slice, ref suffix }) => { + &PatKind::Slice { ref prefix, ref slice, ref suffix }) => { let pat_len = (prefix.len() + suffix.len()) as u64; match (test_len.cmp(&pat_len), slice) { (Ordering::Equal, &None) => { @@ -607,7 +610,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } (&TestKind::Len { len: test_len, op: BinOp::Ge }, - &PatternKind::Slice { ref prefix, ref slice, ref suffix }) => { + &PatKind::Slice { ref prefix, ref slice, ref suffix }) => { // the test is `$actual_len >= test_len` let pat_len = (prefix.len() + suffix.len()) as u64; match (test_len.cmp(&pat_len), slice) { @@ -641,7 +644,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } (&TestKind::Range(test), - &PatternKind::Range(pat)) => { + &PatKind::Range(pat)) => { if test == pat { self.candidate_without_match_pair( match_pair_index, @@ -656,8 +659,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = self.hir.tcx(); - let lo = compare_const_vals(tcx, test.lo, pat.hi, self.hir.param_env, test.ty)?; - let hi = compare_const_vals(tcx, test.hi, pat.lo, self.hir.param_env, test.ty)?; + let test_ty = test.lo.ty; + let lo = compare_const_vals(tcx, test.lo, pat.hi, self.hir.param_env, test_ty)?; + let hi = compare_const_vals(tcx, test.hi, pat.lo, self.hir.param_env, test_ty)?; match (test.end, pat.end, lo, hi) { // pat < test @@ -679,7 +683,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - (&TestKind::Range(range), &PatternKind::Constant { value }) => { + (&TestKind::Range(range), &PatKind::Constant { value }) => { if self.const_range_contains(range, value) == Some(false) { // `value` is not contained in the testing range, // so `value` can be matched only if this test fails. @@ -718,9 +722,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn candidate_after_slice_test<'pat>(&mut self, match_pair_index: usize, candidate: &mut Candidate<'pat, 'tcx>, - prefix: &'pat [Pattern<'tcx>], - opt_slice: Option<&'pat Pattern<'tcx>>, - suffix: &'pat [Pattern<'tcx>]) { + prefix: &'pat [Pat<'tcx>], + opt_slice: Option<&'pat Pat<'tcx>>, + suffix: &'pat [Pat<'tcx>]) { let removed_place = candidate.match_pairs.remove(match_pair_index).place; self.prefix_slice_suffix( &mut candidate.match_pairs, @@ -735,7 +739,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match_pair_index: usize, adt_def: &'tcx ty::AdtDef, variant_index: VariantIdx, - subpatterns: &'pat [FieldPattern<'tcx>], + subpatterns: &'pat [FieldPat<'tcx>], candidate: &mut Candidate<'pat, 'tcx>, ) { let match_pair = candidate.match_pairs.remove(match_pair_index); @@ -767,15 +771,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn const_range_contains( &self, - range: PatternRange<'tcx>, + range: PatRange<'tcx>, value: &'tcx ty::Const<'tcx>, ) -> Option { use std::cmp::Ordering::*; let tcx = self.hir.tcx(); - let a = compare_const_vals(tcx, range.lo, value, self.hir.param_env, range.ty)?; - let b = compare_const_vals(tcx, value, range.hi, self.hir.param_env, range.ty)?; + let a = compare_const_vals(tcx, range.lo, value, self.hir.param_env, range.lo.ty)?; + let b = compare_const_vals(tcx, value, range.hi, self.hir.param_env, range.lo.ty)?; match (b, range.end) { (Less, _) | @@ -786,7 +790,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn values_not_contained_in_range( &self, - range: PatternRange<'tcx>, + range: PatRange<'tcx>, indices: &FxHashMap<&'tcx ty::Const<'tcx>, usize>, ) -> Option { for &val in indices.keys() { diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs index 011b3a8688837..83fb924af6381 100644 --- a/src/librustc_mir/build/matches/util.rs +++ b/src/librustc_mir/build/matches/util.rs @@ -8,7 +8,7 @@ use std::convert::TryInto; impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn field_match_pairs<'pat>(&mut self, place: Place<'tcx>, - subpatterns: &'pat [FieldPattern<'tcx>]) + subpatterns: &'pat [FieldPat<'tcx>]) -> Vec> { subpatterns.iter() .map(|fieldpat| { @@ -22,9 +22,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn prefix_slice_suffix<'pat>(&mut self, match_pairs: &mut Vec>, place: &Place<'tcx>, - prefix: &'pat [Pattern<'tcx>], - opt_slice: Option<&'pat Pattern<'tcx>>, - suffix: &'pat [Pattern<'tcx>]) { + prefix: &'pat [Pat<'tcx>], + opt_slice: Option<&'pat Pat<'tcx>>, + suffix: &'pat [Pat<'tcx>]) { let min_length = prefix.len() + suffix.len(); let min_length = min_length.try_into().unwrap(); @@ -101,7 +101,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { - pub fn new(place: Place<'tcx>, pattern: &'pat Pattern<'tcx>) -> MatchPair<'pat, 'tcx> { + pub fn new(place: Place<'tcx>, pattern: &'pat Pat<'tcx>) -> MatchPair<'pat, 'tcx> { MatchPair { place, pattern, diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 56025eeaaa922..d038310dd4454 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -26,12 +26,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// without any user type annotation. pub fn literal_operand(&mut self, span: Span, - ty: Ty<'tcx>, literal: &'tcx ty::Const<'tcx>) -> Operand<'tcx> { let constant = box Constant { span, - ty, user_ty: None, literal, }; @@ -47,7 +45,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { let literal = ty::Const::from_bits(self.hir.tcx(), 0, ty::ParamEnv::empty().and(ty)); - self.literal_operand(span, ty, literal) + self.literal_operand(span, literal) } pub fn push_usize(&mut self, @@ -61,7 +59,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, &temp, Constant { span: source_info.span, - ty: self.hir.usize_ty(), user_ty: None, literal: self.hir.usize_literal(value), }); diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 4e970aee42cf4..8c35342d324b7 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -1,18 +1,20 @@ use crate::build; use crate::build::scope::DropKind; use crate::hair::cx::Cx; -use crate::hair::{LintLevel, BindingMode, PatternKind}; +use crate::hair::{LintLevel, BindingMode, PatKind}; use crate::transform::MirSource; use crate::util as mir_util; use rustc::hir; use rustc::hir::Node; use rustc::hir::def_id::DefId; +use rustc::middle::lang_items; use rustc::middle::region; use rustc::mir::*; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::subst::Subst; use rustc::util::nodemap::HirIdMap; use rustc_target::spec::PanicStrategy; -use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use rustc_index::vec::{IndexVec, Idx}; use std::u32; use rustc_target::spec::abi::Abi; use syntax::attr::{self, UnwindAttr}; @@ -27,17 +29,17 @@ pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> { // Figure out what primary body this item has. let (body_id, return_ty_span) = match tcx.hir().get(id) { - Node::Expr(hir::Expr { node: hir::ExprKind::Closure(_, decl, body_id, _, _), .. }) - | Node::Item(hir::Item { node: hir::ItemKind::Fn(decl, _, _, body_id), .. }) + Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_, decl, body_id, _, _), .. }) + | Node::Item(hir::Item { kind: hir::ItemKind::Fn(decl, _, _, body_id), .. }) | Node::ImplItem( hir::ImplItem { - node: hir::ImplItemKind::Method(hir::MethodSig { decl, .. }, body_id), + kind: hir::ImplItemKind::Method(hir::MethodSig { decl, .. }, body_id), .. } ) | Node::TraitItem( hir::TraitItem { - node: hir::TraitItemKind::Method( + kind: hir::TraitItemKind::Method( hir::MethodSig { decl, .. }, hir::TraitMethod::Provided(body_id), ), @@ -46,11 +48,11 @@ pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> { ) => { (*body_id, decl.output.span()) } - Node::Item(hir::Item { node: hir::ItemKind::Static(ty, _, body_id), .. }) - | Node::Item(hir::Item { node: hir::ItemKind::Const(ty, body_id), .. }) - | Node::ImplItem(hir::ImplItem { node: hir::ImplItemKind::Const(ty, body_id), .. }) + Node::Item(hir::Item { kind: hir::ItemKind::Static(ty, _, body_id), .. }) + | Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, body_id), .. }) + | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(ty, body_id), .. }) | Node::TraitItem( - hir::TraitItem { node: hir::TraitItemKind::Const(ty, Some(body_id)), .. } + hir::TraitItem { kind: hir::TraitItemKind::Const(ty, Some(body_id)), .. } ) => { (*body_id, ty.span) } @@ -73,7 +75,7 @@ pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> { let ty = tcx.type_of(fn_def_id); let mut abi = fn_sig.abi; - let implicit_argument = match ty.sty { + let implicit_argument = match ty.kind { ty::Closure(..) => { // HACK(eddyb) Avoid having RustCall on closures, // as it adds unnecessary (and wrong) auto-tupling. @@ -94,7 +96,7 @@ pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> { let body = tcx.hir().body(body_id); let explicit_arguments = - body.arguments + body.params .iter() .enumerate() .map(|(index, arg)| { @@ -102,9 +104,7 @@ pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> { let opt_ty_info; let self_arg; if let Some(ref fn_decl) = tcx.hir().fn_decl_by_hir_id(owner_id) { - let ty_hir_id = fn_decl.inputs[index].hir_id; - let ty_span = tcx.hir().span(ty_hir_id); - opt_ty_info = Some(ty_span); + opt_ty_info = fn_decl.inputs.get(index).map(|ty| ty.span); self_arg = if index == 0 && fn_decl.implicit_self.has_implicit_self() { match fn_decl.implicit_self { hir::ImplicitSelfKind::Imm => Some(ImplicitSelfKind::Imm), @@ -121,15 +121,32 @@ pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> { self_arg = None; } - ArgInfo(fn_sig.inputs()[index], opt_ty_info, Some(&arg), self_arg) + // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` + // (as it's created inside the body itself, not passed in from outside). + let ty = if fn_sig.c_variadic && index == fn_sig.inputs().len() { + let va_list_did = tcx.require_lang_item( + lang_items::VaListTypeLangItem, + Some(arg.span), + ); + let region = tcx.mk_region(ty::ReScope(region::Scope { + id: body.value.hir_id.local_id, + data: region::ScopeData::CallSite + })); + + tcx.type_of(va_list_did).subst(tcx, &[region.into()]) + } else { + fn_sig.inputs()[index] + }; + + ArgInfo(ty, opt_ty_info, Some(&arg), self_arg) }); let arguments = implicit_argument.into_iter().chain(explicit_arguments); let (yield_ty, return_ty) = if body.generator_kind.is_some() { - let gen_sig = match ty.sty { + let gen_sig = match ty.kind { ty::Generator(gen_def_id, gen_substs, ..) => - gen_substs.sig(gen_def_id, tcx), + gen_substs.as_generator().sig(gen_def_id, tcx), _ => span_bug!(tcx.hir().span(id), "generator w/o generator type: {:?}", ty), @@ -178,7 +195,7 @@ fn liberated_closure_env_ty( ) -> Ty<'_> { let closure_ty = tcx.body_tables(body_id).node_type(closure_expr_id); - let (closure_def_id, closure_substs) = match closure_ty.sty { + let (closure_def_id, closure_substs) = match closure_ty.kind { ty::Closure(closure_def_id, closure_substs) => (closure_def_id, closure_substs), _ => bug!("closure expr does not have closure type: {:?}", closure_ty) }; @@ -438,7 +455,7 @@ struct CFG<'tcx> { basic_blocks: IndexVec>, } -newtype_index! { +rustc_index::newtype_index! { pub struct ScopeId { .. } } @@ -502,7 +519,7 @@ fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: DefId, abi: Abi) -> bool { // This is a special case: some functions have a C abi but are meant to // unwind anyway. Don't stop them. match unwind_attr { - None => true, + None => false, // FIXME(#58794) Some(UnwindAttr::Allowed) => false, Some(UnwindAttr::Aborts) => true, } @@ -511,7 +528,7 @@ fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: DefId, abi: Abi) -> bool { /////////////////////////////////////////////////////////////////////////// /// the main entry point for building MIR for a function -struct ArgInfo<'tcx>(Ty<'tcx>, Option, Option<&'tcx hir::Arg>, Option); +struct ArgInfo<'tcx>(Ty<'tcx>, Option, Option<&'tcx hir::Param>, Option); fn construct_fn<'a, 'tcx, A>( hir: Cx<'a, 'tcx>, @@ -559,7 +576,7 @@ where }; let mut mutability = Mutability::Not; if let Some(Node::Binding(pat)) = tcx_hir.find(var_hir_id) { - if let hir::PatKind::Binding(_, _, ident, _) = pat.node { + if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { debuginfo.debug_name = ident.name; if let Some(&bm) = hir.tables.pat_binding_modes().get(pat.hir_id) { if bm == ty::BindByValue(hir::MutMutable) { @@ -609,7 +626,7 @@ where unpack!(block = builder.in_breakable_scope( None, START_BLOCK, - Place::RETURN_PLACE, + Place::return_place(), |builder| { builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { builder.args_and_body(block, &arguments, arg_scope, &body.value) @@ -670,7 +687,7 @@ fn construct_const<'a, 'tcx>( let mut block = START_BLOCK; let ast_expr = &tcx.hir().body(body_id).value; let expr = builder.hir.mirror(ast_expr); - unpack!(block = builder.into_expr(&Place::RETURN_PLACE, block, expr)); + unpack!(block = builder.into_expr(&Place::return_place(), block, expr)); let source_info = builder.source_info(span); builder.cfg.terminate(block, source_info, TerminatorKind::Return); @@ -763,7 +780,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.basic_blocks, self.source_scopes, ClearCrossCrate::Set(self.source_scope_local_data), - IndexVec::new(), yield_ty, self.local_decls, self.canonical_user_type_annotations, @@ -813,12 +829,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Function arguments always get the first Local indices after the return place let local = Local::new(index + 1); let place = Place::from(local); - let &ArgInfo(ty, opt_ty_info, arg_opt, ref self_binding) = arg_info; + let &ArgInfo(_, opt_ty_info, arg_opt, ref self_binding) = arg_info; // Make sure we drop (parts of) the argument even when not matched on. self.schedule_drop( arg_opt.as_ref().map_or(ast_body.span, |arg| arg.pat.span), - argument_scope, local, ty, DropKind::Value, + argument_scope, local, DropKind::Value, ); if let Some(arg) = arg_opt { @@ -828,7 +844,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span); match *pattern.kind { // Don't introduce extra copies for simple bindings - PatternKind::Binding { + PatKind::Binding { mutability, var, mode: BindingMode::ByValue, @@ -872,7 +888,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let body = self.hir.mirror(ast_body); - self.into(&Place::RETURN_PLACE, block, body) + self.into(&Place::return_place(), block, body) } fn set_correct_source_scope_for_arg( diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index a04c041ca9dc7..a749b4263ea64 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -85,7 +85,6 @@ should go to. use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG}; use crate::hair::{Expr, ExprRef, LintLevel}; use rustc::middle::region; -use rustc::ty::Ty; use rustc::hir; use rustc::mir::*; use syntax_pos::{DUMMY_SP, Span}; @@ -104,25 +103,14 @@ struct Scope { /// the span of that region_scope region_scope_span: Span, - /// Whether there's anything to do for the cleanup path, that is, - /// when unwinding through this scope. This includes destructors, - /// but not StorageDead statements, which don't get emitted at all - /// for unwinding, for several reasons: - /// * clang doesn't emit llvm.lifetime.end for C++ unwinding - /// * LLVM's memory dependency analysis can't handle it atm - /// * polluting the cleanup MIR with StorageDead creates - /// landing pads even though there's no actual destructors - /// * freeing up stack space has no effect during unwinding - /// Note that for generators we do emit StorageDeads, for the - /// use of optimizations in the MIR generator transform. - needs_cleanup: bool, - /// set of places to drop when exiting this scope. This starts /// out empty but grows as variables are declared during the /// building process. This is a stack, so we always drop from the /// end of the vector (top of the stack) first. drops: Vec, + moved_locals: Vec, + /// The cache for drop chain on “normal” exit into a particular BasicBlock. cached_exits: FxHashMap<(BasicBlock, region::Scope), BasicBlock>, @@ -172,7 +160,7 @@ struct CachedBlock { generator_drop: Option, } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] pub(crate) enum DropKind { Value, Storage, @@ -184,11 +172,11 @@ struct BreakableScope<'tcx> { region_scope: region::Scope, /// Where the body of the loop begins. `None` if block continue_block: Option, - /// Block to branch into when the loop or block terminates (either by being `break`-en out - /// from, or by having its condition to become false) + /// Block to branch into when the loop or block terminates (either by being + /// `break`-en out from, or by having its condition to become false) break_block: BasicBlock, - /// The destination of the loop/block expression itself (i.e., where to put the result of a - /// `break` expression) + /// The destination of the loop/block expression itself (i.e., where to put + /// the result of a `break` expression) break_destination: Place<'tcx>, } @@ -202,8 +190,7 @@ pub enum BreakableTarget { impl CachedBlock { fn invalidate(&mut self) { - self.generator_drop = None; - self.unwind = None; + *self = CachedBlock::default(); } fn get(&self, generator_drop: bool) -> Option { @@ -261,6 +248,25 @@ impl Scope { scope: self.source_scope } } + + + /// Whether there's anything to do for the cleanup path, that is, + /// when unwinding through this scope. This includes destructors, + /// but not StorageDead statements, which don't get emitted at all + /// for unwinding, for several reasons: + /// * clang doesn't emit llvm.lifetime.end for C++ unwinding + /// * LLVM's memory dependency analysis can't handle it atm + /// * polluting the cleanup MIR with StorageDead creates + /// landing pads even though there's no actual destructors + /// * freeing up stack space has no effect during unwinding + /// Note that for generators we do emit StorageDeads, for the + /// use of optimizations in the MIR generator transform. + fn needs_cleanup(&self) -> bool { + self.drops.iter().any(|drop| match drop.kind { + DropKind::Value => true, + DropKind::Storage => false, + }) + } } impl<'tcx> Scopes<'tcx> { @@ -274,8 +280,8 @@ impl<'tcx> Scopes<'tcx> { source_scope: vis_scope, region_scope: region_scope.0, region_scope_span: region_scope.1.span, - needs_cleanup: false, drops: vec![], + moved_locals: vec![], cached_generator_drop: None, cached_exits: Default::default(), cached_unwind: CachedBlock::default(), @@ -295,7 +301,7 @@ impl<'tcx> Scopes<'tcx> { fn may_panic(&self, scope_count: usize) -> bool { let len = self.len(); - self.scopes[(len - scope_count)..].iter().any(|s| s.needs_cleanup) + self.scopes[(len - scope_count)..].iter().any(|s| s.needs_cleanup()) } /// Finds the breakable scope for a given label. This is used for @@ -314,7 +320,7 @@ impl<'tcx> Scopes<'tcx> { match target { BreakableTarget::Return => { let scope = &self.breakable_scopes[0]; - if scope.break_destination != Place::RETURN_PLACE { + if scope.break_destination != Place::return_place() { span_bug!(span, "`return` in item with no return scope"); } (scope.break_block, scope.region_scope, Some(scope.break_destination.clone())) @@ -480,7 +486,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, unwind_to, self.arg_count, - false, + false, // not generator + false, // not unwind path )); block.unit() @@ -572,7 +579,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, unwind_to, self.arg_count, - false, + false, // not generator + false, // not unwind path )); scope = next_scope; @@ -622,7 +630,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, unwind_to, self.arg_count, - true, + true, // is generator + true, // is cached path )); } @@ -718,10 +727,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span: Span, region_scope: region::Scope, local: Local, - place_ty: Ty<'tcx>, ) { - self.schedule_drop(span, region_scope, local, place_ty, DropKind::Storage); - self.schedule_drop(span, region_scope, local, place_ty, DropKind::Value); + self.schedule_drop(span, region_scope, local, DropKind::Storage); + self.schedule_drop(span, region_scope, local, DropKind::Value); } /// Indicates that `place` should be dropped on exit from @@ -734,12 +742,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span: Span, region_scope: region::Scope, local: Local, - place_ty: Ty<'tcx>, drop_kind: DropKind, ) { - let needs_drop = self.hir.needs_drop(place_ty); - match drop_kind { - DropKind::Value => if !needs_drop { return }, + let needs_drop = match drop_kind { + DropKind::Value => { + if !self.hir.needs_drop(self.local_decls[local].ty) { return } + true + }, DropKind::Storage => { if local.index() <= self.arg_count { span_bug!( @@ -748,8 +757,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.arg_count, ) } + false } - } + }; for scope in self.scopes.iter_mut() { let this_scope = scope.region_scope == region_scope; @@ -801,10 +811,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // cache of outer scope stays intact. scope.invalidate_cache(!needs_drop, self.is_generator, this_scope); if this_scope { - if let DropKind::Value = drop_kind { - scope.needs_cleanup = true; - } - let region_scope_span = region_scope.span(self.hir.tcx(), &self.hir.region_scope_tree); // Attribute scope exit drops to scope's closing brace. @@ -822,6 +828,75 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local); } + /// Indicates that the "local operand" stored in `local` is + /// *moved* at some point during execution (see `local_scope` for + /// more information about what a "local operand" is -- in short, + /// it's an intermediate operand created as part of preparing some + /// MIR instruction). We use this information to suppress + /// redundant drops on the non-unwind paths. This results in less + /// MIR, but also avoids spurious borrow check errors + /// (c.f. #64391). + /// + /// Example: when compiling the call to `foo` here: + /// + /// ```rust + /// foo(bar(), ...) + /// ``` + /// + /// we would evaluate `bar()` to an operand `_X`. We would also + /// schedule `_X` to be dropped when the expression scope for + /// `foo(bar())` is exited. This is relevant, for example, if the + /// later arguments should unwind (it would ensure that `_X` gets + /// dropped). However, if no unwind occurs, then `_X` will be + /// unconditionally consumed by the `call`: + /// + /// ``` + /// bb { + /// ... + /// _R = CALL(foo, _X, ...) + /// } + /// ``` + /// + /// However, `_X` is still registered to be dropped, and so if we + /// do nothing else, we would generate a `DROP(_X)` that occurs + /// after the call. This will later be optimized out by the + /// drop-elaboation code, but in the meantime it can lead to + /// spurious borrow-check errors -- the problem, ironically, is + /// not the `DROP(_X)` itself, but the (spurious) unwind pathways + /// that it creates. See #64391 for an example. + pub fn record_operands_moved( + &mut self, + operands: &[Operand<'tcx>], + ) { + let scope = match self.local_scope() { + None => { + // if there is no local scope, operands won't be dropped anyway + return; + } + + Some(local_scope) => { + self.scopes.iter_mut().find(|scope| scope.region_scope == local_scope) + .unwrap_or_else(|| bug!("scope {:?} not found in scope list!", local_scope)) + } + }; + + // look for moves of a local variable, like `MOVE(_X)` + let locals_moved = operands.iter().flat_map(|operand| match operand { + Operand::Copy(_) | Operand::Constant(_) => None, + Operand::Move(place) => place.as_local(), + }); + + for local in locals_moved { + // check if we have a Drop for this operand and -- if so + // -- add it to the list of moved operands. Note that this + // local might not have been an operand created for this + // call, it could come from other places too. + if scope.drops.iter().any(|drop| drop.local == local && drop.kind == DropKind::Value) { + scope.moved_locals.push(local); + } + } + } + // Other // ===== /// Branch based on a boolean condition. @@ -853,11 +928,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ if self.local_scope().is_none() => (), Operand::Copy(Place { base: PlaceBase::Local(cond_temp), - projection: None, + projection: box [], }) | Operand::Move(Place { base: PlaceBase::Local(cond_temp), - projection: None, + projection: box [], }) => { // Manually drop the condition on both branches. let top_scope = self.scopes.scopes.last_mut().unwrap(); @@ -1020,6 +1095,7 @@ fn build_scope_drops<'tcx>( last_unwind_to: BasicBlock, arg_count: usize, generator_drop: bool, + is_cached_path: bool, ) -> BlockAnd<()> { debug!("build_scope_drops({:?} -> {:?})", block, scope); @@ -1046,8 +1122,17 @@ fn build_scope_drops<'tcx>( let drop_data = &scope.drops[drop_idx]; let source_info = scope.source_info(drop_data.span); let local = drop_data.local; + match drop_data.kind { DropKind::Value => { + // If the operand has been moved, and we are not on an unwind + // path, then don't generate the drop. (We only take this into + // account for non-unwind paths so as not to disturb the + // caching mechanism.) + if !is_cached_path && scope.moved_locals.iter().any(|&o| o == local) { + continue; + } + let unwind_to = get_unwind_to(scope, is_generator, drop_idx, generator_drop) .unwrap_or(last_unwind_to); diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 36d80d0cb5767..bb02b99dd8d87 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -11,17 +11,17 @@ use rustc::hir::def::DefKind; use rustc::hir::def_id::DefId; use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef}; use rustc::mir; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt, subst::Subst}; use rustc::ty::layout::{self, LayoutOf, VariantIdx}; -use rustc::ty::subst::Subst; use rustc::traits::Reveal; use rustc_data_structures::fx::FxHashMap; +use crate::interpret::eval_nullary_intrinsic; use syntax::source_map::{Span, DUMMY_SP}; use crate::interpret::{self, PlaceTy, MPlaceTy, OpTy, ImmTy, Immediate, Scalar, Pointer, - RawConst, ConstValue, + RawConst, ConstValue, Machine, InterpResult, InterpErrorInfo, GlobalId, InterpCx, StackPopCleanup, Allocation, AllocId, MemoryKind, Memory, snapshot, RefTracking, intern_const_alloc_recursive, @@ -41,7 +41,7 @@ const DETECTOR_SNAPSHOT_PERIOD: isize = 256; /// that inform us about the generic bounds of the constant. E.g., using an associated constant /// of a function's generic parameter will require knowledge about the bounds on the generic /// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. -pub(crate) fn mk_eval_cx<'mir, 'tcx>( +fn mk_eval_cx<'mir, 'tcx>( tcx: TyCtxt<'tcx>, span: Span, param_env: ty::ParamEnv<'tcx>, @@ -50,17 +50,6 @@ pub(crate) fn mk_eval_cx<'mir, 'tcx>( InterpCx::new(tcx.at(span), param_env, CompileTimeInterpreter::new(), Default::default()) } -pub(crate) fn eval_promoted<'mir, 'tcx>( - tcx: TyCtxt<'tcx>, - cid: GlobalId<'tcx>, - body: &'mir mir::Body<'tcx>, - param_env: ty::ParamEnv<'tcx>, -) -> InterpResult<'tcx, MPlaceTy<'tcx>> { - let span = tcx.def_span(cid.instance.def_id()); - let mut ecx = mk_eval_cx(tcx, span, param_env); - eval_body_using_ecx(&mut ecx, cid, body, param_env) -} - fn op_to_const<'tcx>( ecx: &CompileTimeEvalContext<'_, 'tcx>, op: OpTy<'tcx>, @@ -74,8 +63,8 @@ fn op_to_const<'tcx>( // `Undef` situation. let try_as_immediate = match op.layout.abi { layout::Abi::Scalar(..) => true, - layout::Abi::ScalarPair(..) => match op.layout.ty.sty { - ty::Ref(_, inner, _) => match inner.sty { + layout::Abi::ScalarPair(..) => match op.layout.ty.kind { + ty::Ref(_, inner, _) => match inner.kind { ty::Slice(elem) => elem == ecx.tcx.types.u8, ty::Str => true, _ => false, @@ -146,9 +135,8 @@ fn eval_body_using_ecx<'mir, 'tcx>( ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, cid: GlobalId<'tcx>, body: &'mir mir::Body<'tcx>, - param_env: ty::ParamEnv<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { - debug!("eval_body_using_ecx: {:?}, {:?}", cid, param_env); + debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env); let tcx = ecx.tcx.tcx; let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); @@ -174,7 +162,6 @@ fn eval_body_using_ecx<'mir, 'tcx>( ecx, cid.instance.def_id(), ret, - param_env, )?; debug!("eval_body_using_ecx done: {:?}", *ret); @@ -182,7 +169,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( } #[derive(Clone, Debug)] -enum ConstEvalError { +pub enum ConstEvalError { NeedsRfc(String), } @@ -361,7 +348,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } } // This is a const fn. Call it. - Ok(Some(match ecx.load_mir(instance.def) { + Ok(Some(match ecx.load_mir(instance.def, None) { Ok(body) => body, Err(err) => { if let err_unsup!(NoMirFor(ref path)) = err.kind { @@ -395,7 +382,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, return Ok(()); } // An intrinsic that we do not support - let intrinsic_name = &ecx.tcx.item_name(instance.def_id()).as_str()[..]; + let intrinsic_name = ecx.tcx.item_name(instance.def_id()); Err( ConstEvalError::NeedsRfc(format!("calling intrinsic `{}`", intrinsic_name)).into() ) @@ -415,7 +402,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, _bin_op: mir::BinOp, _left: ImmTy<'tcx>, _right: ImmTy<'tcx>, - ) -> InterpResult<'tcx, (Scalar, bool)> { + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { Err( ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(), ) @@ -531,8 +518,11 @@ pub fn const_variant_index<'tcx>( ecx.read_discriminant(op).unwrap().1 } -pub fn error_to_const_error<'mir, 'tcx>( - ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, +/// Turn an interpreter error into something to report to the user. +/// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace. +/// Should be called only if the error is actually going to to be reported! +pub fn error_to_const_error<'mir, 'tcx, M: Machine<'mir, 'tcx>>( + ecx: &InterpCx<'mir, 'tcx, M>, mut error: InterpErrorInfo<'tcx>, ) -> ConstEvalErr<'tcx> { error.print_backtrace(); @@ -540,6 +530,12 @@ pub fn error_to_const_error<'mir, 'tcx>( ConstEvalErr { error: error.kind, stacktrace, span: ecx.tcx.span } } +pub fn note_on_undefined_behavior_error() -> &'static str { + "The rules on what exactly is undefined behavior aren't clear, \ + so this check might be overzealous. Please open an issue on the rustc \ + repository if you believe it should not be considered undefined behavior." +} + fn validate_and_turn_into_const<'tcx>( tcx: TyCtxt<'tcx>, constant: RawConst<'tcx>, @@ -579,10 +575,7 @@ fn validate_and_turn_into_const<'tcx>( let err = error_to_const_error(&ecx, error); match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") { Ok(mut diag) => { - diag.note("The rules on what exactly is undefined behavior aren't clear, \ - so this check might be overzealous. Please open an issue on the rust compiler \ - repository if you believe it should not be considered undefined behavior", - ); + diag.note(note_on_undefined_behavior_error()); diag.emit(); ErrorHandled::Reported } @@ -595,7 +588,7 @@ pub fn const_eval_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> { - // see comment in const_eval_provider for what we're doing here + // see comment in const_eval_raw_provider for what we're doing here if key.param_env.reveal == Reveal::All { let mut key = key.clone(); key.param_env.reveal = Reveal::UserFacing; @@ -610,6 +603,23 @@ pub fn const_eval_provider<'tcx>( other => return other, } } + + // We call `const_eval` for zero arg intrinsics, too, in order to cache their value. + // Catch such calls and evaluate them instead of trying to load a constant's MIR. + if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def { + let ty = key.value.instance.ty(tcx); + let substs = match ty.kind { + ty::FnDef(_, substs) => substs, + _ => bug!("intrinsic with type {:?}", ty), + }; + return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs) + .map_err(|error| { + let span = tcx.def_span(def_id); + let error = ConstEvalErr { error: error.kind, stacktrace: vec![], span }; + error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic") + }) + } + tcx.const_eval_raw(key).and_then(|val| { validate_and_turn_into_const(tcx, val, key) }) @@ -662,15 +672,9 @@ pub fn const_eval_raw_provider<'tcx>( Default::default() ); - let res = ecx.load_mir(cid.instance.def); - res.map(|body| { - if let Some(index) = cid.promoted { - &body.promoted[index] - } else { - body - } - }).and_then( - |body| eval_body_using_ecx(&mut ecx, cid, body, key.param_env) + let res = ecx.load_mir(cid.instance.def, cid.promoted); + res.and_then( + |body| eval_body_using_ecx(&mut ecx, cid, body) ).and_then(|place| { Ok(RawConst { alloc_id: place.ptr.assert_ptr().alloc_id, diff --git a/src/librustc_mir/dataflow/at_location.rs b/src/librustc_mir/dataflow/at_location.rs index f0014602e2d6b..e0ca10535237b 100644 --- a/src/librustc_mir/dataflow/at_location.rs +++ b/src/librustc_mir/dataflow/at_location.rs @@ -2,7 +2,7 @@ //! locations. use rustc::mir::{BasicBlock, Location}; -use rustc_data_structures::bit_set::{BitIter, BitSet, HybridBitSet}; +use rustc_index::bit_set::{BitIter, BitSet, HybridBitSet}; use crate::dataflow::{BitDenotation, DataflowResults, GenKillSet}; use crate::dataflow::move_paths::{HasMoveData, MovePathIndex}; diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs index c071b3101fce3..0fe58c07b1b86 100644 --- a/src/librustc_mir/dataflow/drop_flag_effects.rs +++ b/src/librustc_mir/dataflow/drop_flag_effects.rs @@ -10,19 +10,17 @@ pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>, path: MovePathIndex, mut cond: F) -> Option - where F: FnMut(&mir::Projection<'tcx>) -> bool + where F: FnMut(&mir::PlaceElem<'tcx>) -> bool { let mut next_child = move_data.move_paths[path].first_child; while let Some(child_index) = next_child { - match move_data.move_paths[child_index].place.projection { - Some(ref proj) => { - if cond(proj) { - return Some(child_index) - } + let move_path_children = &move_data.move_paths[child_index]; + if let Some(elem) = move_path_children.place.projection.last() { + if cond(elem) { + return Some(child_index) } - _ => {} } - next_child = move_data.move_paths[child_index].next_sibling; + next_child = move_path_children.next_sibling; } None @@ -52,7 +50,7 @@ fn place_contents_drop_state_cannot_differ<'tcx>( place: &mir::Place<'tcx>, ) -> bool { let ty = place.ty(body, tcx).ty; - match ty.sty { + match ty.kind { ty::Array(..) => { debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false", place, ty); @@ -150,9 +148,8 @@ pub(crate) fn on_all_drop_children_bits<'tcx, F>( let ty = place.ty(body, tcx).ty; debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty); - let gcx = tcx.global_tcx(); let erased_ty = tcx.erase_regions(&ty); - if erased_ty.needs_drop(gcx, ctxt.param_env) { + if erased_ty.needs_drop(tcx, ctxt.param_env) { each_child(child); } else { debug!("on_all_drop_children_bits - skipping") diff --git a/src/librustc_mir/dataflow/generic.rs b/src/librustc_mir/dataflow/generic.rs new file mode 100644 index 0000000000000..dd6238b80d174 --- /dev/null +++ b/src/librustc_mir/dataflow/generic.rs @@ -0,0 +1,613 @@ +//! Dataflow analysis with arbitrary transfer functions. +//! +//! This module is a work in progress. You should instead use `BitDenotation` in +//! `librustc_mir/dataflow/mod.rs` and encode your transfer function as a [gen/kill set][gk]. In +//! doing so, your analysis will run faster and you will be able to generate graphviz diagrams for +//! debugging with no extra effort. The interface in this module is intended only for dataflow +//! problems that cannot be expressed using gen/kill sets. +//! +//! FIXME(ecstaticmorse): In the long term, the plan is to preserve the existing `BitDenotation` +//! interface, but make `Engine` and `ResultsCursor` the canonical way to perform and inspect a +//! dataflow analysis. This requires porting the graphviz debugging logic to this module, deciding +//! on a way to handle the `before` methods in `BitDenotation` and creating an adapter so that +//! gen-kill problems can still be evaluated efficiently. See the discussion in [#64566][] for more +//! information. +//! +//! [gk]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems +//! [#64566]: https://github.com/rust-lang/rust/pull/64566 + +use std::borrow::Borrow; +use std::cmp::Ordering; +use std::ffi::OsString; +use std::path::{Path, PathBuf}; +use std::{fs, io, ops}; + +use rustc::hir::def_id::DefId; +use rustc::mir::{self, traversal, BasicBlock, Location}; +use rustc::ty::{self, TyCtxt}; +use rustc_data_structures::work_queue::WorkQueue; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::{Idx, IndexVec}; +use syntax::symbol::sym; + +use crate::dataflow::BottomValue; + +mod graphviz; + +/// A specific kind of dataflow analysis. +/// +/// To run a dataflow analysis, one must set the initial state of the `START_BLOCK` via +/// `initialize_start_block` and define a transfer function for each statement or terminator via +/// the various `effect` methods. The entry set for all other basic blocks is initialized to +/// `Self::BOTTOM_VALUE`. The dataflow `Engine` then iteratively updates the various entry sets for +/// each block with the cumulative effects of the transfer functions of all preceding blocks. +/// +/// You should use an `Engine` to actually run an analysis, and a `ResultsCursor` to inspect the +/// results of that analysis like so: +/// +/// ```ignore(cross-crate-imports) +/// fn do_my_analysis(body: &mir::Body<'tcx>, dead_unwinds: &BitSet) { +/// // `MyAnalysis` implements `Analysis`. +/// let analysis = MyAnalysis::new(); +/// +/// let results = Engine::new(body, dead_unwinds, analysis).iterate_to_fixpoint(); +/// let mut cursor = ResultsCursor::new(body, results); +/// +/// for (_, statement_index) in body.block_data[START_BLOCK].statements.iter_enumerated() { +/// cursor.seek_after(Location { block: START_BLOCK, statement_index }); +/// let state = cursor.get(); +/// println!("{:?}", state); +/// } +/// } +/// ``` +pub trait Analysis<'tcx>: BottomValue { + /// The index type used to access the dataflow state. + type Idx: Idx; + + /// A name, used for debugging, that describes this dataflow analysis. + /// + /// The name should be suitable as part of a filename, so avoid whitespace, slashes or periods + /// and try to keep it short. + const NAME: &'static str; + + /// How each element of your dataflow state will be displayed during debugging. + /// + /// By default, this is the `fmt::Debug` representation of `Self::Idx`. + fn pretty_print_idx(&self, w: &mut impl io::Write, idx: Self::Idx) -> io::Result<()> { + write!(w, "{:?}", idx) + } + + /// The size of each bitvector allocated for each block. + fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize; + + /// Mutates the entry set of the `START_BLOCK` to contain the initial state for dataflow + /// analysis. + fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet); + + /// Updates the current dataflow state with the effect of evaluating a statement. + fn apply_statement_effect( + &self, + state: &mut BitSet, + statement: &mir::Statement<'tcx>, + location: Location, + ); + + /// Updates the current dataflow state with the effect of evaluating a terminator. + /// + /// Note that the effect of a successful return from a `Call` terminator should **not** be + /// acounted for in this function. That should go in `apply_call_return_effect`. For example, + /// in the `InitializedPlaces` analyses, the return place is not marked as initialized here. + fn apply_terminator_effect( + &self, + state: &mut BitSet, + terminator: &mir::Terminator<'tcx>, + location: Location, + ); + + /// Updates the current dataflow state with the effect of a successful return from a `Call` + /// terminator. + /// + /// This is separated from `apply_terminator_effect` to properly track state across + /// unwind edges for `Call`s. + fn apply_call_return_effect( + &self, + state: &mut BitSet, + block: BasicBlock, + func: &mir::Operand<'tcx>, + args: &[mir::Operand<'tcx>], + return_place: &mir::Place<'tcx>, + ); + + /// Applies the cumulative effect of an entire basic block to the dataflow state (except for + /// `call_return_effect`, which is handled in the `Engine`). + /// + /// The default implementation calls `statement_effect` for every statement in the block before + /// finally calling `terminator_effect`. However, some dataflow analyses are able to coalesce + /// transfer functions for an entire block and apply them at once. Such analyses should + /// override `block_effect`. + fn apply_whole_block_effect( + &self, + state: &mut BitSet, + block: BasicBlock, + block_data: &mir::BasicBlockData<'tcx>, + ) { + for (statement_index, stmt) in block_data.statements.iter().enumerate() { + let location = Location { block, statement_index }; + self.apply_statement_effect(state, stmt, location); + } + + let location = Location { block, statement_index: block_data.statements.len() }; + self.apply_terminator_effect(state, block_data.terminator(), location); + } + + /// Applies the cumulative effect of a sequence of statements (and possibly a terminator) + /// within a single basic block. + /// + /// When called with `0..block_data.statements.len() + 1` as the statement range, this function + /// is equivalent to `apply_whole_block_effect`. + fn apply_partial_block_effect( + &self, + state: &mut BitSet, + block: BasicBlock, + block_data: &mir::BasicBlockData<'tcx>, + mut range: ops::Range, + ) { + if range.is_empty() { + return; + } + + // The final location might be a terminator, so iterate through all statements until the + // final one, then check to see whether the final one is a statement or terminator. + // + // This can't cause the range to wrap-around since we check that the range contains at + // least one element above. + range.end -= 1; + let final_location = Location { block, statement_index: range.end }; + + for statement_index in range { + let location = Location { block, statement_index }; + let stmt = &block_data.statements[statement_index]; + self.apply_statement_effect(state, stmt, location); + } + + if final_location.statement_index == block_data.statements.len() { + let terminator = block_data.terminator(); + self.apply_terminator_effect(state, terminator, final_location); + } else { + let stmt = &block_data.statements[final_location.statement_index]; + self.apply_statement_effect(state, stmt, final_location); + } + } +} + +#[derive(Clone, Copy, Debug)] +enum CursorPosition { + AtBlockStart(BasicBlock), + After(Location), +} + +impl CursorPosition { + fn block(&self) -> BasicBlock { + match *self { + Self::AtBlockStart(block) => block, + Self::After(Location { block, .. }) => block, + } + } +} + +type ResultsRefCursor<'a, 'mir, 'tcx, A> = + ResultsCursor<'mir, 'tcx, A, &'a Results<'tcx, A>>; + +/// Inspect the results of dataflow analysis. +/// +/// This cursor has linear performance when visiting statements in a block in order. Visiting +/// statements within a block in reverse order is `O(n^2)`, where `n` is the number of statements +/// in that block. +pub struct ResultsCursor<'mir, 'tcx, A, R = Results<'tcx, A>> +where + A: Analysis<'tcx>, +{ + body: &'mir mir::Body<'tcx>, + results: R, + state: BitSet, + + pos: CursorPosition, + + /// Whether the effects of `apply_call_return_effect` are currently stored in `state`. + /// + /// This flag ensures that multiple calls to `seek_after_assume_call_returns` with the same + /// target only result in one invocation of `apply_call_return_effect`. + is_call_return_effect_applied: bool, +} + +impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R> +where + A: Analysis<'tcx>, + R: Borrow>, +{ + /// Returns a new cursor for `results` that points to the start of the `START_BLOCK`. + pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self { + ResultsCursor { + body, + pos: CursorPosition::AtBlockStart(mir::START_BLOCK), + is_call_return_effect_applied: false, + state: results.borrow().entry_sets[mir::START_BLOCK].clone(), + results, + } + } + + pub fn analysis(&self) -> &A { + &self.results.borrow().analysis + } + + /// Resets the cursor to the start of the given `block`. + pub fn seek_to_block_start(&mut self, block: BasicBlock) { + self.state.overwrite(&self.results.borrow().entry_sets[block]); + self.pos = CursorPosition::AtBlockStart(block); + self.is_call_return_effect_applied = false; + } + + /// Updates the cursor to hold the dataflow state immediately before `target`. + pub fn seek_before(&mut self, target: Location) { + assert!(target <= self.body.terminator_loc(target.block)); + + if target.statement_index == 0 { + self.seek_to_block_start(target.block); + } else { + self._seek_after(Location { + block: target.block, + statement_index: target.statement_index - 1, + }); + } + } + + /// Updates the cursor to hold the dataflow state at `target`. + /// + /// If `target` is a `Call` terminator, `apply_call_return_effect` will not be called. See + /// `seek_after_assume_call_returns` if you wish to observe the dataflow state upon a + /// successful return. + pub fn seek_after(&mut self, target: Location) { + assert!(target <= self.body.terminator_loc(target.block)); + + // This check ensures the correctness of a call to `seek_after_assume_call_returns` + // followed by one to `seek_after` with the same target. + if self.is_call_return_effect_applied { + self.seek_to_block_start(target.block); + } + + self._seek_after(target); + } + + /// Equivalent to `seek_after`, but also calls `apply_call_return_effect` if `target` is a + /// `Call` terminator whose callee is convergent. + pub fn seek_after_assume_call_returns(&mut self, target: Location) { + assert!(target <= self.body.terminator_loc(target.block)); + + self._seek_after(target); + + if target != self.body.terminator_loc(target.block) { + return; + } + + let term = self.body.basic_blocks()[target.block].terminator(); + if let mir::TerminatorKind::Call { + destination: Some((return_place, _)), + func, + args, + .. + } = &term.kind { + if !self.is_call_return_effect_applied { + self.is_call_return_effect_applied = true; + self.results.borrow().analysis.apply_call_return_effect( + &mut self.state, + target.block, + func, + args, + return_place, + ); + } + } + } + + fn _seek_after(&mut self, target: Location) { + let Location { block: target_block, statement_index: target_index } = target; + + if self.pos.block() != target_block { + self.seek_to_block_start(target_block); + } + + // If we're in the same block but after the target statement, we need to reset to the start + // of the block. + if let CursorPosition::After(Location { statement_index: curr_index, .. }) = self.pos { + match curr_index.cmp(&target_index) { + Ordering::Equal => return, + Ordering::Less => {}, + Ordering::Greater => self.seek_to_block_start(target_block), + } + } + + // The cursor is now in the same block as the target location pointing at an earlier + // statement. + debug_assert_eq!(self.pos.block(), target_block); + if let CursorPosition::After(Location { statement_index, .. }) = self.pos { + debug_assert!(statement_index < target_index); + } + + let first_unapplied_statement = match self.pos { + CursorPosition::AtBlockStart(_) => 0, + CursorPosition::After(Location { statement_index, .. }) => statement_index + 1, + }; + + let block_data = &self.body.basic_blocks()[target_block]; + self.results.borrow().analysis.apply_partial_block_effect( + &mut self.state, + target_block, + block_data, + first_unapplied_statement..target_index + 1, + ); + + self.pos = CursorPosition::After(target); + self.is_call_return_effect_applied = false; + } + + /// Gets the dataflow state at the current location. + pub fn get(&self) -> &BitSet { + &self.state + } +} + +/// A completed dataflow analysis. +pub struct Results<'tcx, A> +where + A: Analysis<'tcx>, +{ + analysis: A, + entry_sets: IndexVec>, +} + +/// All information required to iterate a dataflow analysis to fixpoint. +pub struct Engine<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + analysis: A, + bits_per_block: usize, + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, + def_id: DefId, + dead_unwinds: &'a BitSet, + entry_sets: IndexVec>, +} + +impl Engine<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + pub fn new( + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, + def_id: DefId, + dead_unwinds: &'a BitSet, + analysis: A, + ) -> Self { + let bits_per_block = analysis.bits_per_block(body); + + let bottom_value_set = if A::BOTTOM_VALUE == true { + BitSet::new_filled(bits_per_block) + } else { + BitSet::new_empty(bits_per_block) + }; + + let mut entry_sets = IndexVec::from_elem(bottom_value_set, body.basic_blocks()); + analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]); + + Engine { + analysis, + bits_per_block, + tcx, + body, + def_id, + dead_unwinds, + entry_sets, + } + } + + pub fn iterate_to_fixpoint(mut self) -> Results<'tcx, A> { + let mut temp_state = BitSet::new_empty(self.bits_per_block); + + let mut dirty_queue: WorkQueue = + WorkQueue::with_none(self.body.basic_blocks().len()); + + for (bb, _) in traversal::reverse_postorder(self.body) { + dirty_queue.insert(bb); + } + + // Add blocks that are not reachable from START_BLOCK to the work queue. These blocks will + // be processed after the ones added above. + for bb in self.body.basic_blocks().indices() { + dirty_queue.insert(bb); + } + + while let Some(bb) = dirty_queue.pop() { + let bb_data = &self.body[bb]; + let on_entry = &self.entry_sets[bb]; + + temp_state.overwrite(on_entry); + self.analysis.apply_whole_block_effect(&mut temp_state, bb, bb_data); + + self.propagate_bits_into_graph_successors_of( + &mut temp_state, + (bb, bb_data), + &mut dirty_queue, + ); + } + + let Engine { + tcx, + body, + def_id, + analysis, + entry_sets, + .. + } = self; + + let results = Results { analysis, entry_sets }; + + let attrs = tcx.get_attrs(def_id); + if let Some(path) = get_dataflow_graphviz_output_path(tcx, attrs, A::NAME) { + let result = write_dataflow_graphviz_results(body, def_id, &path, &results); + if let Err(e) = result { + warn!("Failed to write dataflow results to {}: {}", path.display(), e); + } + } + + results + } + + fn propagate_bits_into_graph_successors_of( + &mut self, + in_out: &mut BitSet, + (bb, bb_data): (BasicBlock, &'a mir::BasicBlockData<'tcx>), + dirty_list: &mut WorkQueue, + ) { + match bb_data.terminator().kind { + mir::TerminatorKind::Return + | mir::TerminatorKind::Resume + | mir::TerminatorKind::Abort + | mir::TerminatorKind::GeneratorDrop + | mir::TerminatorKind::Unreachable => {} + + mir::TerminatorKind::Goto { target } + | mir::TerminatorKind::Assert { target, cleanup: None, .. } + | mir::TerminatorKind::Yield { resume: target, drop: None, .. } + | mir::TerminatorKind::Drop { target, location: _, unwind: None } + | mir::TerminatorKind::DropAndReplace { target, value: _, location: _, unwind: None } => + { + self.propagate_bits_into_entry_set_for(in_out, target, dirty_list); + } + + mir::TerminatorKind::Yield { resume: target, drop: Some(drop), .. } => { + self.propagate_bits_into_entry_set_for(in_out, target, dirty_list); + self.propagate_bits_into_entry_set_for(in_out, drop, dirty_list); + } + + mir::TerminatorKind::Assert { target, cleanup: Some(unwind), .. } + | mir::TerminatorKind::Drop { target, location: _, unwind: Some(unwind) } + | mir::TerminatorKind::DropAndReplace { + target, + value: _, + location: _, + unwind: Some(unwind), + } => { + self.propagate_bits_into_entry_set_for(in_out, target, dirty_list); + if !self.dead_unwinds.contains(bb) { + self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list); + } + } + + mir::TerminatorKind::SwitchInt { ref targets, .. } => { + for target in targets { + self.propagate_bits_into_entry_set_for(in_out, *target, dirty_list); + } + } + + mir::TerminatorKind::Call { cleanup, ref destination, ref func, ref args, .. } => { + if let Some(unwind) = cleanup { + if !self.dead_unwinds.contains(bb) { + self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list); + } + } + + if let Some((ref dest_place, dest_bb)) = *destination { + // N.B.: This must be done *last*, after all other + // propagation, as documented in comment above. + self.analysis.apply_call_return_effect(in_out, bb, func, args, dest_place); + self.propagate_bits_into_entry_set_for(in_out, dest_bb, dirty_list); + } + } + + mir::TerminatorKind::FalseEdges { real_target, imaginary_target } => { + self.propagate_bits_into_entry_set_for(in_out, real_target, dirty_list); + self.propagate_bits_into_entry_set_for(in_out, imaginary_target, dirty_list); + } + + mir::TerminatorKind::FalseUnwind { real_target, unwind } => { + self.propagate_bits_into_entry_set_for(in_out, real_target, dirty_list); + if let Some(unwind) = unwind { + if !self.dead_unwinds.contains(bb) { + self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list); + } + } + } + } + } + + fn propagate_bits_into_entry_set_for( + &mut self, + in_out: &BitSet, + bb: BasicBlock, + dirty_queue: &mut WorkQueue, + ) { + let entry_set = &mut self.entry_sets[bb]; + let set_changed = self.analysis.join(entry_set, &in_out); + if set_changed { + dirty_queue.insert(bb); + } + } +} + +/// Looks for attributes like `#[rustc_mir(borrowck_graphviz_postflow="./path/to/suffix.dot")]` and +/// extracts the path with the given analysis name prepended to the suffix. +/// +/// Returns `None` if no such attribute exists. +fn get_dataflow_graphviz_output_path( + tcx: TyCtxt<'tcx>, + attrs: ty::Attributes<'tcx>, + analysis: &str, +) -> Option { + let mut rustc_mir_attrs = attrs + .into_iter() + .filter(|attr| attr.check_name(sym::rustc_mir)) + .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter())); + + let borrowck_graphviz_postflow = rustc_mir_attrs + .find(|attr| attr.check_name(sym::borrowck_graphviz_postflow))?; + + let path_and_suffix = match borrowck_graphviz_postflow.value_str() { + Some(p) => p, + None => { + tcx.sess.span_err( + borrowck_graphviz_postflow.span(), + "borrowck_graphviz_postflow requires a path", + ); + + return None; + } + }; + + // Change "path/suffix.dot" to "path/analysis_name_suffix.dot" + let mut ret = PathBuf::from(path_and_suffix.to_string()); + let suffix = ret.file_name().unwrap(); + + let mut file_name: OsString = analysis.into(); + file_name.push("_"); + file_name.push(suffix); + ret.set_file_name(file_name); + + Some(ret) +} + +fn write_dataflow_graphviz_results>( + body: &mir::Body<'tcx>, + def_id: DefId, + path: &Path, + results: &Results<'tcx, A> +) -> io::Result<()> { + debug!("printing dataflow results for {:?} to {}", def_id, path.display()); + + let mut buf = Vec::new(); + let graphviz = graphviz::Formatter::new(body, def_id, results); + + dot::render(&graphviz, &mut buf)?; + fs::write(path, buf) +} diff --git a/src/librustc_mir/dataflow/generic/graphviz.rs b/src/librustc_mir/dataflow/generic/graphviz.rs new file mode 100644 index 0000000000000..47ace8f33ecac --- /dev/null +++ b/src/librustc_mir/dataflow/generic/graphviz.rs @@ -0,0 +1,413 @@ +use std::cell::RefCell; +use std::io::{self, Write}; +use std::{ops, str}; + +use rustc::hir::def_id::DefId; +use rustc::mir::{self, BasicBlock, Body, Location}; +use rustc_index::bit_set::{BitSet, HybridBitSet}; +use rustc_index::vec::Idx; + +use crate::util::graphviz_safe_def_name; +use super::{Analysis, Results, ResultsRefCursor}; + +pub struct Formatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + body: &'a Body<'tcx>, + def_id: DefId, + + // This must be behind a `RefCell` because `dot::Labeller` takes `&self`. + block_formatter: RefCell>, +} + +impl Formatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + pub fn new( + body: &'a Body<'tcx>, + def_id: DefId, + results: &'a Results<'tcx, A>, + ) -> Self { + let block_formatter = BlockFormatter { + bg: Background::Light, + prev_state: BitSet::new_empty(results.analysis.bits_per_block(body)), + results: ResultsRefCursor::new(body, results), + }; + + Formatter { + body, + def_id, + block_formatter: RefCell::new(block_formatter), + } + } +} + +/// A pair of a basic block and an index into that basic blocks `successors`. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct CfgEdge { + source: BasicBlock, + index: usize, +} + +fn outgoing_edges(body: &Body<'_>, bb: BasicBlock) -> Vec { + body[bb] + .terminator() + .successors() + .enumerate() + .map(|(index, _)| CfgEdge { source: bb, index }) + .collect() +} + +impl dot::Labeller<'_> for Formatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + type Node = BasicBlock; + type Edge = CfgEdge; + + fn graph_id(&self) -> dot::Id<'_> { + let name = graphviz_safe_def_name(self.def_id); + dot::Id::new(format!("graph_for_def_id_{}", name)).unwrap() + } + + fn node_id(&self, n: &Self::Node) -> dot::Id<'_> { + dot::Id::new(format!("bb_{}", n.index())).unwrap() + } + + fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { + let mut label = Vec::new(); + self.block_formatter + .borrow_mut() + .write_node_label(&mut label, self.body, *block) + .unwrap(); + dot::LabelText::html(String::from_utf8(label).unwrap()) + } + + fn node_shape(&self, _n: &Self::Node) -> Option> { + Some(dot::LabelText::label("none")) + } + + fn edge_label(&self, e: &Self::Edge) -> dot::LabelText<'_> { + let label = &self.body + [e.source] + .terminator() + .kind + .fmt_successor_labels() + [e.index]; + dot::LabelText::label(label.clone()) + } +} + +impl dot::GraphWalk<'a> for Formatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + type Node = BasicBlock; + type Edge = CfgEdge; + + fn nodes(&self) -> dot::Nodes<'_, Self::Node> { + self.body + .basic_blocks() + .indices() + .collect::>() + .into() + } + + fn edges(&self) -> dot::Edges<'_, Self::Edge> { + self.body + .basic_blocks() + .indices() + .flat_map(|bb| outgoing_edges(self.body, bb)) + .collect::>() + .into() + } + + fn source(&self, edge: &Self::Edge) -> Self::Node { + edge.source + } + + fn target(&self, edge: &Self::Edge) -> Self::Node { + self.body + [edge.source] + .terminator() + .successors() + .nth(edge.index) + .copied() + .unwrap() + } +} + +struct BlockFormatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + prev_state: BitSet, + results: ResultsRefCursor<'a, 'a, 'tcx, A>, + bg: Background, +} + +impl BlockFormatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + fn toggle_background(&mut self) -> Background { + let bg = self.bg; + self.bg = !bg; + bg + } + + fn write_node_label( + &mut self, + w: &mut impl io::Write, + body: &'a Body<'tcx>, + block: BasicBlock, + ) -> io::Result<()> { + // Sample output: + // +-+-----------------------------------------------+ + // A | bb4 | + // +-+----------------------------------+------------+ + // B | MIR | STATE | + // +-+----------------------------------+------------+ + // C | | (on entry) | {_0,_2,_3} | + // +-+----------------------------------+------------+ + // D |0| StorageLive(_7) | | + // +-+----------------------------------+------------+ + // |1| StorageLive(_8) | | + // +-+----------------------------------+------------+ + // |2| _8 = &mut _1 | +_8 | + // +-+----------------------------------+------------+ + // E |T| _4 = const Foo::twiddle(move _2) | -_2 | + // +-+----------------------------------+------------+ + // F | | (on unwind) | {_0,_3,_8} | + // +-+----------------------------------+------------+ + // | | (on successful return) | +_4 | + // +-+----------------------------------+------------+ + + write!( + w, + r#""#, + )?; + + // A: Block info + write!( + w, + r#" + + "#, + num_headers = 3, + block_id = block.index(), + )?; + + // B: Column headings + write!( + w, + r#" + + + "#, + fmt = r##"bgcolor="#a0a0a0" sides="tl""##, + )?; + + // C: Entry state + self.bg = Background::Light; + self.results.seek_to_block_start(block); + self.write_row_with_curr_state(w, "", "(on entry)")?; + self.prev_state.overwrite(self.results.get()); + + // D: Statement transfer functions + for (i, statement) in body[block].statements.iter().enumerate() { + let location = Location { block, statement_index: i }; + + let mir_col = format!("{:?}", statement); + let i_col = i.to_string(); + + self.results.seek_after(location); + self.write_row_with_curr_diff(w, &i_col, &mir_col)?; + self.prev_state.overwrite(self.results.get()); + } + + // E: Terminator transfer function + let terminator = body[block].terminator(); + let location = body.terminator_loc(block); + + let mut mir_col = String::new(); + terminator.kind.fmt_head(&mut mir_col).unwrap(); + + self.results.seek_after(location); + self.write_row_with_curr_diff(w, "T", &mir_col)?; + self.prev_state.overwrite(self.results.get()); + + // F: Exit state + if let mir::TerminatorKind::Call { destination: Some(_), .. } = &terminator.kind { + self.write_row_with_curr_state(w, "", "(on unwind)")?; + + self.results.seek_after_assume_call_returns(location); + self.write_row_with_curr_diff(w, "", "(on successful return)")?; + } else { + self.write_row_with_curr_state(w, "", "(on exit)")?; + } + + write!(w, "
bb{block_id}
MIRSTATE
") + } + + fn write_row_with_curr_state( + &mut self, + w: &mut impl io::Write, + i: &str, + mir: &str, + ) -> io::Result<()> { + let bg = self.toggle_background(); + + let mut out = Vec::new(); + write!(&mut out, "{{")?; + pretty_print_state_elems(&mut out, self.results.analysis(), self.results.get().iter())?; + write!(&mut out, "}}")?; + + write!( + w, + r#" + {i} + {mir} + {state} + "#, + fmt = &["sides=\"tl\"", bg.attr()].join(" "), + i = i, + mir = dot::escape_html(mir), + state = dot::escape_html(str::from_utf8(&out).unwrap()), + ) + } + + fn write_row_with_curr_diff( + &mut self, + w: &mut impl io::Write, + i: &str, + mir: &str, + ) -> io::Result<()> { + let bg = self.toggle_background(); + let analysis = self.results.analysis(); + + let diff = BitSetDiff::compute(&self.prev_state, self.results.get()); + + let mut set = Vec::new(); + pretty_print_state_elems(&mut set, analysis, diff.set.iter())?; + + let mut clear = Vec::new(); + pretty_print_state_elems(&mut clear, analysis, diff.clear.iter())?; + + write!( + w, + r#" + {i} + {mir} + "#, + i = i, + fmt = &["sides=\"tl\"", bg.attr()].join(" "), + mir = dot::escape_html(mir), + )?; + + if !set.is_empty() { + write!( + w, + r#"+{}"#, + dot::escape_html(str::from_utf8(&set).unwrap()), + )?; + } + + if !set.is_empty() && !clear.is_empty() { + write!(w, " ")?; + } + + if !clear.is_empty() { + write!( + w, + r#"-{}"#, + dot::escape_html(str::from_utf8(&clear).unwrap()), + )?; + } + + write!(w, "") + } +} + +/// The operations required to transform one `BitSet` into another. +struct BitSetDiff { + set: HybridBitSet, + clear: HybridBitSet, +} + +impl BitSetDiff { + fn compute(from: &BitSet, to: &BitSet) -> Self { + assert_eq!(from.domain_size(), to.domain_size()); + let len = from.domain_size(); + + let mut set = HybridBitSet::new_empty(len); + let mut clear = HybridBitSet::new_empty(len); + + // FIXME: This could be made faster if `BitSet::xor` were implemented. + for i in (0..len).map(|i| T::new(i)) { + match (from.contains(i), to.contains(i)) { + (false, true) => set.insert(i), + (true, false) => clear.insert(i), + _ => continue, + }; + } + + BitSetDiff { + set, + clear, + } + } +} + +/// Formats each `elem` using the pretty printer provided by `analysis` into a comma-separated +/// list. +fn pretty_print_state_elems
( + w: &mut impl io::Write, + analysis: &A, + elems: impl Iterator, +) -> io::Result<()> +where + A: Analysis<'tcx>, +{ + let mut first = true; + for idx in elems { + if first { + first = false; + } else { + write!(w, ",")?; + } + + analysis.pretty_print_idx(w, idx)?; + } + + Ok(()) +} + +/// The background color used for zebra-striping the table. +#[derive(Clone, Copy)] +enum Background { + Light, + Dark, +} + +impl Background { + fn attr(self) -> &'static str { + match self { + Self::Dark => "bgcolor=\"#f0f0f0\"", + Self::Light => "", + } + } +} + +impl ops::Not for Background { + type Output = Self; + + fn not(self) -> Self { + match self { + Self::Light => Self::Dark, + Self::Dark => Self::Light, + } + } +} diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs index d94ebdbae24ae..1c43a553cc3c9 100644 --- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs +++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs @@ -93,19 +93,10 @@ struct BorrowedLocalsVisitor<'gk> { } fn find_local(place: &Place<'_>) -> Option { - place.iterate(|place_base, place_projection| { - for proj in place_projection { - if proj.elem == ProjectionElem::Deref { - return None; - } - } - - if let PlaceBase::Local(local) = place_base { - Some(*local) - } else { - None - } - }) + match place.base { + PlaceBase::Local(local) if !place.is_indirect() => Some(local), + _ => None, + } } impl<'tcx> Visitor<'tcx> for BorrowedLocalsVisitor<'_> { diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 018fd2e97b264..5e64144df2cd1 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -5,9 +5,9 @@ use rustc::mir::{self, Location, Place, PlaceBase, Body}; use rustc::ty::{self, TyCtxt}; use rustc::ty::RegionVid; -use rustc_data_structures::bit_set::BitSet; +use rustc_index::bit_set::BitSet; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_index::vec::{Idx, IndexVec}; use crate::dataflow::{BitDenotation, BottomValue, GenKillSet}; use crate::borrow_check::nll::region_infer::RegionInferenceContext; @@ -16,7 +16,7 @@ use crate::borrow_check::places_conflict; use std::rc::Rc; -newtype_index! { +rustc_index::newtype_index! { pub struct BorrowIndex { DEBUG_FORMAT = "bw{}" } @@ -208,7 +208,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { // If the borrowed place is a local with no projections, all other borrows of this // local must conflict. This is purely an optimization so we don't have to call // `places_conflict` for every borrow. - if place.projection.is_none() { + if place.projection.is_empty() { trans.kill_all(other_borrows_of_local); return; } @@ -268,12 +268,8 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> { debug!("Borrows::statement_effect: stmt={:?}", stmt); match stmt.kind { - mir::StatementKind::Assign(ref lhs, ref rhs) => { - // Make sure there are no remaining borrows for variables - // that are assigned over. - self.kill_borrows_on_place(trans, lhs); - - if let mir::Rvalue::Ref(_, _, ref place) = **rhs { + mir::StatementKind::Assign(box(ref lhs, ref rhs)) => { + if let mir::Rvalue::Ref(_, _, ref place) = *rhs { if place.ignore_borrow( self.tcx, self.body, @@ -287,6 +283,10 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> { trans.gen(*index); } + + // Make sure there are no remaining borrows for variables + // that are assigned over. + self.kill_borrows_on_place(trans, lhs); } mir::StatementKind::StorageDead(local) => { diff --git a/src/librustc_mir/dataflow/impls/indirect_mutation.rs b/src/librustc_mir/dataflow/impls/indirect_mutation.rs new file mode 100644 index 0000000000000..990425c3252e0 --- /dev/null +++ b/src/librustc_mir/dataflow/impls/indirect_mutation.rs @@ -0,0 +1,164 @@ +use rustc::mir::visit::Visitor; +use rustc::mir::{self, Local, Location}; +use rustc::ty::{self, TyCtxt}; +use rustc_index::bit_set::BitSet; +use syntax_pos::DUMMY_SP; + +use crate::dataflow::{self, GenKillSet}; + +/// Whether a borrow to a `Local` has been created that could allow that `Local` to be mutated +/// indirectly. This could either be a mutable reference (`&mut`) or a shared borrow if the type of +/// that `Local` allows interior mutability. Operations that can mutate local's indirectly include: +/// assignments through a pointer (`*p = 42`), function calls, drop terminators and inline assembly. +/// +/// If this returns false for a `Local` at a given statement (or terminator), that `Local` could +/// not possibly have been mutated indirectly prior to that statement. +#[derive(Copy, Clone)] +pub struct IndirectlyMutableLocals<'mir, 'tcx> { + body: &'mir mir::Body<'tcx>, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, +} + +impl<'mir, 'tcx> IndirectlyMutableLocals<'mir, 'tcx> { + pub fn new( + tcx: TyCtxt<'tcx>, + body: &'mir mir::Body<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> Self { + IndirectlyMutableLocals { body, tcx, param_env } + } + + fn transfer_function<'a>( + &self, + trans: &'a mut GenKillSet, + ) -> TransferFunction<'a, 'mir, 'tcx> { + TransferFunction { + body: self.body, + tcx: self.tcx, + param_env: self.param_env, + trans + } + } +} + +impl<'mir, 'tcx> dataflow::BitDenotation<'tcx> for IndirectlyMutableLocals<'mir, 'tcx> { + type Idx = Local; + + fn name() -> &'static str { "mut_borrowed_locals" } + + fn bits_per_block(&self) -> usize { + self.body.local_decls.len() + } + + fn start_block_effect(&self, _entry_set: &mut BitSet) { + // Nothing is borrowed on function entry + } + + fn statement_effect( + &self, + trans: &mut GenKillSet, + loc: Location, + ) { + let stmt = &self.body[loc.block].statements[loc.statement_index]; + self.transfer_function(trans).visit_statement(stmt, loc); + } + + fn terminator_effect( + &self, + trans: &mut GenKillSet, + loc: Location, + ) { + let terminator = self.body[loc.block].terminator(); + self.transfer_function(trans).visit_terminator(terminator, loc); + } + + fn propagate_call_return( + &self, + _in_out: &mut BitSet, + _call_bb: mir::BasicBlock, + _dest_bb: mir::BasicBlock, + _dest_place: &mir::Place<'tcx>, + ) { + // Nothing to do when a call returns successfully + } +} + +impl<'mir, 'tcx> dataflow::BottomValue for IndirectlyMutableLocals<'mir, 'tcx> { + // bottom = unborrowed + const BOTTOM_VALUE: bool = false; +} + +/// A `Visitor` that defines the transfer function for `IndirectlyMutableLocals`. +struct TransferFunction<'a, 'mir, 'tcx> { + trans: &'a mut GenKillSet, + body: &'mir mir::Body<'tcx>, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, +} + +impl<'tcx> TransferFunction<'_, '_, 'tcx> { + /// Returns `true` if this borrow would allow mutation of the `borrowed_place`. + fn borrow_allows_mutation( + &self, + kind: mir::BorrowKind, + borrowed_place: &mir::Place<'tcx>, + ) -> bool { + let borrowed_ty = borrowed_place.ty(self.body, self.tcx).ty; + + // Zero-sized types cannot be mutated, since there is nothing inside to mutate. + // + // FIXME: For now, we only exempt arrays of length zero. We need to carefully + // consider the effects before extending this to all ZSTs. + if let ty::Array(_, len) = borrowed_ty.kind { + if len.try_eval_usize(self.tcx, self.param_env) == Some(0) { + return false; + } + } + + match kind { + mir::BorrowKind::Mut { .. } => true, + + | mir::BorrowKind::Shared + | mir::BorrowKind::Shallow + | mir::BorrowKind::Unique + => !borrowed_ty.is_freeze(self.tcx, self.param_env, DUMMY_SP), + } + } +} + +impl<'tcx> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx> { + fn visit_rvalue( + &mut self, + rvalue: &mir::Rvalue<'tcx>, + location: Location, + ) { + if let mir::Rvalue::Ref(_, kind, ref borrowed_place) = *rvalue { + if self.borrow_allows_mutation(kind, borrowed_place) { + match borrowed_place.base { + mir::PlaceBase::Local(borrowed_local) if !borrowed_place.is_indirect() + => self.trans.gen(borrowed_local), + + _ => (), + } + } + } + + self.super_rvalue(rvalue, location); + } + + + fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { + // This method purposely does nothing except call `super_terminator`. It exists solely to + // document the subtleties around drop terminators. + + self.super_terminator(terminator, location); + + if let mir::TerminatorKind::Drop { location: _, .. } + | mir::TerminatorKind::DropAndReplace { location: _, .. } = &terminator.kind + { + // Although drop terminators mutably borrow the location being dropped, that borrow + // cannot live beyond the drop terminator because the dropped location is invalidated. + } + } +} diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index 69bbe08792140..6f860d00a22c2 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -4,8 +4,8 @@ use rustc::ty::TyCtxt; use rustc::mir::{self, Body, Location}; -use rustc_data_structures::bit_set::BitSet; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::Idx; use super::MoveDataParamEnv; @@ -18,13 +18,13 @@ use super::drop_flag_effects_for_function_entry; use super::drop_flag_effects_for_location; use super::on_lookup_result_bits; -mod storage_liveness; - -pub use self::storage_liveness::*; - mod borrowed_locals; +mod indirect_mutation; +mod storage_liveness; pub use self::borrowed_locals::*; +pub use self::indirect_mutation::IndirectlyMutableLocals; +pub use self::storage_liveness::*; pub(super) mod borrows; diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs index 0e01701ea9e44..c1695ba66d0d5 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs @@ -109,18 +109,16 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> { assert_eq!(1, self.body.arg_count); } - fn statement_effect(&self, - sets: &mut GenKillSet, - loc: Location) { - self.check_for_move(sets, loc); + fn before_statement_effect(&self, sets: &mut GenKillSet, loc: Location) { + // If we borrow or assign to a place then it needs storage for that + // statement. self.check_for_borrow(sets, loc); let stmt = &self.body[loc.block].statements[loc.statement_index]; match stmt.kind { - StatementKind::StorageLive(l) => sets.gen(l), StatementKind::StorageDead(l) => sets.kill(l), - StatementKind::Assign(ref place, _) - | StatementKind::SetDiscriminant { ref place, .. } => { + StatementKind::Assign(box(ref place, _)) + | StatementKind::SetDiscriminant { box ref place, .. } => { if let PlaceBase::Local(local) = place.base { sets.gen(local); } @@ -136,11 +134,35 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> { } } - fn terminator_effect(&self, - sets: &mut GenKillSet, - loc: Location) { + fn statement_effect(&self, sets: &mut GenKillSet, loc: Location) { + // If we move from a place then only stops needing storage *after* + // that statement. self.check_for_move(sets, loc); + } + + fn before_terminator_effect(&self, sets: &mut GenKillSet, loc: Location) { self.check_for_borrow(sets, loc); + + if let TerminatorKind::Call { + destination: Some((Place { base: PlaceBase::Local(local), .. }, _)), + .. + } = self.body[loc.block].terminator().kind { + sets.gen(local); + } + } + + fn terminator_effect(&self, sets: &mut GenKillSet, loc: Location) { + // For call terminators the destination requires storage for the call + // and after the call returns successfully, but not after a panic. + // Since `propagate_call_unwind` doesn't exist, we have to kill the + // destination here, and then gen it again in `propagate_call_return`. + if let TerminatorKind::Call { + destination: Some((Place { base: PlaceBase::Local(local), projection: box [] }, _)), + .. + } = self.body[loc.block].terminator().kind { + sets.kill(local); + } + self.check_for_move(sets, loc); } fn propagate_call_return( diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index 3bdd3e3da048e..06999abdc8b26 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -1,8 +1,8 @@ use syntax::ast::{self, MetaItem}; use syntax::symbol::{Symbol, sym}; -use rustc_data_structures::bit_set::{BitSet, HybridBitSet}; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::bit_set::{BitSet, HybridBitSet}; +use rustc_index::vec::Idx; use rustc_data_structures::work_queue::WorkQueue; use rustc::hir::def_id::DefId; @@ -23,6 +23,7 @@ pub use self::impls::DefinitelyInitializedPlaces; pub use self::impls::EverInitializedPlaces; pub use self::impls::borrows::Borrows; pub use self::impls::HaveBeenBorrowedLocals; +pub use self::impls::IndirectlyMutableLocals; pub use self::at_location::{FlowAtLocation, FlowsAtLocation}; pub(crate) use self::drop_flag_effects::*; @@ -30,6 +31,7 @@ use self::move_paths::MoveData; mod at_location; pub mod drop_flag_effects; +pub mod generic; mod graphviz; mod impls; pub mod move_paths; @@ -56,7 +58,7 @@ where /// string (as well as that of rendering up-front); in exchange, you /// don't have to hand over ownership of your value or deal with /// borrowing it. -pub(crate) struct DebugFormatted(String); +pub struct DebugFormatted(String); impl DebugFormatted { pub fn new(input: &dyn fmt::Debug) -> DebugFormatted { @@ -70,7 +72,7 @@ impl fmt::Debug for DebugFormatted { } } -pub(crate) trait Dataflow<'tcx, BD: BitDenotation<'tcx>> { +pub trait Dataflow<'tcx, BD: BitDenotation<'tcx>> { /// Sets up and runs the dataflow problem, using `p` to render results if /// implementation so chooses. fn dataflow

(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> DebugFormatted { @@ -121,7 +123,7 @@ pub struct MoveDataParamEnv<'tcx> { pub(crate) param_env: ty::ParamEnv<'tcx>, } -pub(crate) fn do_dataflow<'a, 'tcx, BD, P>( +pub fn do_dataflow<'a, 'tcx, BD, P>( tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, def_id: DefId, @@ -453,34 +455,10 @@ where { self.flow_state.each_gen_bit(f) } -} - -pub fn state_for_location<'tcx, T: BitDenotation<'tcx>>(loc: Location, - analysis: &T, - result: &DataflowResults<'tcx, T>, - body: &Body<'tcx>) - -> BitSet { - let mut trans = GenKill::from_elem(HybridBitSet::new_empty(analysis.bits_per_block())); - - for stmt in 0..loc.statement_index { - let mut stmt_loc = loc; - stmt_loc.statement_index = stmt; - analysis.before_statement_effect(&mut trans, stmt_loc); - analysis.statement_effect(&mut trans, stmt_loc); - } - // Apply the pre-statement effect of the statement we're evaluating. - if loc.statement_index == body[loc.block].statements.len() { - analysis.before_terminator_effect(&mut trans, loc); - } else { - analysis.before_statement_effect(&mut trans, loc); + pub fn get(&self) -> &BitSet { + self.flow_state.as_dense() } - - // Apply the transfer function for all preceding statements to the fixpoint - // at the start of the block. - let mut state = result.sets().entry_set_for(loc.block.index()).to_owned(); - trans.apply(&mut state); - state } pub struct DataflowAnalysis<'a, 'tcx, O> @@ -565,7 +543,7 @@ pub struct GenKill { pub(crate) kill_set: T, } -type GenKillSet = GenKill>; +pub type GenKillSet = GenKill>; impl GenKill { /// Creates a new tuple where `gen_set == kill_set == elem`. @@ -580,33 +558,28 @@ impl GenKill { } impl GenKillSet { - pub(crate) fn clear(&mut self) { + pub fn clear(&mut self) { self.gen_set.clear(); self.kill_set.clear(); } - fn gen(&mut self, e: E) { + pub fn gen(&mut self, e: E) { self.gen_set.insert(e); self.kill_set.remove(e); } - fn gen_all(&mut self, i: I) - where I: IntoIterator, - I::Item: Borrow - { + + pub fn gen_all(&mut self, i: impl IntoIterator>) { for j in i { self.gen(*j.borrow()); } } - fn kill(&mut self, e: E) { + pub fn kill(&mut self, e: E) { self.gen_set.remove(e); self.kill_set.insert(e); } - fn kill_all(&mut self, i: I) - where I: IntoIterator, - I::Item: Borrow - { + pub fn kill_all(&mut self, i: impl IntoIterator>) { for j in i { self.kill(*j.borrow()); } diff --git a/src/librustc_mir/dataflow/move_paths/abs_domain.rs b/src/librustc_mir/dataflow/move_paths/abs_domain.rs index b26547c4ff77e..d97f3b7417286 100644 --- a/src/librustc_mir/dataflow/move_paths/abs_domain.rs +++ b/src/librustc_mir/dataflow/move_paths/abs_domain.rs @@ -11,7 +11,7 @@ //! `a[x]` would still overlap them both. But that is not this //! representation does today.) -use rustc::mir::{Local, PlaceElem, Operand, ProjectionElem}; +use rustc::mir::{Local, Operand, PlaceElem, ProjectionElem}; use rustc::ty::Ty; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -26,36 +26,36 @@ pub trait Lift { } impl<'tcx> Lift for Operand<'tcx> { type Abstract = AbstractOperand; - fn lift(&self) -> Self::Abstract { AbstractOperand } + fn lift(&self) -> Self::Abstract { + AbstractOperand + } } impl Lift for Local { type Abstract = AbstractOperand; - fn lift(&self) -> Self::Abstract { AbstractOperand } + fn lift(&self) -> Self::Abstract { + AbstractOperand + } } impl<'tcx> Lift for Ty<'tcx> { type Abstract = AbstractType; - fn lift(&self) -> Self::Abstract { AbstractType } + fn lift(&self) -> Self::Abstract { + AbstractType + } } impl<'tcx> Lift for PlaceElem<'tcx> { type Abstract = AbstractElem; fn lift(&self) -> Self::Abstract { match *self { - ProjectionElem::Deref => - ProjectionElem::Deref, - ProjectionElem::Field(ref f, ty) => - ProjectionElem::Field(f.clone(), ty.lift()), - ProjectionElem::Index(ref i) => - ProjectionElem::Index(i.lift()), - ProjectionElem::Subslice {from, to} => - ProjectionElem::Subslice { from: from, to: to }, - ProjectionElem::ConstantIndex {offset,min_length,from_end} => - ProjectionElem::ConstantIndex { - offset, - min_length, - from_end, - }, - ProjectionElem::Downcast(a, u) => - ProjectionElem::Downcast(a, u.clone()), + ProjectionElem::Deref => ProjectionElem::Deref, + ProjectionElem::Field(ref f, ty) => ProjectionElem::Field(f.clone(), ty.lift()), + ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()), + ProjectionElem::Subslice { from, to } => { + ProjectionElem::Subslice { from: from, to: to } + } + ProjectionElem::ConstantIndex { offset, min_length, from_end } => { + ProjectionElem::ConstantIndex { offset, min_length, from_end } + } + ProjectionElem::Downcast(a, u) => ProjectionElem::Downcast(a, u.clone()), } } } diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 366b96b53b423..53b18e4364b95 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -1,16 +1,18 @@ -use rustc::ty::{self, TyCtxt}; -use rustc::mir::*; use rustc::mir::tcx::RvalueInitializationState; -use rustc_data_structures::indexed_vec::{IndexVec}; -use smallvec::{SmallVec, smallvec}; +use rustc::mir::*; +use rustc::ty::{self, TyCtxt}; +use rustc_index::vec::IndexVec; +use smallvec::{smallvec, SmallVec}; use std::collections::hash_map::Entry; use std::mem; use super::abs_domain::Lift; -use super::{LocationMap, MoveData, MovePath, MovePathLookup, MovePathIndex, MoveOut, MoveOutIndex}; -use super::{MoveError, InitIndex, Init, InitLocation, LookupResult, InitKind}; use super::IllegalMoveOriginKind::*; +use super::{Init, InitIndex, InitKind, InitLocation, LookupResult, MoveError}; +use super::{ + LocationMap, MoveData, MoveOut, MoveOutIndex, MovePath, MovePathIndex, MovePathLookup, +}; struct MoveDataBuilder<'a, 'tcx> { body: &'a Body<'tcx>, @@ -33,15 +35,19 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { moves: IndexVec::new(), loc_map: LocationMap::new(body), rev_lookup: MovePathLookup { - locals: body.local_decls.indices().map(|i| { - Self::new_move_path( - &mut move_paths, - &mut path_map, - &mut init_path_map, - None, - Place::from(i), - ) - }).collect(), + locals: body + .local_decls + .indices() + .map(|i| { + Self::new_move_path( + &mut move_paths, + &mut path_map, + &mut init_path_map, + None, + Place::from(i), + ) + }) + .collect(), projections: Default::default(), }, move_paths, @@ -49,27 +55,22 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { inits: IndexVec::new(), init_loc_map: LocationMap::new(body), init_path_map, - } + }, } } - fn new_move_path(move_paths: &mut IndexVec>, - path_map: &mut IndexVec>, - init_path_map: &mut IndexVec>, - parent: Option, - place: Place<'tcx>) - -> MovePathIndex - { - let move_path = move_paths.push(MovePath { - next_sibling: None, - first_child: None, - parent, - place, - }); + fn new_move_path( + move_paths: &mut IndexVec>, + path_map: &mut IndexVec>, + init_path_map: &mut IndexVec>, + parent: Option, + place: Place<'tcx>, + ) -> MovePathIndex { + let move_path = + move_paths.push(MovePath { next_sibling: None, first_child: None, parent, place }); if let Some(parent) = parent { - let next_sibling = - mem::replace(&mut move_paths[parent].first_child, Some(move_path)); + let next_sibling = mem::replace(&mut move_paths[parent].first_child, Some(move_path)); move_paths[move_path].next_sibling = next_sibling; } @@ -91,69 +92,76 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { /// problematic for borrowck. /// /// Maybe we should have separate "borrowck" and "moveck" modes. - fn move_path_for(&mut self, place: &Place<'tcx>) - -> Result> - { + fn move_path_for(&mut self, place: &Place<'tcx>) -> Result> { debug!("lookup({:?})", place); - place.iterate(|place_base, place_projection| { - let mut base = match place_base { - PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[*local], - PlaceBase::Static(..) => { - return Err(MoveError::cannot_move_out_of(self.loc, Static)); - } - }; + let mut base = match place.base { + PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[local], + PlaceBase::Static(..) => { + return Err(MoveError::cannot_move_out_of(self.loc, Static)); + } + }; - for proj in place_projection { - let body = self.builder.body; - let tcx = self.builder.tcx; - let place_ty = Place::ty_from(place_base, &proj.base, body, tcx).ty; - match place_ty.sty { - ty::Ref(..) | ty::RawPtr(..) => - return Err(MoveError::cannot_move_out_of( - self.loc, - BorrowedContent { - target_place: Place { - base: place_base.clone(), - projection: Some(Box::new(proj.clone())), - } - })), - ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => - return Err(MoveError::cannot_move_out_of(self.loc, - InteriorOfTypeWithDestructor { - container_ty: place_ty - })), - // move out of union - always move the entire union - ty::Adt(adt, _) if adt.is_union() => - return Err(MoveError::UnionMove { path: base }), - ty::Slice(_) => + for (i, elem) in place.projection.iter().enumerate() { + let proj_base = &place.projection[..i]; + let body = self.builder.body; + let tcx = self.builder.tcx; + let place_ty = Place::ty_from(&place.base, proj_base, body, tcx).ty; + match place_ty.kind { + ty::Ref(..) | ty::RawPtr(..) => { + let proj = &place.projection[..i+1]; + return Err(MoveError::cannot_move_out_of( + self.loc, + BorrowedContent { + target_place: Place { + base: place.base.clone(), + projection: proj.to_vec().into_boxed_slice(), + }, + }, + )); + } + ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => { + return Err(MoveError::cannot_move_out_of( + self.loc, + InteriorOfTypeWithDestructor { container_ty: place_ty }, + )); + } + // move out of union - always move the entire union + ty::Adt(adt, _) if adt.is_union() => { + return Err(MoveError::UnionMove { path: base }); + } + ty::Slice(_) => { + return Err(MoveError::cannot_move_out_of( + self.loc, + InteriorOfSliceOrArray { + ty: place_ty, + is_index: match elem { + ProjectionElem::Index(..) => true, + _ => false, + }, + }, + )); + } + ty::Array(..) => match elem { + ProjectionElem::Index(..) => { return Err(MoveError::cannot_move_out_of( self.loc, - InteriorOfSliceOrArray { - ty: place_ty, is_index: match proj.elem { - ProjectionElem::Index(..) => true, - _ => false - }, - })), - ty::Array(..) => match proj.elem { - ProjectionElem::Index(..) => - return Err(MoveError::cannot_move_out_of( - self.loc, - InteriorOfSliceOrArray { - ty: place_ty, is_index: true - })), - _ => { - // FIXME: still badly broken - } - }, - _ => {} - }; + InteriorOfSliceOrArray { ty: place_ty, is_index: true }, + )); + } + _ => { + // FIXME: still badly broken + } + }, + _ => {} + }; - base = match self - .builder - .data - .rev_lookup - .projections - .entry((base, proj.elem.lift())) + let proj = &place.projection[..i+1]; + base = match self + .builder + .data + .rev_lookup + .projections + .entry((base, elem.lift())) { Entry::Occupied(ent) => *ent.get(), Entry::Vacant(ent) => { @@ -163,18 +171,17 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { &mut self.builder.data.init_path_map, Some(base), Place { - base: place_base.clone(), - projection: Some(Box::new(proj.clone())), + base: place.base.clone(), + projection: proj.to_vec().into_boxed_slice(), }, ); ent.insert(path); path } }; - } + } - Ok(base) - }) + Ok(base) } fn create_move_path(&mut self, place: &Place<'tcx>) { @@ -186,7 +193,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { fn finalize( - self + self, ) -> Result, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> { debug!("{}", { debug!("moves for {:?}:", self.body.span); @@ -200,11 +207,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { "done dumping moves" }); - if !self.errors.is_empty() { - Err((self.data, self.errors)) - } else { - Ok(self.data) - } + if !self.errors.is_empty() { Err((self.data, self.errors)) } else { Ok(self.data) } } } @@ -222,10 +225,7 @@ pub(super) fn gather_moves<'tcx>( builder.gather_statement(source, stmt); } - let terminator_loc = Location { - block: bb, - statement_index: block.statements.len() - }; + let terminator_loc = Location { block: bb, statement_index: block.statements.len() }; builder.gather_terminator(terminator_loc, block.terminator()); } @@ -238,11 +238,12 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { let path = self.data.rev_lookup.locals[arg]; let init = self.data.inits.push(Init { - path, kind: InitKind::Deep, location: InitLocation::Argument(arg), + path, + kind: InitKind::Deep, + location: InitLocation::Argument(arg), }); - debug!("gather_args: adding init {:?} of {:?} for argument {:?}", - init, path, arg); + debug!("gather_args: adding init {:?} of {:?} for argument {:?}", init, path, arg); self.data.init_path_map[path].push(init); } @@ -267,7 +268,7 @@ struct Gatherer<'b, 'a, 'tcx> { impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { fn gather_statement(&mut self, stmt: &Statement<'tcx>) { match stmt.kind { - StatementKind::Assign(ref place, ref rval) => { + StatementKind::Assign(box(ref place, ref rval)) => { self.create_move_path(place); if let RvalueInitializationState::Shallow = rval.initialization_state() { // Box starts out uninitialized - need to create a separate @@ -297,26 +298,26 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { StatementKind::StorageDead(local) => { self.gather_move(&Place::from(local)); } - StatementKind::SetDiscriminant{ .. } => { - span_bug!(stmt.source_info.span, - "SetDiscriminant should not exist during borrowck"); + StatementKind::SetDiscriminant { .. } => { + span_bug!( + stmt.source_info.span, + "SetDiscriminant should not exist during borrowck" + ); } - StatementKind::Retag { .. } | - StatementKind::AscribeUserType(..) | - StatementKind::Nop => {} + StatementKind::Retag { .. } + | StatementKind::AscribeUserType(..) + | StatementKind::Nop => {} } } fn gather_rvalue(&mut self, rvalue: &Rvalue<'tcx>) { match *rvalue { - Rvalue::Use(ref operand) | - Rvalue::Repeat(ref operand, _) | - Rvalue::Cast(_, ref operand, _) | - Rvalue::UnaryOp(_, ref operand) => { - self.gather_operand(operand) - } - Rvalue::BinaryOp(ref _binop, ref lhs, ref rhs) | - Rvalue::CheckedBinaryOp(ref _binop, ref lhs, ref rhs) => { + Rvalue::Use(ref operand) + | Rvalue::Repeat(ref operand, _) + | Rvalue::Cast(_, ref operand, _) + | Rvalue::UnaryOp(_, ref operand) => self.gather_operand(operand), + Rvalue::BinaryOp(ref _binop, ref lhs, ref rhs) + | Rvalue::CheckedBinaryOp(ref _binop, ref lhs, ref rhs) => { self.gather_operand(lhs); self.gather_operand(rhs); } @@ -325,11 +326,11 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { self.gather_operand(operand); } } - Rvalue::Ref(..) | - Rvalue::Discriminant(..) | - Rvalue::Len(..) | - Rvalue::NullaryOp(NullOp::SizeOf, _) | - Rvalue::NullaryOp(NullOp::Box, _) => { + Rvalue::Ref(..) + | Rvalue::Discriminant(..) + | Rvalue::Len(..) + | Rvalue::NullaryOp(NullOp::SizeOf, _) + | Rvalue::NullaryOp(NullOp::Box, _) => { // This returns an rvalue with uninitialized contents. We can't // move out of it here because it is an rvalue - assignments always // completely initialize their place. @@ -346,16 +347,16 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { fn gather_terminator(&mut self, term: &Terminator<'tcx>) { match term.kind { - TerminatorKind::Goto { target: _ } | - TerminatorKind::Resume | - TerminatorKind::Abort | - TerminatorKind::GeneratorDrop | - TerminatorKind::FalseEdges { .. } | - TerminatorKind::FalseUnwind { .. } | - TerminatorKind::Unreachable => { } + TerminatorKind::Goto { target: _ } + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::GeneratorDrop + | TerminatorKind::FalseEdges { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::Unreachable => {} TerminatorKind::Return => { - self.gather_move(&Place::RETURN_PLACE); + self.gather_move(&Place::return_place()); } TerminatorKind::Assert { ref cond, .. } => { @@ -399,9 +400,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { fn gather_operand(&mut self, operand: &Operand<'tcx>) { match *operand { - Operand::Constant(..) | - Operand::Copy(..) => {} // not-a-move - Operand::Move(ref place) => { // a move + Operand::Constant(..) | Operand::Copy(..) => {} // not-a-move + Operand::Move(ref place) => { + // a move self.gather_move(place); } } @@ -419,8 +420,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { }; let move_out = self.builder.data.moves.push(MoveOut { path: path, source: self.loc }); - debug!("gather_move({:?}, {:?}): adding move {:?} of {:?}", - self.loc, place, move_out, path); + debug!( + "gather_move({:?}, {:?}): adding move {:?} of {:?}", + self.loc, place, move_out, path + ); self.builder.data.path_map[path].push(move_out); self.builder.data.loc_map[self.loc].push(move_out); @@ -433,11 +436,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { // Check if we are assigning into a field of a union, if so, lookup the place // of the union so it is marked as initialized again. - if let Some(box Projection { base: proj_base, elem: ProjectionElem::Field(_, _) }) = - place.projection - { + if let [proj_base @ .., ProjectionElem::Field(_, _)] = place.projection { if let ty::Adt(def, _) = - Place::ty_from(place.base, proj_base, self.builder.body, self.builder.tcx).ty.sty + Place::ty_from(place.base, proj_base, self.builder.body, self.builder.tcx).ty.kind { if def.is_union() { place = PlaceRef { base: place.base, projection: proj_base } @@ -452,8 +453,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { kind, }); - debug!("gather_init({:?}, {:?}): adding init {:?} of {:?}", - self.loc, place, init, path); + debug!( + "gather_init({:?}, {:?}): adding init {:?} of {:?}", + self.loc, place, init, path + ); self.builder.data.init_path_map[path].push(init); self.builder.data.init_loc_map[self.loc].push(init); diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 5c2255882b2c7..f5a03316d809c 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -1,9 +1,10 @@ -use rustc::ty::{Ty, TyCtxt}; +use core::slice::Iter; use rustc::mir::*; +use rustc::ty::{Ty, TyCtxt}; use rustc::util::nodemap::FxHashMap; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_index::vec::{Enumerated, Idx, IndexVec}; use smallvec::SmallVec; -use syntax_pos::{Span}; +use syntax_pos::Span; use std::fmt; use std::ops::{Index, IndexMut}; @@ -12,19 +13,19 @@ use self::abs_domain::{AbstractElem, Lift}; mod abs_domain; -newtype_index! { +rustc_index::newtype_index! { pub struct MovePathIndex { DEBUG_FORMAT = "mp{}" } } -newtype_index! { +rustc_index::newtype_index! { pub struct MoveOutIndex { DEBUG_FORMAT = "mo{}" } } -newtype_index! { +rustc_index::newtype_index! { pub struct InitIndex { DEBUG_FORMAT = "in{}" } @@ -137,12 +138,17 @@ impl IndexMut for LocationMap { } } -impl LocationMap where T: Default + Clone { +impl LocationMap +where + T: Default + Clone, +{ fn new(body: &Body<'_>) -> Self { LocationMap { - map: body.basic_blocks().iter().map(|block| { - vec![T::default(); block.statements.len()+1] - }).collect() + map: body + .basic_blocks() + .iter() + .map(|block| vec![T::default(); block.statements.len() + 1]) + .collect(), } } } @@ -178,7 +184,6 @@ pub struct Init { pub kind: InitKind, } - /// Initializations can be from an argument or from a statement. Arguments /// do not have locations, in those cases the `Local` is kept.. #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -224,7 +229,7 @@ pub struct MovePathLookup { /// subsequent search so that it is solely relative to that /// base-place). For the remaining lookup, we map the projection /// elem to the associated MovePathIndex. - projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex> + projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex>, } mod builder; @@ -232,7 +237,7 @@ mod builder; #[derive(Copy, Clone, Debug)] pub enum LookupResult { Exact(MovePathIndex), - Parent(Option) + Parent(Option), } impl MovePathLookup { @@ -240,28 +245,32 @@ impl MovePathLookup { // alternative will *not* create a MovePath on the fly for an // unknown place, but will rather return the nearest available // parent. - pub fn find(&self, place_ref: PlaceRef<'cx, 'tcx>) -> LookupResult { - place_ref.iterate(|place_base, place_projection| { - let mut result = match place_base { - PlaceBase::Local(local) => self.locals[*local], - PlaceBase::Static(..) => return LookupResult::Parent(None), - }; - - for proj in place_projection { - if let Some(&subpath) = self.projections.get(&(result, proj.elem.lift())) { - result = subpath; - } else { - return LookupResult::Parent(Some(result)); - } + pub fn find(&self, place: PlaceRef<'_, '_>) -> LookupResult { + let mut result = match place.base { + PlaceBase::Local(local) => self.locals[*local], + PlaceBase::Static(..) => return LookupResult::Parent(None), + }; + + for elem in place.projection.iter() { + if let Some(&subpath) = self.projections.get(&(result, elem.lift())) { + result = subpath; + } else { + return LookupResult::Parent(Some(result)); } + } - LookupResult::Exact(result) - }) + LookupResult::Exact(result) } pub fn find_local(&self, local: Local) -> MovePathIndex { self.locals[local] } + + /// An enumerated iterator of `local`s and their associated + /// `MovePathIndex`es. + pub fn iter_locals_enumerated(&self) -> Enumerated> { + self.locals.iter_enumerated() + } } #[derive(Debug)] @@ -289,7 +298,7 @@ pub(crate) enum IllegalMoveOriginKind<'tcx> { InteriorOfTypeWithDestructor { container_ty: Ty<'tcx> }, /// Illegal move due to attempt to move out of a slice or array. - InteriorOfSliceOrArray { ty: Ty<'tcx>, is_index: bool, }, + InteriorOfSliceOrArray { ty: Ty<'tcx>, is_index: bool }, } #[derive(Debug)] @@ -318,11 +327,15 @@ impl<'tcx> MoveData<'tcx> { pub fn base_local(&self, mut mpi: MovePathIndex) -> Option { loop { let path = &self.move_paths[mpi]; - if let Place { - base: PlaceBase::Local(l), - projection: None, - } = path.place { return Some(l); } - if let Some(parent) = path.parent { mpi = parent; continue } else { return None } + if let Place { base: PlaceBase::Local(l), projection: box [] } = path.place { + return Some(l); + } + if let Some(parent) = path.parent { + mpi = parent; + continue; + } else { + return None; + } } } } diff --git a/src/librustc_mir/error_codes.rs b/src/librustc_mir/error_codes.rs index 86c263a447bb6..77853ff1fe80a 100644 --- a/src/librustc_mir/error_codes.rs +++ b/src/librustc_mir/error_codes.rs @@ -1,4 +1,4 @@ -register_long_diagnostics! { +syntax::register_diagnostics! { E0001: r##" @@ -157,81 +157,6 @@ match x { See also the error E0303. "##, -E0008: r##" -Names bound in match arms retain their type in pattern guards. As such, if a -name is bound by move in a pattern, it should also be moved to wherever it is -referenced in the pattern guard code. Doing so however would prevent the name -from being available in the body of the match arm. Consider the following: - -```compile_fail,E0008 -match Some("hi".to_string()) { - Some(s) if s.len() == 0 => {}, // use s. - _ => {}, -} -``` - -The variable `s` has type `String`, and its use in the guard is as a variable of -type `String`. The guard code effectively executes in a separate scope to the -body of the arm, so the value would be moved into this anonymous scope and -therefore becomes unavailable in the body of the arm. - -The problem above can be solved by using the `ref` keyword. - -``` -match Some("hi".to_string()) { - Some(ref s) if s.len() == 0 => {}, - _ => {}, -} -``` - -Though this example seems innocuous and easy to solve, the problem becomes clear -when it encounters functions which consume the value: - -```compile_fail,E0008 -struct A{} - -impl A { - fn consume(self) -> usize { - 0 - } -} - -fn main() { - let a = Some(A{}); - match a { - Some(y) if y.consume() > 0 => {} - _ => {} - } -} -``` - -In this situation, even the `ref` keyword cannot solve it, since borrowed -content cannot be moved. This problem cannot be solved generally. If the value -can be cloned, here is a not-so-specific solution: - -``` -#[derive(Clone)] -struct A{} - -impl A { - fn consume(self) -> usize { - 0 - } -} - -fn main() { - let a = Some(A{}); - match a{ - Some(ref y) if y.clone().consume() > 0 => {} - _ => {} - } -} -``` - -If the value will be consumed in the pattern guard, using its clone will not -move its ownership, so the code works. -"##, - E0009: r##" In a pattern, all values that don't implement the `Copy` trait have to be bound the same way. The goal here is to avoid binding simultaneously by-move and @@ -475,13 +400,15 @@ for item in xs { "##, E0301: r##" +#### Note: this error code is no longer emitted by the compiler. + Mutable borrows are not allowed in pattern guards, because matching cannot have side effects. Side effects could alter the matched object or the environment on which the match depends in such a way, that the match would not be exhaustive. For instance, the following would not match any arm if mutable borrows were allowed: -```compile_fail,E0301 +```compile_fail,E0596 match Some(()) { None => { }, option if option.take().is_none() => { @@ -493,13 +420,15 @@ match Some(()) { "##, E0302: r##" +#### Note: this error code is no longer emitted by the compiler. + Assignments are not allowed in pattern guards, because matching cannot have side effects. Side effects could alter the matched object or the environment on which the match depends in such a way, that the match would not be exhaustive. For instance, the following would not match any arm if assignments were allowed: -```compile_fail,E0302 +```compile_fail,E0594 match Some(()) { None => { }, option if { option = None; false } => { }, @@ -748,7 +677,7 @@ It is not allowed to use or capture an uninitialized variable. For example: ```compile_fail,E0381 fn main() { let x: i32; - let y = x; // error, use of possibly uninitialized variable + let y = x; // error, use of possibly-uninitialized variable } ``` @@ -1024,7 +953,7 @@ https://doc.rust-lang.org/std/cell/ "##, E0388: r##" -E0388 was removed and is no longer issued. +#### Note: this error code is no longer emitted by the compiler. "##, E0389: r##" @@ -1199,6 +1128,51 @@ Remember this solution is unsafe! You will have to ensure that accesses to the cell are synchronized. "##, +E0493: r##" +A type with a `Drop` implementation was destructured when trying to initialize +a static item. + +Erroneous code example: + +```compile_fail,E0493 +enum DropType { + A, +} + +impl Drop for DropType { + fn drop(&mut self) {} +} + +struct Foo { + field1: DropType, +} + +static FOO: Foo = Foo { ..Foo { field1: DropType::A } }; // error! +``` + +The problem here is that if the given type or one of its fields implements the +`Drop` trait, this `Drop` implementation cannot be called during the static +type initialization which might cause a memory leak. To prevent this issue, +you need to instantiate all the static type's fields by hand. + +``` +enum DropType { + A, +} + +impl Drop for DropType { + fn drop(&mut self) {} +} + +struct Foo { + field1: DropType, +} + +static FOO: Foo = Foo { field1: DropType::A }; // We initialize all fields + // by hand. +``` +"##, + E0499: r##" A variable was borrowed as mutable more than once. Erroneous code example: @@ -1717,7 +1691,14 @@ fn print_fancy_ref(fancy_ref: &FancyNum){ "##, E0507: r##" -You tried to move out of a value which was borrowed. Erroneous code example: +You tried to move out of a value which was borrowed. + +This can also happen when using a type implementing `Fn` or `FnMut`, as neither +allows moving out of them (they usually represent closures which can be called +more than once). Much of the text following applies equally well to non-`FnOnce` +closure bodies. + +Erroneous code example: ```compile_fail,E0507 use std::cell::RefCell; @@ -1989,7 +1970,6 @@ When matching on a variable it cannot be mutated in the match guards, as this could cause the match to be non-exhaustive: ```compile_fail,E0510 -#![feature(bind_by_move_pattern_guards)] let mut x = Some(0); match x { None => (), @@ -2058,6 +2038,69 @@ fn get_owned_iterator() -> IntoIter { ``` "##, +E0524: r##" +A variable which requires unique access is being used in more than one closure +at the same time. + +Erroneous code example: + +```compile_fail,E0524 +fn set(x: &mut isize) { + *x += 4; +} + +fn dragoooon(x: &mut isize) { + let mut c1 = || set(x); + let mut c2 = || set(x); // error! + + c2(); + c1(); +} +``` + +To solve this issue, multiple solutions are available. First, is it required +for this variable to be used in more than one closure at a time? If it is the +case, use reference counted types such as `Rc` (or `Arc` if it runs +concurrently): + +``` +use std::rc::Rc; +use std::cell::RefCell; + +fn set(x: &mut isize) { + *x += 4; +} + +fn dragoooon(x: &mut isize) { + let x = Rc::new(RefCell::new(x)); + let y = Rc::clone(&x); + let mut c1 = || { let mut x2 = x.borrow_mut(); set(&mut x2); }; + let mut c2 = || { let mut x2 = y.borrow_mut(); set(&mut x2); }; // ok! + + c2(); + c1(); +} +``` + +If not, just run closures one at a time: + +``` +fn set(x: &mut isize) { + *x += 4; +} + +fn dragoooon(x: &mut isize) { + { // This block isn't necessary since non-lexical lifetimes, it's just to + // make it more clear. + let mut c1 = || set(&mut *x); + c1(); + } // `c1` has been dropped here so we're free to use `x` again! + let mut c2 = || set(&mut *x); + c2(); +} +``` +"##, + E0595: r##" #### Note: this error code is no longer emitted by the compiler. @@ -2448,16 +2491,15 @@ information. There are some known bugs that trigger this message. "##, -} -register_diagnostics! { +; + +// E0008, // cannot bind by-move into a pattern guard // E0298, // cannot compare constants // E0299, // mismatched types between arms // E0471, // constant evaluation error (in pattern) // E0385, // {} in an aliasable location - E0493, // destructors cannot be evaluated at compile-time E0521, // borrowed data escapes outside of closure - E0524, // two closures require unique access to `..` at the same time E0526, // shuffle indices are not constant E0594, // cannot assign to {} // E0598, // lifetime of {} is too short to guarantee its contents can be... diff --git a/src/librustc_mir/hair/constant.rs b/src/librustc_mir/hair/constant.rs index bc01e3ee95b97..956716f8ceaf7 100644 --- a/src/librustc_mir/hair/constant.rs +++ b/src/librustc_mir/hair/constant.rs @@ -49,7 +49,7 @@ crate fn lit_to_const<'tcx>( parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)? } LitKind::FloatUnsuffixed(n) => { - let fty = match ty.sty { + let fty = match ty.kind { ty::Float(fty) => fty, _ => bug!() }; diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index 9a73842d2f02a..e9777dab26e2a 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -5,7 +5,7 @@ use rustc::middle::region; use rustc::hir; use rustc::ty; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; impl<'tcx> Mirror<'tcx> for &'tcx hir::Block { type Output = Block<'tcx>; @@ -49,7 +49,7 @@ fn mirror_stmts<'a, 'tcx>( for (index, stmt) in stmts.iter().enumerate() { let hir_id = stmt.hir_id; let opt_dxn_ext = cx.region_scope_tree.opt_destruction_scope(hir_id.local_id); - match stmt.node { + match stmt.kind { hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => { result.push(StmtRef::Mirror(Box::new(Stmt { @@ -78,12 +78,12 @@ fn mirror_stmts<'a, 'tcx>( if let Some(ty) = &local.ty { if let Some(&user_ty) = cx.tables.user_provided_types().get(ty.hir_id) { debug!("mirror_stmts: user_ty={:?}", user_ty); - pattern = Pattern { + pattern = Pat { ty: pattern.ty, span: pattern.span, - kind: Box::new(PatternKind::AscribeUserType { + kind: Box::new(PatKind::AscribeUserType { ascription: hair::pattern::Ascription { - user_ty: PatternTypeProjection::from_user_type(user_ty), + user_ty: PatTyProj::from_user_type(user_ty), user_ty_span: ty.span, variance: ty::Variance::Covariant, }, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 1c6a743155ee4..e6f7a042f1c2b 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -3,7 +3,7 @@ use crate::hair::cx::Cx; use crate::hair::cx::block; use crate::hair::cx::to_ref::ToRef; use crate::hair::util::UserAnnotatedTyHelpers; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use rustc::hir::def::{CtorOf, Res, DefKind, CtorKind}; use rustc::mir::interpret::{GlobalId, ErrorHandled, ConstValue}; use rustc::ty::{self, AdtKind, Ty}; @@ -204,7 +204,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( let expr_ty = cx.tables().expr_ty(expr); let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); - let kind = match expr.node { + let kind = match expr.kind { // Here comes the interesting stuff: hir::ExprKind::MethodCall(_, method_span, ref args) => { // Rewrite a.b(c) into UFCS form like Trait::b(a, c) @@ -247,7 +247,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( } } else { let adt_data = if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = - fun.node + fun.kind { // Tuple-like ADTs are represented as ExprKind::Call. We convert them here. expr_ty.ty_adt_def().and_then(|adt_def| { @@ -427,7 +427,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( if cx.tables().is_method_call(expr) { overloaded_operator(cx, expr, vec![arg.to_ref()]) } else { - if let hir::ExprKind::Lit(ref lit) = arg.node { + if let hir::ExprKind::Lit(ref lit) = arg.kind { ExprKind::Literal { literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true), user_ty: None, @@ -442,7 +442,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( } hir::ExprKind::Struct(ref qpath, ref fields, ref base) => { - match expr_ty.sty { + match expr_ty.kind { ty::Adt(adt, substs) => { match adt.adt_kind() { AdtKind::Struct | AdtKind::Union => { @@ -505,8 +505,9 @@ fn make_mirror_unadjusted<'a, 'tcx>( hir::ExprKind::Closure(..) => { let closure_ty = cx.tables().expr_ty(expr); - let (def_id, substs, movability) = match closure_ty.sty { - ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs), None), + let (def_id, substs, movability) = match closure_ty.kind { + ty::Closure(def_id, substs) => (def_id, + UpvarSubsts::Closure(substs), None), ty::Generator(def_id, substs, movability) => { (def_id, UpvarSubsts::Generator(substs), Some(movability)) } @@ -543,9 +544,9 @@ fn make_mirror_unadjusted<'a, 'tcx>( // Now comes the rote stuff: hir::ExprKind::Repeat(ref v, ref count) => { let def_id = cx.tcx.hir().local_def_id(count.hir_id); - let substs = InternalSubsts::identity_for_item(cx.tcx.global_tcx(), def_id); + let substs = InternalSubsts::identity_for_item(cx.tcx, def_id); let instance = ty::Instance::resolve( - cx.tcx.global_tcx(), + cx.tcx, cx.param_env, def_id, substs, @@ -639,7 +640,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( // } // The correct solution would be to add symbolic computations to miri, // so we wouldn't have to compute and store the actual value - let var = if let hir::ExprKind::Path(ref qpath) = source.node { + let var = if let hir::ExprKind::Path(ref qpath) = source.kind { let res = cx.tables().qpath_res(qpath, source.hir_id); cx .tables() @@ -860,9 +861,9 @@ impl ToBorrowKind for hir::Mutability { } } -fn convert_arm<'a, 'tcx>(cx: &mut Cx<'a, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> { +fn convert_arm<'tcx>(cx: &mut Cx<'_, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> { Arm { - patterns: arm.pats.iter().map(|p| cx.pattern_from_hir(p)).collect(), + pattern: cx.pattern_from_hir(&arm.pat), guard: match arm.guard { Some(hir::Guard::If(ref e)) => Some(Guard::If(e.to_ref())), _ => None, @@ -927,7 +928,7 @@ fn convert_path_expr<'a, 'tcx>( ExprKind::Literal { literal: cx.tcx.mk_const(ty::Const { val: ConstValue::Unevaluated(def_id, substs), - ty: cx.tcx.type_of(def_id), + ty: cx.tables().node_type(expr.hir_id), }), user_ty, } @@ -938,7 +939,7 @@ fn convert_path_expr<'a, 'tcx>( let user_provided_type = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty); debug!("convert_path_expr: user_provided_type={:?}", user_provided_type); let ty = cx.tables().node_type(expr.hir_id); - match ty.sty { + match ty.kind { // A unit struct/variant which is used as a value. // We return a completely different ExprKind here to account for this special case. ty::Adt(adt_def, substs) => { @@ -1001,7 +1002,7 @@ fn convert_var( }); let region = cx.tcx.mk_region(region); - let self_expr = if let ty::Closure(_, closure_substs) = closure_ty.sty { + let self_expr = if let ty::Closure(_, closure_substs) = closure_ty.kind { match cx.infcx.closure_kind(closure_def_id, closure_substs).unwrap() { ty::ClosureKind::Fn => { let ref_closure_ty = cx.tcx.mk_ref(region, @@ -1011,7 +1012,7 @@ fn convert_var( }); Expr { ty: closure_ty, - temp_lifetime: temp_lifetime, + temp_lifetime, span: expr.span, kind: ExprKind::Deref { arg: Expr { @@ -1147,7 +1148,7 @@ fn overloaded_place<'a, 'tcx>( // Reconstruct the output assuming it's a reference with the // same region and mutability as the receiver. This holds for // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. - let (region, mutbl) = match recv_ty.sty { + let (region, mutbl) = match recv_ty.kind { ty::Ref(region, _, mutbl) => (region, mutbl), _ => span_bug!(expr.span, "overloaded_place: receiver is not a reference"), }; diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 3d9349df5bedb..e120b496d3d09 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -5,14 +5,14 @@ use crate::hair::*; use crate::hair::util::UserAnnotatedTyHelpers; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use rustc::hir::def_id::DefId; use rustc::hir::Node; use rustc::middle::region; use rustc::infer::InferCtxt; use rustc::ty::subst::Subst; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::subst::{Kind, InternalSubsts}; +use rustc::ty::subst::{GenericArg, InternalSubsts}; use rustc::ty::layout::VariantIdx; use syntax::ast; use syntax::attr; @@ -83,7 +83,7 @@ impl<'a, 'tcx> Cx<'a, 'tcx> { infcx, root_lint_level: src_id, param_env: tcx.param_env(src_def_id), - identity_substs: InternalSubsts::identity_for_item(tcx.global_tcx(), src_def_id), + identity_substs: InternalSubsts::identity_for_item(tcx, src_def_id), region_scope_tree: tcx.region_scope_tree(src_def_id), tables, constness, @@ -153,30 +153,26 @@ impl<'a, 'tcx> Cx<'a, 'tcx> { } } - pub fn pattern_from_hir(&mut self, p: &hir::Pat) -> Pattern<'tcx> { - let tcx = self.tcx.global_tcx(); - let p = match tcx.hir().get(p.hir_id) { + pub fn pattern_from_hir(&mut self, p: &hir::Pat) -> Pat<'tcx> { + let p = match self.tcx.hir().get(p.hir_id) { Node::Pat(p) | Node::Binding(p) => p, node => bug!("pattern became {:?}", node) }; - Pattern::from_hir(tcx, - self.param_env.and(self.identity_substs), - self.tables(), - p) + Pat::from_hir(self.tcx, self.param_env.and(self.identity_substs), self.tables(), p) } pub fn trait_method(&mut self, trait_def_id: DefId, method_name: Symbol, self_ty: Ty<'tcx>, - params: &[Kind<'tcx>]) - -> (Ty<'tcx>, &'tcx ty::Const<'tcx>) { + params: &[GenericArg<'tcx>]) + -> &'tcx ty::Const<'tcx> { let substs = self.tcx.mk_substs_trait(self_ty, params); for item in self.tcx.associated_items(trait_def_id) { if item.kind == ty::AssocKind::Method && item.ident.name == method_name { let method_ty = self.tcx.type_of(item.def_id); let method_ty = method_ty.subst(self.tcx, substs); - return (method_ty, ty::Const::zero_sized(self.tcx, method_ty)); + return ty::Const::zero_sized(self.tcx, method_ty); } } @@ -190,7 +186,7 @@ impl<'a, 'tcx> Cx<'a, 'tcx> { } pub fn needs_drop(&mut self, ty: Ty<'tcx>) -> bool { - ty.needs_drop(self.tcx.global_tcx(), self.param_env) + ty.needs_drop(self.tcx, self.param_env) } pub fn tcx(&self) -> TyCtxt<'tcx> { diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 0638cb462f73b..a76377d24bdf9 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -20,8 +20,8 @@ pub mod cx; mod constant; pub mod pattern; -pub use self::pattern::{BindingMode, Pattern, PatternKind, PatternRange, FieldPattern}; -pub(crate) use self::pattern::PatternTypeProjection; +pub use self::pattern::{BindingMode, Pat, PatKind, PatRange, FieldPat}; +pub(crate) use self::pattern::PatTyProj; mod util; @@ -83,7 +83,7 @@ pub enum StmtKind<'tcx> { /// `let = ...` /// /// if a type is included, it is added as an ascription pattern - pattern: Pattern<'tcx>, + pattern: Pat<'tcx>, /// let pat: ty = ... initializer: Option>, @@ -293,7 +293,7 @@ pub struct FruInfo<'tcx> { #[derive(Clone, Debug)] pub struct Arm<'tcx> { - pub patterns: Vec>, + pub pattern: Pat<'tcx>, pub guard: Option>, pub body: ExprRef<'tcx>, pub lint_level: LintLevel, @@ -301,6 +301,17 @@ pub struct Arm<'tcx> { pub span: Span, } +impl Arm<'tcx> { + // HACK(or_patterns; Centril | dlrobertson): Remove this and + // correctly handle each case in which this method is used. + pub fn top_pats_hack(&self) -> &[Pat<'tcx>] { + match &*self.pattern.kind { + PatKind::Or { pats } => pats, + _ => std::slice::from_ref(&self.pattern), + } + } +} + #[derive(Clone, Debug)] pub enum Guard<'tcx> { If(ExprRef<'tcx>), diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 8a3d904e77579..3ea5805287724 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -161,9 +161,9 @@ use self::Usefulness::*; use self::WitnessPreference::*; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; -use super::{FieldPattern, Pattern, PatternKind, PatternRange}; +use super::{FieldPat, Pat, PatKind, PatRange}; use super::{PatternFoldable, PatternFolder, compare_const_vals}; use rustc::hir::def_id::DefId; @@ -188,9 +188,7 @@ use std::ops::RangeInclusive; use std::u128; use std::convert::TryInto; -pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>) - -> &'a Pattern<'tcx> -{ +pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> &'a Pat<'tcx> { cx.pattern_arena.alloc(LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat)) } @@ -213,7 +211,7 @@ impl LiteralExpander<'tcx> { crty: Ty<'tcx>, ) -> ConstValue<'tcx> { debug!("fold_const_value_deref {:?} {:?} {:?}", val, rty, crty); - match (val, &crty.sty, &rty.sty) { + match (val, &crty.kind, &rty.kind) { // the easy case, deref a reference (ConstValue::Scalar(Scalar::Ptr(p)), x, y) if x == y => { let alloc = self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id); @@ -243,24 +241,24 @@ impl LiteralExpander<'tcx> { } impl PatternFolder<'tcx> for LiteralExpander<'tcx> { - fn fold_pattern(&mut self, pat: &Pattern<'tcx>) -> Pattern<'tcx> { - debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.sty, pat.kind); - match (&pat.ty.sty, &*pat.kind) { + fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> { + debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind, pat.kind); + match (&pat.ty.kind, &*pat.kind) { ( &ty::Ref(_, rty, _), - &PatternKind::Constant { value: Const { + &PatKind::Constant { value: Const { val, - ty: ty::TyS { sty: ty::Ref(_, crty, _), .. }, + ty: ty::TyS { kind: ty::Ref(_, crty, _), .. }, } }, ) => { - Pattern { + Pat { ty: pat.ty, span: pat.span, - kind: box PatternKind::Deref { - subpattern: Pattern { + kind: box PatKind::Deref { + subpattern: Pat { ty: rty, span: pat.span, - kind: box PatternKind::Constant { value: self.tcx.mk_const(Const { + kind: box PatKind::Constant { value: self.tcx.mk_const(Const { val: self.fold_const_value_deref(*val, rty, crty), ty: rty, }) }, @@ -268,7 +266,7 @@ impl PatternFolder<'tcx> for LiteralExpander<'tcx> { } } } - (_, &PatternKind::Binding { subpattern: Some(ref s), .. }) => { + (_, &PatKind::Binding { subpattern: Some(ref s), .. }) => { s.fold_with(self) } _ => pat.super_fold_with(self) @@ -276,10 +274,10 @@ impl PatternFolder<'tcx> for LiteralExpander<'tcx> { } } -impl<'tcx> Pattern<'tcx> { +impl<'tcx> Pat<'tcx> { fn is_wildcard(&self) -> bool { match *self.kind { - PatternKind::Binding { subpattern: None, .. } | PatternKind::Wild => + PatKind::Binding { subpattern: None, .. } | PatKind::Wild => true, _ => false } @@ -288,14 +286,14 @@ impl<'tcx> Pattern<'tcx> { /// A 2D matrix. Nx1 matrices are very common, which is why `SmallVec[_; 2]` /// works well for each row. -pub struct Matrix<'p, 'tcx>(Vec; 2]>>); +pub struct Matrix<'p, 'tcx>(Vec; 2]>>); impl<'p, 'tcx> Matrix<'p, 'tcx> { pub fn empty() -> Self { Matrix(vec![]) } - pub fn push(&mut self, row: SmallVec<[&'p Pattern<'tcx>; 2]>) { + pub fn push(&mut self, row: SmallVec<[&'p Pat<'tcx>; 2]>) { self.0.push(row) } } @@ -344,9 +342,9 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { } } -impl<'p, 'tcx> FromIterator; 2]>> for Matrix<'p, 'tcx> { +impl<'p, 'tcx> FromIterator; 2]>> for Matrix<'p, 'tcx> { fn from_iter(iter: T) -> Self - where T: IntoIterator; 2]>> + where T: IntoIterator; 2]>> { Matrix(iter.into_iter().collect()) } @@ -362,8 +360,8 @@ pub struct MatchCheckCtxt<'a, 'tcx> { /// statement. pub module: DefId, param_env: ty::ParamEnv<'tcx>, - pub pattern_arena: &'a TypedArena>, - pub byte_array_map: FxHashMap<*const Pattern<'tcx>, Vec<&'a Pattern<'tcx>>>, + pub pattern_arena: &'a TypedArena>, + pub byte_array_map: FxHashMap<*const Pat<'tcx>, Vec<&'a Pat<'tcx>>>, } impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { @@ -395,9 +393,9 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } } - fn is_non_exhaustive_variant<'p>(&self, pattern: &'p Pattern<'tcx>) -> bool { + fn is_non_exhaustive_variant<'p>(&self, pattern: &'p Pat<'tcx>) -> bool { match *pattern.kind { - PatternKind::Variant { adt_def, variant_index, .. } => { + PatKind::Variant { adt_def, variant_index, .. } => { let ref variant = adt_def.variants[variant_index]; variant.is_field_list_non_exhaustive() } @@ -406,14 +404,14 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { - match ty.sty { + match ty.kind { ty::Adt(adt_def, ..) => adt_def.is_variant_list_non_exhaustive(), _ => false, } } fn is_local(&self, ty: Ty<'tcx>) -> bool { - match ty.sty { + match ty.kind { ty::Adt(adt_def, ..) => adt_def.did.is_local(), _ => false, } @@ -436,6 +434,13 @@ enum Constructor<'tcx> { } impl<'tcx> Constructor<'tcx> { + fn is_slice(&self) -> bool { + match self { + Slice { .. } => true, + _ => false, + } + } + fn variant_index_for_adt<'a>( &self, cx: &MatchCheckCtxt<'a, 'tcx>, @@ -476,7 +481,7 @@ pub enum WitnessPreference { } #[derive(Copy, Clone, Debug)] -struct PatternContext<'tcx> { +struct PatCtxt<'tcx> { ty: Ty<'tcx>, max_slice_length: u64, } @@ -514,12 +519,12 @@ struct PatternContext<'tcx> { /// /// The final `Pair(Some(_), true)` is then the resulting witness. #[derive(Clone, Debug)] -pub struct Witness<'tcx>(Vec>); +pub struct Witness<'tcx>(Vec>); impl<'tcx> Witness<'tcx> { - pub fn single_pattern(&self) -> &Pattern<'tcx> { + pub fn single_pattern(self) -> Pat<'tcx> { assert_eq!(self.0.len(), 1); - &self.0[0] + self.0.into_iter().next().unwrap() } fn push_wild_constructor<'a>( @@ -531,10 +536,10 @@ impl<'tcx> Witness<'tcx> { { let sub_pattern_tys = constructor_sub_pattern_tys(cx, ctor, ty); self.0.extend(sub_pattern_tys.into_iter().map(|ty| { - Pattern { + Pat { ty, span: DUMMY_SP, - kind: box PatternKind::Wild, + kind: box PatKind::Wild, } })); self.apply_constructor(cx, ctor, ty) @@ -565,38 +570,38 @@ impl<'tcx> Witness<'tcx> { let len = self.0.len() as u64; let mut pats = self.0.drain((len - arity) as usize..).rev(); - match ty.sty { + match ty.kind { ty::Adt(..) | ty::Tuple(..) => { let pats = pats.enumerate().map(|(i, p)| { - FieldPattern { + FieldPat { field: Field::new(i), pattern: p } }).collect(); - if let ty::Adt(adt, substs) = ty.sty { + if let ty::Adt(adt, substs) = ty.kind { if adt.is_enum() { - PatternKind::Variant { + PatKind::Variant { adt_def: adt, substs, variant_index: ctor.variant_index_for_adt(cx, adt), subpatterns: pats } } else { - PatternKind::Leaf { subpatterns: pats } + PatKind::Leaf { subpatterns: pats } } } else { - PatternKind::Leaf { subpatterns: pats } + PatKind::Leaf { subpatterns: pats } } } ty::Ref(..) => { - PatternKind::Deref { subpattern: pats.nth(0).unwrap() } + PatKind::Deref { subpattern: pats.nth(0).unwrap() } } ty::Slice(_) | ty::Array(..) => { - PatternKind::Slice { + PatKind::Slice { prefix: pats.collect(), slice: None, suffix: vec![] @@ -605,20 +610,19 @@ impl<'tcx> Witness<'tcx> { _ => { match *ctor { - ConstantValue(value) => PatternKind::Constant { value }, - ConstantRange(lo, hi, ty, end) => PatternKind::Range(PatternRange { + ConstantValue(value) => PatKind::Constant { value }, + ConstantRange(lo, hi, ty, end) => PatKind::Range(PatRange { lo: ty::Const::from_bits(cx.tcx, lo, ty::ParamEnv::empty().and(ty)), hi: ty::Const::from_bits(cx.tcx, hi, ty::ParamEnv::empty().and(ty)), - ty, end, }), - _ => PatternKind::Wild, + _ => PatKind::Wild, } } } }; - self.0.push(Pattern { + self.0.push(Pat { ty, span: DUMMY_SP, kind: Box::new(pat), @@ -637,10 +641,10 @@ impl<'tcx> Witness<'tcx> { /// `Option`, we do not include `Some(_)` in the returned list of constructors. fn all_constructors<'a, 'tcx>( cx: &mut MatchCheckCtxt<'a, 'tcx>, - pcx: PatternContext<'tcx>, + pcx: PatCtxt<'tcx>, ) -> Vec> { debug!("all_constructors({:?})", pcx.ty); - let ctors = match pcx.ty.sty { + let ctors = match pcx.ty.kind { ty::Bool => { [true, false].iter().map(|&b| { ConstantValue(ty::Const::from_bool(cx.tcx, b)) @@ -711,7 +715,7 @@ fn all_constructors<'a, 'tcx>( fn max_slice_length<'p, 'a, 'tcx, I>(cx: &mut MatchCheckCtxt<'a, 'tcx>, patterns: I) -> u64 where - I: Iterator>, + I: Iterator>, 'tcx: 'p, { // The exhaustiveness-checking paper does not include any details on @@ -784,9 +788,9 @@ where for row in patterns { match *row.kind { - PatternKind::Constant { value } => { + PatKind::Constant { value } => { // extract the length of an array/slice from a constant - match (value.val, &value.ty.sty) { + match (value.val, &value.ty.kind) { (_, ty::Array(_, n)) => max_fixed_len = cmp::max( max_fixed_len, n.eval_usize(cx.tcx, cx.param_env), @@ -798,11 +802,11 @@ where _ => {}, } } - PatternKind::Slice { ref prefix, slice: None, ref suffix } => { + PatKind::Slice { ref prefix, slice: None, ref suffix } => { let fixed_len = prefix.len() as u64 + suffix.len() as u64; max_fixed_len = cmp::max(max_fixed_len, fixed_len); } - PatternKind::Slice { ref prefix, slice: Some(_), ref suffix } => { + PatKind::Slice { ref prefix, slice: Some(_), ref suffix } => { max_prefix_len = cmp::max(max_prefix_len, prefix.len() as u64); max_suffix_len = cmp::max(max_suffix_len, suffix.len() as u64); } @@ -830,6 +834,80 @@ struct IntRange<'tcx> { } impl<'tcx> IntRange<'tcx> { + #[inline] + fn is_integral(ty: Ty<'_>) -> bool { + match ty.kind { + ty::Char | ty::Int(_) | ty::Uint(_) => true, + _ => false, + } + } + + #[inline] + fn integral_size_and_signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'_>) -> Option<(Size, u128)> { + match ty.kind { + ty::Char => Some((Size::from_bytes(4), 0)), + ty::Int(ity) => { + let size = Integer::from_attr(&tcx, SignedInt(ity)).size(); + Some((size, 1u128 << (size.bits() as u128 - 1))) + } + ty::Uint(uty) => Some((Integer::from_attr(&tcx, UnsignedInt(uty)).size(), 0)), + _ => None, + } + } + + #[inline] + fn from_const( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: &Const<'tcx>, + ) -> Option> { + if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) { + let ty = value.ty; + let val = if let ConstValue::Scalar(Scalar::Raw { data, size }) = value.val { + // For this specific pattern we can skip a lot of effort and go + // straight to the result, after doing a bit of checking. (We + // could remove this branch and just use the next branch, which + // is more general but much slower.) + Scalar::<()>::check_raw(data, size, target_size); + data + } else if let Some(val) = value.try_eval_bits(tcx, param_env, ty) { + // This is a more general form of the previous branch. + val + } else { + return None + }; + let val = val ^ bias; + Some(IntRange { range: val..=val, ty }) + } else { + None + } + } + + #[inline] + fn from_range( + tcx: TyCtxt<'tcx>, + lo: u128, + hi: u128, + ty: Ty<'tcx>, + end: &RangeEnd, + ) -> Option> { + if Self::is_integral(ty) { + // Perform a shift if the underlying types are signed, + // which makes the interval arithmetic simpler. + let bias = IntRange::signed_bias(tcx, ty); + let (lo, hi) = (lo ^ bias, hi ^ bias); + // Make sure the interval is well-formed. + if lo > hi || lo == hi && *end == RangeEnd::Excluded { + None + } else { + let offset = (*end == RangeEnd::Excluded) as u128; + Some(IntRange { range: lo..=(hi - offset), ty }) + } + } else { + None + } + } + fn from_ctor( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -837,37 +915,9 @@ impl<'tcx> IntRange<'tcx> { ) -> Option> { // Floating-point ranges are permitted and we don't want // to consider them when constructing integer ranges. - fn is_integral(ty: Ty<'_>) -> bool { - match ty.sty { - ty::Char | ty::Int(_) | ty::Uint(_) => true, - _ => false, - } - } - match ctor { - ConstantRange(lo, hi, ty, end) if is_integral(ty) => { - // Perform a shift if the underlying types are signed, - // which makes the interval arithmetic simpler. - let bias = IntRange::signed_bias(tcx, ty); - let (lo, hi) = (lo ^ bias, hi ^ bias); - // Make sure the interval is well-formed. - if lo > hi || lo == hi && *end == RangeEnd::Excluded { - None - } else { - let offset = (*end == RangeEnd::Excluded) as u128; - Some(IntRange { range: lo..=(hi - offset), ty }) - } - } - ConstantValue(val) if is_integral(val.ty) => { - let ty = val.ty; - if let Some(val) = val.try_eval_bits(tcx, param_env, ty) { - let bias = IntRange::signed_bias(tcx, ty); - let val = val ^ bias; - Some(IntRange { range: val..=val, ty }) - } else { - None - } - } + ConstantRange(lo, hi, ty, end) => Self::from_range(tcx, *lo, *hi, ty, end), + ConstantValue(val) => Self::from_const(tcx, param_env, val), _ => None, } } @@ -875,29 +925,33 @@ impl<'tcx> IntRange<'tcx> { fn from_pat( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - mut pat: &Pattern<'tcx>, + mut pat: &Pat<'tcx>, ) -> Option> { - let range = loop { + loop { match pat.kind { - box PatternKind::Constant { value } => break ConstantValue(value), - box PatternKind::Range(PatternRange { lo, hi, ty, end }) => break ConstantRange( - lo.eval_bits(tcx, param_env, ty), - hi.eval_bits(tcx, param_env, ty), - ty, - end, - ), - box PatternKind::AscribeUserType { ref subpattern, .. } => { + box PatKind::Constant { value } => { + return Self::from_const(tcx, param_env, value); + } + box PatKind::Range(PatRange { lo, hi, end }) => { + return Self::from_range( + tcx, + lo.eval_bits(tcx, param_env, lo.ty), + hi.eval_bits(tcx, param_env, hi.ty), + &lo.ty, + &end, + ); + } + box PatKind::AscribeUserType { ref subpattern, .. } => { pat = subpattern; }, _ => return None, } - }; - Self::from_ctor(tcx, param_env, &range) + } } // The return value of `signed_bias` should be XORed with an endpoint to encode/decode it. fn signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> u128 { - match ty.sty { + match ty.kind { ty::Int(ity) => { let bits = Integer::from_attr(&tcx, SignedInt(ity)).size().bits() as u128; 1u128 << (bits - 1) @@ -1059,7 +1113,7 @@ fn compute_missing_ctors<'tcx>( /// inputs that will match `v` but not any of the sets in `m`. /// /// All the patterns at each column of the `matrix ++ v` matrix must -/// have the same type, except that wildcard (PatternKind::Wild) patterns +/// have the same type, except that wildcard (PatKind::Wild) patterns /// with type `TyErr` are also allowed, even if the "type of the column" /// is not `TyErr`. That is used to represent private fields, as using their /// real type would assert that they are inhabited. @@ -1071,7 +1125,7 @@ fn compute_missing_ctors<'tcx>( pub fn is_useful<'p, 'a, 'tcx>( cx: &mut MatchCheckCtxt<'a, 'tcx>, matrix: &Matrix<'p, 'tcx>, - v: &[&Pattern<'tcx>], + v: &[&Pat<'tcx>], witness: WitnessPreference, ) -> Usefulness<'tcx> { let &Matrix(ref rows) = matrix; @@ -1095,7 +1149,7 @@ pub fn is_useful<'p, 'a, 'tcx>( assert!(rows.iter().all(|r| r.len() == v.len())); - let pcx = PatternContext { + let pcx = PatCtxt { // TyErr is used to represent the type of wildcard patterns matching // against inaccessible (private) fields of structs, so that we won't // be able to observe whether the types of the struct's fields are @@ -1248,10 +1302,10 @@ pub fn is_useful<'p, 'a, 'tcx>( // All constructors are unused. Add wild patterns // rather than each individual constructor. pats.into_iter().map(|mut witness| { - witness.0.push(Pattern { + witness.0.push(Pat { ty: pcx.ty, span: DUMMY_SP, - kind: box PatternKind::Wild, + kind: box PatKind::Wild, }); witness }).collect() @@ -1286,7 +1340,7 @@ pub fn is_useful<'p, 'a, 'tcx>( fn is_useful_specialized<'p, 'a, 'tcx>( cx: &mut MatchCheckCtxt<'a, 'tcx>, &Matrix(ref m): &Matrix<'p, 'tcx>, - v: &[&Pattern<'tcx>], + v: &[&Pat<'tcx>], ctor: Constructor<'tcx>, lty: Ty<'tcx>, witness: WitnessPreference, @@ -1294,16 +1348,18 @@ fn is_useful_specialized<'p, 'a, 'tcx>( debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty); let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty); let wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| { - Pattern { + Pat { ty, span: DUMMY_SP, - kind: box PatternKind::Wild, + kind: box PatKind::Wild, } }).collect(); let wild_patterns: Vec<_> = wild_patterns_owned.iter().collect(); - let matrix = Matrix(m.iter().flat_map(|r| { - specialize(cx, &r, &ctor, &wild_patterns) - }).collect()); + let matrix = Matrix( + m.iter() + .filter_map(|r| specialize(cx, &r, &ctor, &wild_patterns)) + .collect() + ); match specialize(cx, v, &ctor, &wild_patterns) { Some(v) => match is_useful(cx, &matrix, &v, witness) { UsefulWithWitness(witnesses) => UsefulWithWitness( @@ -1326,33 +1382,33 @@ fn is_useful_specialized<'p, 'a, 'tcx>( /// /// Returns `None` in case of a catch-all, which can't be specialized. fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>, - pat: &Pattern<'tcx>, - pcx: PatternContext<'tcx>) + pat: &Pat<'tcx>, + pcx: PatCtxt<'tcx>) -> Option>> { match *pat.kind { - PatternKind::AscribeUserType { ref subpattern, .. } => + PatKind::AscribeUserType { ref subpattern, .. } => pat_constructors(cx, subpattern, pcx), - PatternKind::Binding { .. } | PatternKind::Wild => None, - PatternKind::Leaf { .. } | PatternKind::Deref { .. } => Some(vec![Single]), - PatternKind::Variant { adt_def, variant_index, .. } => { + PatKind::Binding { .. } | PatKind::Wild => None, + PatKind::Leaf { .. } | PatKind::Deref { .. } => Some(vec![Single]), + PatKind::Variant { adt_def, variant_index, .. } => { Some(vec![Variant(adt_def.variants[variant_index].def_id)]) } - PatternKind::Constant { value } => Some(vec![ConstantValue(value)]), - PatternKind::Range(PatternRange { lo, hi, ty, end }) => + PatKind::Constant { value } => Some(vec![ConstantValue(value)]), + PatKind::Range(PatRange { lo, hi, end }) => Some(vec![ConstantRange( - lo.eval_bits(cx.tcx, cx.param_env, ty), - hi.eval_bits(cx.tcx, cx.param_env, ty), - ty, + lo.eval_bits(cx.tcx, cx.param_env, lo.ty), + hi.eval_bits(cx.tcx, cx.param_env, hi.ty), + lo.ty, end, )]), - PatternKind::Array { .. } => match pcx.ty.sty { + PatKind::Array { .. } => match pcx.ty.kind { ty::Array(_, length) => Some(vec![ Slice(length.eval_usize(cx.tcx, cx.param_env)) ]), _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty) }, - PatternKind::Slice { ref prefix, ref slice, ref suffix } => { + PatKind::Slice { ref prefix, ref slice, ref suffix } => { let pat_len = prefix.len() as u64 + suffix.len() as u64; if slice.is_some() { Some((pat_len..pcx.max_slice_length+1).map(Slice).collect()) @@ -1360,6 +1416,9 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>, Some(vec![Slice(pat_len)]) } } + PatKind::Or { .. } => { + bug!("support for or-patterns has not been fully implemented yet."); + } } } @@ -1370,7 +1429,7 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>, /// A struct pattern's arity is the number of fields it contains, etc. fn constructor_arity(cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor<'tcx>, ty: Ty<'tcx>) -> u64 { debug!("constructor_arity({:#?}, {:?})", ctor, ty); - match ty.sty { + match ty.kind { ty::Tuple(ref fs) => fs.len() as u64, ty::Slice(..) | ty::Array(..) => match *ctor { Slice(length) => length, @@ -1395,7 +1454,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx>( ty: Ty<'tcx>, ) -> Vec> { debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty); - match ty.sty { + match ty.kind { ty::Tuple(ref fs) => fs.into_iter().map(|t| t.expect_ty()).collect(), ty::Slice(ty) | ty::Array(ty, _) => match *ctor { Slice(length) => (0..length).map(|_| ty).collect(), @@ -1413,7 +1472,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx>( || field.vis.is_accessible_from(cx.module, cx.tcx); if is_visible { let ty = field.ty(cx.tcx, substs); - match ty.sty { + match ty.kind { // If the field type returned is an array of an unknown // size return an TyErr. ty::Array(_, len) @@ -1444,12 +1503,12 @@ fn slice_pat_covered_by_const<'tcx>( tcx: TyCtxt<'tcx>, _span: Span, const_val: &'tcx ty::Const<'tcx>, - prefix: &[Pattern<'tcx>], - slice: &Option>, - suffix: &[Pattern<'tcx>], + prefix: &[Pat<'tcx>], + slice: &Option>, + suffix: &[Pat<'tcx>], param_env: ty::ParamEnv<'tcx>, ) -> Result { - let data: &[u8] = match (const_val.val, &const_val.ty.sty) { + let data: &[u8] = match (const_val.val, &const_val.ty.kind) { (ConstValue::ByRef { offset, alloc, .. }, ty::Array(t, n)) => { assert_eq!(*t, tcx.types.u8); let n = n.eval_usize(tcx, param_env); @@ -1479,7 +1538,7 @@ fn slice_pat_covered_by_const<'tcx>( data[data.len()-suffix.len()..].iter().zip(suffix)) { match pat.kind { - box PatternKind::Constant { value } => { + box PatKind::Constant { value } => { let b = value.eval_bits(tcx, param_env, pat.ty); assert_eq!(b as u8 as u128, b); if b as u8 != *ch { @@ -1501,7 +1560,7 @@ fn should_treat_range_exhaustively(tcx: TyCtxt<'tcx>, ctor: &Constructor<'tcx>) ConstantRange(_, _, ty, _) => ty, _ => return false, }; - if let ty::Char | ty::Int(_) | ty::Uint(_) = ty.sty { + if let ty::Char | ty::Int(_) | ty::Uint(_) = ty.kind { !ty.is_ptr_sized_integral() || tcx.features().precise_pointer_size_matching } else { false @@ -1618,45 +1677,15 @@ fn split_grouped_constructors<'p, 'tcx>( split_ctors } -/// Checks whether there exists any shared value in either `ctor` or `pat` by intersecting them. -fn constructor_intersects_pattern<'p, 'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ctor: &Constructor<'tcx>, - pat: &'p Pattern<'tcx>, -) -> Option; 2]>> { - if should_treat_range_exhaustively(tcx, ctor) { - match (IntRange::from_ctor(tcx, param_env, ctor), IntRange::from_pat(tcx, param_env, pat)) { - (Some(ctor), Some(pat)) => { - ctor.intersection(&pat).map(|_| { - let (pat_lo, pat_hi) = pat.range.into_inner(); - let (ctor_lo, ctor_hi) = ctor.range.into_inner(); - assert!(pat_lo <= ctor_lo && ctor_hi <= pat_hi); - smallvec![] - }) - } - _ => None, - } - } else { - // Fallback for non-ranges and ranges that involve floating-point numbers, which are not - // conveniently handled by `IntRange`. For these cases, the constructor may not be a range - // so intersection actually devolves into being covered by the pattern. - match constructor_covered_by_range(tcx, param_env, ctor, pat) { - Ok(true) => Some(smallvec![]), - Ok(false) | Err(ErrorReported) => None, - } - } -} - fn constructor_covered_by_range<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ctor: &Constructor<'tcx>, - pat: &Pattern<'tcx>, + pat: &Pat<'tcx>, ) -> Result { let (from, to, end, ty) = match pat.kind { - box PatternKind::Constant { value } => (value, value, RangeEnd::Included, value.ty), - box PatternKind::Range(PatternRange { lo, hi, end, ty }) => (lo, hi, end, ty), + box PatKind::Constant { value } => (value, value, RangeEnd::Included, value.ty), + box PatKind::Range(PatRange { lo, hi, end }) => (lo, hi, end, lo.ty), _ => bug!("`constructor_covered_by_range` called with {:?}", pat), }; trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty); @@ -1712,9 +1741,9 @@ fn constructor_covered_by_range<'tcx>( } fn patterns_for_variant<'p, 'tcx>( - subpatterns: &'p [FieldPattern<'tcx>], - wild_patterns: &[&'p Pattern<'tcx>]) - -> SmallVec<[&'p Pattern<'tcx>; 2]> + subpatterns: &'p [FieldPat<'tcx>], + wild_patterns: &[&'p Pat<'tcx>]) + -> SmallVec<[&'p Pat<'tcx>; 2]> { let mut result = SmallVec::from_slice(wild_patterns); @@ -1736,124 +1765,138 @@ fn patterns_for_variant<'p, 'tcx>( /// fields filled with wild patterns. fn specialize<'p, 'a: 'p, 'tcx>( cx: &mut MatchCheckCtxt<'a, 'tcx>, - r: &[&'p Pattern<'tcx>], + r: &[&'p Pat<'tcx>], constructor: &Constructor<'tcx>, - wild_patterns: &[&'p Pattern<'tcx>], -) -> Option; 2]>> { + wild_patterns: &[&'p Pat<'tcx>], +) -> Option; 2]>> { let pat = &r[0]; let head = match *pat.kind { - PatternKind::AscribeUserType { ref subpattern, .. } => { + PatKind::AscribeUserType { ref subpattern, .. } => { specialize(cx, ::std::slice::from_ref(&subpattern), constructor, wild_patterns) } - PatternKind::Binding { .. } | PatternKind::Wild => { + PatKind::Binding { .. } | PatKind::Wild => { Some(SmallVec::from_slice(wild_patterns)) } - PatternKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { + PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { let ref variant = adt_def.variants[variant_index]; Some(Variant(variant.def_id)) .filter(|variant_constructor| variant_constructor == constructor) .map(|_| patterns_for_variant(subpatterns, wild_patterns)) } - PatternKind::Leaf { ref subpatterns } => { + PatKind::Leaf { ref subpatterns } => { Some(patterns_for_variant(subpatterns, wild_patterns)) } - PatternKind::Deref { ref subpattern } => { + PatKind::Deref { ref subpattern } => { Some(smallvec![subpattern]) } - PatternKind::Constant { value } => { - match *constructor { - Slice(..) => { - // we extract an `Option` for the pointer because slices of zero elements don't - // necessarily point to memory, they are usually just integers. The only time - // they should be pointing to memory is when they are subslices of nonzero - // slices - let (alloc, offset, n, ty) = match value.ty.sty { - ty::Array(t, n) => { - match value.val { - ConstValue::ByRef { offset, alloc, .. } => ( - alloc, - offset, - n.eval_usize(cx.tcx, cx.param_env), - t, - ), - _ => span_bug!( - pat.span, - "array pattern is {:?}", value, - ), - } - }, - ty::Slice(t) => { - match value.val { - ConstValue::Slice { data, start, end } => ( - data, - Size::from_bytes(start as u64), - (end - start) as u64, - t, - ), - ConstValue::ByRef { .. } => { - // FIXME(oli-obk): implement `deref` for `ConstValue` - return None; - }, - _ => span_bug!( - pat.span, - "slice pattern constant must be scalar pair but is {:?}", - value, - ), - } + PatKind::Constant { value } if constructor.is_slice() => { + // We extract an `Option` for the pointer because slices of zero + // elements don't necessarily point to memory, they are usually + // just integers. The only time they should be pointing to memory + // is when they are subslices of nonzero slices. + let (alloc, offset, n, ty) = match value.ty.kind { + ty::Array(t, n) => { + match value.val { + ConstValue::ByRef { offset, alloc, .. } => ( + alloc, + offset, + n.eval_usize(cx.tcx, cx.param_env), + t, + ), + _ => span_bug!( + pat.span, + "array pattern is {:?}", value, + ), + } + }, + ty::Slice(t) => { + match value.val { + ConstValue::Slice { data, start, end } => ( + data, + Size::from_bytes(start as u64), + (end - start) as u64, + t, + ), + ConstValue::ByRef { .. } => { + // FIXME(oli-obk): implement `deref` for `ConstValue` + return None; }, _ => span_bug!( pat.span, - "unexpected const-val {:?} with ctor {:?}", + "slice pattern constant must be scalar pair but is {:?}", value, - constructor, ), - }; - if wild_patterns.len() as u64 == n { - // convert a constant slice/array pattern to a list of patterns. - let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?; - let ptr = Pointer::new(AllocId(0), offset); - (0..n).map(|i| { - let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?; - let scalar = alloc.read_scalar( - &cx.tcx, ptr, layout.size, - ).ok()?; - let scalar = scalar.not_undef().ok()?; - let value = ty::Const::from_scalar(cx.tcx, scalar, ty); - let pattern = Pattern { - ty, - span: pat.span, - kind: box PatternKind::Constant { value }, - }; - Some(&*cx.pattern_arena.alloc(pattern)) - }).collect() - } else { - None } - } - _ => { - // If the constructor is a: - // Single value: add a row if the constructor equals the pattern. - // Range: add a row if the constructor contains the pattern. - constructor_intersects_pattern(cx.tcx, cx.param_env, constructor, pat) - } + }, + _ => span_bug!( + pat.span, + "unexpected const-val {:?} with ctor {:?}", + value, + constructor, + ), + }; + if wild_patterns.len() as u64 == n { + // convert a constant slice/array pattern to a list of patterns. + let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?; + let ptr = Pointer::new(AllocId(0), offset); + (0..n).map(|i| { + let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?; + let scalar = alloc.read_scalar( + &cx.tcx, ptr, layout.size, + ).ok()?; + let scalar = scalar.not_undef().ok()?; + let value = ty::Const::from_scalar(cx.tcx, scalar, ty); + let pattern = Pat { + ty, + span: pat.span, + kind: box PatKind::Constant { value }, + }; + Some(&*cx.pattern_arena.alloc(pattern)) + }).collect() + } else { + None } } - PatternKind::Range { .. } => { + PatKind::Constant { .. } | + PatKind::Range { .. } => { // If the constructor is a: - // Single value: add a row if the pattern contains the constructor. - // Range: add a row if the constructor intersects the pattern. - constructor_intersects_pattern(cx.tcx, cx.param_env, constructor, pat) + // - Single value: add a row if the pattern contains the constructor. + // - Range: add a row if the constructor intersects the pattern. + if should_treat_range_exhaustively(cx.tcx, constructor) { + match (IntRange::from_ctor(cx.tcx, cx.param_env, constructor), + IntRange::from_pat(cx.tcx, cx.param_env, pat)) { + (Some(ctor), Some(pat)) => { + ctor.intersection(&pat).map(|_| { + let (pat_lo, pat_hi) = pat.range.into_inner(); + let (ctor_lo, ctor_hi) = ctor.range.into_inner(); + assert!(pat_lo <= ctor_lo && ctor_hi <= pat_hi); + smallvec![] + }) + } + _ => None, + } + } else { + // Fallback for non-ranges and ranges that involve + // floating-point numbers, which are not conveniently handled + // by `IntRange`. For these cases, the constructor may not be a + // range so intersection actually devolves into being covered + // by the pattern. + match constructor_covered_by_range(cx.tcx, cx.param_env, constructor, pat) { + Ok(true) => Some(smallvec![]), + Ok(false) | Err(ErrorReported) => None, + } + } } - PatternKind::Array { ref prefix, ref slice, ref suffix } | - PatternKind::Slice { ref prefix, ref slice, ref suffix } => { + PatKind::Array { ref prefix, ref slice, ref suffix } | + PatKind::Slice { ref prefix, ref slice, ref suffix } => { match *constructor { Slice(..) => { let pat_len = prefix.len() + suffix.len(); @@ -1885,6 +1928,10 @@ fn specialize<'p, 'a: 'p, 'tcx>( "unexpected ctor {:?} for slice pat", constructor) } } + + PatKind::Or { .. } => { + bug!("support for or-patterns has not been fully implemented yet."); + } }; debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head); diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 17fd9377a1629..c521b7352214b 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -2,14 +2,8 @@ use super::_match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful}; use super::_match::Usefulness::*; use super::_match::WitnessPreference::*; -use super::{Pattern, PatternContext, PatternError, PatternKind}; - -use rustc::middle::borrowck::SignalledError; -use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; -use rustc::middle::expr_use_visitor::{LoanCause, MutateMode}; -use rustc::middle::expr_use_visitor as euv; -use rustc::middle::mem_categorization::cmt_; -use rustc::middle::region; +use super::{PatCtxt, PatternError, PatKind}; + use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{InternalSubsts, SubstsRef}; @@ -19,32 +13,26 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc::hir::def::*; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; -use rustc::hir::ptr::P; -use rustc::hir::{self, Pat, PatKind}; +use rustc::hir::{self, Pat}; use smallvec::smallvec; use std::slice; use syntax_pos::{Span, DUMMY_SP, MultiSpan}; -crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) -> SignalledError { - let body_id = if let Some(id) = tcx.hir().as_local_hir_id(def_id) { - tcx.hir().body_owned_by(id) - } else { - return SignalledError::NoErrorsSeen; +crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { + let body_id = match tcx.hir().as_local_hir_id(def_id) { + None => return, + Some(id) => tcx.hir().body_owned_by(id), }; let mut visitor = MatchVisitor { tcx, - body_owner: def_id, tables: tcx.body_tables(body_id), - region_scope_tree: &tcx.region_scope_tree(def_id), param_env: tcx.param_env(def_id), identity_substs: InternalSubsts::identity_for_item(tcx, def_id), - signalled_error: SignalledError::NoErrorsSeen, }; visitor.visit_body(tcx.hir().body(body_id)); - visitor.signalled_error } fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBuilder<'_> { @@ -53,15 +41,12 @@ fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBu struct MatchVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, - body_owner: DefId, tables: &'a ty::TypeckTables<'tcx>, param_env: ty::ParamEnv<'tcx>, identity_substs: SubstsRef<'tcx>, - region_scope_tree: &'a region::ScopeTree, - signalled_error: SignalledError, } -impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::None } @@ -69,7 +54,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> { fn visit_expr(&mut self, ex: &'tcx hir::Expr) { intravisit::walk_expr(self, ex); - if let hir::ExprKind::Match(ref scrut, ref arms, source) = ex.node { + if let hir::ExprKind::Match(ref scrut, ref arms, source) = ex.kind { self.check_match(scrut, arms, source); } } @@ -85,21 +70,20 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> { }); // Check legality of move bindings and `@` patterns. - self.check_patterns(false, slice::from_ref(&loc.pat)); + self.check_patterns(false, &loc.pat); } fn visit_body(&mut self, body: &'tcx hir::Body) { intravisit::walk_body(self, body); - for arg in &body.arguments { - self.check_irrefutable(&arg.pat, "function argument"); - self.check_patterns(false, slice::from_ref(&arg.pat)); + for param in &body.params { + self.check_irrefutable(¶m.pat, "function argument"); + self.check_patterns(false, ¶m.pat); } } } - -impl<'a, 'tcx> PatternContext<'a, 'tcx> { +impl PatCtxt<'_, '_> { fn report_inlining_errors(&self, pat_span: Span) { for error in &self.errors { match *error { @@ -131,12 +115,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } -impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { - fn check_patterns(&mut self, has_guard: bool, pats: &[P]) { - check_legality_of_move_bindings(self, has_guard, pats); - for pat in pats { - check_legality_of_bindings_in_at_patterns(self, pat); - } +impl<'tcx> MatchVisitor<'_, 'tcx> { + fn check_patterns(&mut self, has_guard: bool, pat: &Pat) { + check_legality_of_move_bindings(self, has_guard, pat); + check_legality_of_bindings_in_at_patterns(self, pat); } fn check_match( @@ -147,21 +129,10 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { ) { for arm in arms { // First, check legality of move bindings. - self.check_patterns(arm.guard.is_some(), &arm.pats); - - // Second, if there is a guard on each arm, make sure it isn't - // assigning or borrowing anything mutably. - if let Some(ref guard) = arm.guard { - self.signalled_error = SignalledError::SawSomeError; - if !self.tcx.features().bind_by_move_pattern_guards { - check_for_mutation_in_guard(self, &guard); - } - } + self.check_patterns(arm.guard.is_some(), &arm.pat); - // Third, perform some lints. - for pat in &arm.pats { - check_for_bindings_named_same_as_variants(self, pat); - } + // Second, perform some lints. + check_for_bindings_named_same_as_variants(self, &arm.pat); } let module = self.tcx.hir().get_module_parent(scrut.hir_id); @@ -169,10 +140,17 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { let mut have_errors = false; let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| ( - arm.pats.iter().map(|pat| { - let mut patcx = PatternContext::new(self.tcx, - self.param_env.and(self.identity_substs), - self.tables); + // HACK(or_patterns; Centril | dlrobertson): Remove this and + // correctly handle exhaustiveness checking for nested or-patterns. + match &arm.pat.kind { + hir::PatKind::Or(pats) => pats, + _ => std::slice::from_ref(&arm.pat), + }.iter().map(|pat| { + let mut patcx = PatCtxt::new( + self.tcx, + self.param_env.and(self.identity_substs), + self.tables + ); patcx.include_lint_checks(); let pattern = expand_pattern(cx, patcx.lower_pattern(&pat)); if !patcx.errors.is_empty() { @@ -204,7 +182,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns { self.tcx.is_ty_uninhabited_from(module, pat_ty) } else { - match pat_ty.sty { + match pat_ty.kind { ty::Never => true, ty::Adt(def, _) => { def_span = self.tcx.hir().span_if_local(def.did); @@ -267,7 +245,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str) { let module = self.tcx.hir().get_module_parent(pat.hir_id); MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| { - let mut patcx = PatternContext::new(self.tcx, + let mut patcx = PatCtxt::new(self.tcx, self.param_env.and(self.identity_substs), self.tables); patcx.include_lint_checks(); @@ -277,52 +255,72 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { expand_pattern(cx, pattern) ]].into_iter().collect(); - let wild_pattern = Pattern { - ty: pattern_ty, - span: DUMMY_SP, - kind: box PatternKind::Wild, - }; - let witness = match is_useful(cx, &pats, &[&wild_pattern], ConstructWitness) { - UsefulWithWitness(witness) => witness, - NotUseful => return, - Useful => bug!() + let witnesses = match check_not_useful(cx, pattern_ty, &pats) { + Ok(_) => return, + Err(err) => err, }; - let pattern_string = witness[0].single_pattern().to_string(); + let joined_patterns = joined_uncovered_patterns(&witnesses); let mut err = struct_span_err!( self.tcx.sess, pat.span, E0005, - "refutable pattern in {}: `{}` not covered", - origin, pattern_string + "refutable pattern in {}: {} not covered", + origin, joined_patterns ); - let label_msg = match pat.node { - PatKind::Path(hir::QPath::Resolved(None, ref path)) - if path.segments.len() == 1 && path.segments[0].args.is_none() => { - format!("interpreted as {} {} pattern, not new variable", - path.res.article(), path.res.descr()) + match &pat.kind { + hir::PatKind::Path(hir::QPath::Resolved(None, path)) + if path.segments.len() == 1 && path.segments[0].args.is_none() => + { + const_not_var(&mut err, cx.tcx, pat, path); } - _ => format!("pattern `{}` not covered", pattern_string), - }; - err.span_label(pat.span, label_msg); - if let ty::Adt(def, _) = pattern_ty.sty { - if let Some(sp) = self.tcx.hir().span_if_local(def.did){ - err.span_label(sp, format!("`{}` defined here", pattern_ty)); + _ => { + err.span_label( + pat.span, + pattern_not_covered_label(&witnesses, &joined_patterns), + ); } } + + adt_defined_here(cx, &mut err, pattern_ty, &witnesses); err.emit(); }); } } +/// A path pattern was interpreted as a constant, not a new variable. +/// This caused an irrefutable match failure in e.g. `let`. +fn const_not_var(err: &mut DiagnosticBuilder<'_>, tcx: TyCtxt<'_>, pat: &Pat, path: &hir::Path) { + let descr = path.res.descr(); + err.span_label(pat.span, format!( + "interpreted as {} {} pattern, not a new variable", + path.res.article(), + descr, + )); + + err.span_suggestion( + pat.span, + "introduce a variable instead", + format!("{}_var", path.segments[0].ident).to_lowercase(), + // Cannot use `MachineApplicable` as it's not really *always* correct + // because there may be such an identifier in scope or the user maybe + // really wanted to match against the constant. This is quite unlikely however. + Applicability::MaybeIncorrect, + ); + + if let Some(span) = tcx.hir().res_span(path.res) { + err.span_label(span, format!("{} defined here", descr)); + } +} + fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pat) { pat.walk(|p| { - if let PatKind::Binding(_, _, ident, None) = p.node { + if let hir::PatKind::Binding(_, _, ident, None) = p.kind { if let Some(&bm) = cx.tables.pat_binding_modes().get(p.hir_id) { if bm != ty::BindByValue(hir::MutImmutable) { // Nothing to check. return true; } let pat_ty = cx.tables.pat_ty(p); - if let ty::Adt(edef, _) = pat_ty.sty { + if let ty::Adt(edef, _) = pat_ty.kind { if edef.is_enum() && edef.variants.iter().any(|variant| { variant.ident == ident && variant.ctor_kind == CtorKind::Const }) { @@ -350,11 +348,11 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa /// Checks for common cases of "catchall" patterns that may not be intended as such. fn pat_is_catchall(pat: &Pat) -> bool { - match pat.node { - PatKind::Binding(.., None) => true, - PatKind::Binding(.., Some(ref s)) => pat_is_catchall(s), - PatKind::Ref(ref s, _) => pat_is_catchall(s), - PatKind::Tuple(ref v, _) => v.iter().all(|p| { + match pat.kind { + hir::PatKind::Binding(.., None) => true, + hir::PatKind::Binding(.., Some(ref s)) => pat_is_catchall(s), + hir::PatKind::Ref(ref s, _) => pat_is_catchall(s), + hir::PatKind::Tuple(ref v, _) => v.iter().all(|p| { pat_is_catchall(&p) }), _ => false @@ -362,9 +360,9 @@ fn pat_is_catchall(pat: &Pat) -> bool { } // Check for unreachable patterns -fn check_arms<'a, 'tcx>( - cx: &mut MatchCheckCtxt<'a, 'tcx>, - arms: &[(Vec<(&'a Pattern<'tcx>, &hir::Pat)>, Option<&hir::Expr>)], +fn check_arms<'tcx>( + cx: &mut MatchCheckCtxt<'_, 'tcx>, + arms: &[(Vec<(&super::Pat<'tcx>, &hir::Pat)>, Option<&hir::Expr>)], source: hir::MatchSource, ) { let mut seen = Matrix::empty(); @@ -445,263 +443,195 @@ fn check_arms<'a, 'tcx>( } } -fn check_exhaustive<'p, 'a, 'tcx>( - cx: &mut MatchCheckCtxt<'a, 'tcx>, +fn check_not_useful( + cx: &mut MatchCheckCtxt<'_, 'tcx>, + ty: Ty<'tcx>, + matrix: &Matrix<'_, 'tcx>, +) -> Result<(), Vec>> { + let wild_pattern = super::Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild }; + match is_useful(cx, matrix, &[&wild_pattern], ConstructWitness) { + NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable. + UsefulWithWitness(pats) => Err(if pats.is_empty() { + vec![wild_pattern] + } else { + pats.into_iter().map(|w| w.single_pattern()).collect() + }), + Useful => bug!(), + } +} + +fn check_exhaustive<'tcx>( + cx: &mut MatchCheckCtxt<'_, 'tcx>, scrut_ty: Ty<'tcx>, sp: Span, - matrix: &Matrix<'p, 'tcx>, + matrix: &Matrix<'_, 'tcx>, ) { - let wild_pattern = Pattern { - ty: scrut_ty, - span: DUMMY_SP, - kind: box PatternKind::Wild, + let witnesses = match check_not_useful(cx, scrut_ty, matrix) { + Ok(_) => return, + Err(err) => err, }; - match is_useful(cx, matrix, &[&wild_pattern], ConstructWitness) { - UsefulWithWitness(pats) => { - let witnesses = if pats.is_empty() { - vec![&wild_pattern] - } else { - pats.iter().map(|w| w.single_pattern()).collect() - }; - const LIMIT: usize = 3; - let joined_patterns = match witnesses.len() { - 0 => bug!(), - 1 => format!("`{}`", witnesses[0]), - 2..=LIMIT => { - let (tail, head) = witnesses.split_last().unwrap(); - let head: Vec<_> = head.iter().map(|w| w.to_string()).collect(); - format!("`{}` and `{}`", head.join("`, `"), tail) - } - _ => { - let (head, tail) = witnesses.split_at(LIMIT); - let head: Vec<_> = head.iter().map(|w| w.to_string()).collect(); - format!("`{}` and {} more", head.join("`, `"), tail.len()) - } - }; + let joined_patterns = joined_uncovered_patterns(&witnesses); + let mut err = create_e0004( + cx.tcx.sess, sp, + format!("non-exhaustive patterns: {} not covered", joined_patterns), + ); + err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns)); + adt_defined_here(cx, &mut err, scrut_ty, &witnesses); + err.help( + "ensure that all possible cases are being handled, \ + possibly by adding wildcards or more match arms" + ) + .emit(); +} - let label_text = match witnesses.len() { - 1 => format!("pattern {} not covered", joined_patterns), - _ => format!("patterns {} not covered", joined_patterns), - }; - let mut err = create_e0004(cx.tcx.sess, sp, format!( - "non-exhaustive patterns: {} not covered", - joined_patterns, - )); - err.span_label(sp, label_text); - // point at the definition of non-covered enum variants - if let ty::Adt(def, _) = scrut_ty.sty { - if let Some(sp) = cx.tcx.hir().span_if_local(def.did){ - err.span_label(sp, format!("`{}` defined here", scrut_ty)); - } - } - let patterns = witnesses.iter().map(|p| (**p).clone()).collect::>>(); - if patterns.len() < 4 { - for sp in maybe_point_at_variant(cx, scrut_ty, patterns.as_slice()) { - err.span_label(sp, "not covered"); - } - } - err.help("ensure that all possible cases are being handled, \ - possibly by adding wildcards or more match arms"); - err.emit(); +fn joined_uncovered_patterns(witnesses: &[super::Pat<'_>]) -> String { + const LIMIT: usize = 3; + match witnesses { + [] => bug!(), + [witness] => format!("`{}`", witness), + [head @ .., tail] if head.len() < LIMIT => { + let head: Vec<_> = head.iter().map(<_>::to_string).collect(); + format!("`{}` and `{}`", head.join("`, `"), tail) } - NotUseful => { - // This is good, wildcard pattern isn't reachable + _ => { + let (head, tail) = witnesses.split_at(LIMIT); + let head: Vec<_> = head.iter().map(<_>::to_string).collect(); + format!("`{}` and {} more", head.join("`, `"), tail.len()) } - _ => bug!() } } -fn maybe_point_at_variant( - cx: &mut MatchCheckCtxt<'a, 'tcx>, - ty: Ty<'tcx>, - patterns: &[Pattern<'_>], -) -> Vec { +fn pattern_not_covered_label(witnesses: &[super::Pat<'_>], joined_patterns: &str) -> String { + format!("pattern{} {} not covered", rustc_errors::pluralise!(witnesses.len()), joined_patterns) +} + +/// Point at the definition of non-covered `enum` variants. +fn adt_defined_here( + cx: &MatchCheckCtxt<'_, '_>, + err: &mut DiagnosticBuilder<'_>, + ty: Ty<'_>, + witnesses: &[super::Pat<'_>], +) { + let ty = ty.peel_refs(); + if let ty::Adt(def, _) = ty.kind { + if let Some(sp) = cx.tcx.hir().span_if_local(def.did) { + err.span_label(sp, format!("`{}` defined here", ty)); + } + + if witnesses.len() < 4 { + for sp in maybe_point_at_variant(ty, &witnesses) { + err.span_label(sp, "not covered"); + } + } + } +} + +fn maybe_point_at_variant(ty: Ty<'_>, patterns: &[super::Pat<'_>]) -> Vec { let mut covered = vec![]; - if let ty::Adt(def, _) = ty.sty { + if let ty::Adt(def, _) = ty.kind { // Don't point at variants that have already been covered due to other patterns to avoid - // visual clutter + // visual clutter. for pattern in patterns { - let pk: &PatternKind<'_> = &pattern.kind; - if let PatternKind::Variant { adt_def, variant_index, subpatterns, .. } = pk { - if adt_def.did == def.did { + use PatKind::{AscribeUserType, Deref, Variant, Or, Leaf}; + match &*pattern.kind { + AscribeUserType { subpattern, .. } | Deref { subpattern } => { + covered.extend(maybe_point_at_variant(ty, slice::from_ref(&subpattern))); + } + Variant { adt_def, variant_index, subpatterns, .. } if adt_def.did == def.did => { let sp = def.variants[*variant_index].ident.span; if covered.contains(&sp) { continue; } covered.push(sp); - let subpatterns = subpatterns.iter() + + let pats = subpatterns.iter() .map(|field_pattern| field_pattern.pattern.clone()) - .collect::>(); - covered.extend( - maybe_point_at_variant(cx, ty, subpatterns.as_slice()), - ); + .collect::>(); + covered.extend(maybe_point_at_variant(ty, &pats)); } - } - if let PatternKind::Leaf { subpatterns } = pk { - let subpatterns = subpatterns.iter() - .map(|field_pattern| field_pattern.pattern.clone()) - .collect::>(); - covered.extend(maybe_point_at_variant(cx, ty, subpatterns.as_slice())); + Leaf { subpatterns } => { + let pats = subpatterns.iter() + .map(|field_pattern| field_pattern.pattern.clone()) + .collect::>(); + covered.extend(maybe_point_at_variant(ty, &pats)); + } + Or { pats } => { + let pats = pats.iter().cloned().collect::>(); + covered.extend(maybe_point_at_variant(ty, &pats)); + } + _ => {} } } } covered } -// Legality of move bindings checking -fn check_legality_of_move_bindings( - cx: &mut MatchVisitor<'_, '_>, - has_guard: bool, - pats: &[P], -) { +// Check the legality of legality of by-move bindings. +fn check_legality_of_move_bindings(cx: &mut MatchVisitor<'_, '_>, has_guard: bool, pat: &Pat) { let mut by_ref_span = None; - for pat in pats { - pat.each_binding(|_, hir_id, span, _path| { - if let Some(&bm) = cx.tables.pat_binding_modes().get(hir_id) { - if let ty::BindByReference(..) = bm { - by_ref_span = Some(span); - } - } else { - cx.tcx.sess.delay_span_bug(pat.span, "missing binding mode"); + pat.each_binding(|_, hir_id, span, _| { + if let Some(&bm) = cx.tables.pat_binding_modes().get(hir_id) { + if let ty::BindByReference(..) = bm { + by_ref_span = Some(span); } - }) - } + } else { + cx.tcx.sess.delay_span_bug(pat.span, "missing binding mode"); + } + }); + let span_vec = &mut Vec::new(); - let check_move = | - cx: &mut MatchVisitor<'_, '_>, - p: &Pat, - sub: Option<&Pat>, - span_vec: &mut Vec, - | { - // check legality of moving out of the enum - - // x @ Foo(..) is legal, but x @ Foo(y) isn't. + let mut check_move = |p: &Pat, sub: Option<&Pat>| { + // Check legality of moving out of the enum. + // + // `x @ Foo(..)` is legal, but `x @ Foo(y)` isn't. if sub.map_or(false, |p| p.contains_bindings()) { - struct_span_err!(cx.tcx.sess, p.span, E0007, - "cannot bind by-move with sub-bindings") + struct_span_err!(cx.tcx.sess, p.span, E0007, "cannot bind by-move with sub-bindings") .span_label(p.span, "binds an already bound by-move value by moving it") .emit(); - } else if has_guard { - if !cx.tcx.features().bind_by_move_pattern_guards { - let mut err = struct_span_err!(cx.tcx.sess, p.span, E0008, - "cannot bind by-move into a pattern guard"); - err.span_label(p.span, "moves value into pattern guard"); - if cx.tcx.sess.opts.unstable_features.is_nightly_build() { - err.help("add `#![feature(bind_by_move_pattern_guards)]` to the \ - crate attributes to enable"); - } - err.emit(); - } - } else if let Some(_by_ref_span) = by_ref_span { + } else if !has_guard && by_ref_span.is_some() { span_vec.push(p.span); } }; - for pat in pats { - pat.walk(|p| { - if let PatKind::Binding(_, _, _, ref sub) = p.node { - if let Some(&bm) = cx.tables.pat_binding_modes().get(p.hir_id) { - match bm { - ty::BindByValue(..) => { - let pat_ty = cx.tables.node_type(p.hir_id); - if !pat_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, pat.span) { - check_move(cx, p, sub.as_ref().map(|p| &**p), span_vec); - } - } - _ => {} + pat.walk(|p| { + if let hir::PatKind::Binding(.., sub) = &p.kind { + if let Some(&bm) = cx.tables.pat_binding_modes().get(p.hir_id) { + if let ty::BindByValue(..) = bm { + let pat_ty = cx.tables.node_type(p.hir_id); + if !pat_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, pat.span) { + check_move(p, sub.as_deref()); } - } else { - cx.tcx.sess.delay_span_bug(pat.span, "missing binding mode"); } + } else { + cx.tcx.sess.delay_span_bug(pat.span, "missing binding mode"); } - true - }); - } - if !span_vec.is_empty(){ - let span = MultiSpan::from_spans(span_vec.clone()); + } + true + }); + + if !span_vec.is_empty() { let mut err = struct_span_err!( cx.tcx.sess, - span, + MultiSpan::from_spans(span_vec.clone()), E0009, "cannot bind by-move and by-ref in the same pattern", ); if let Some(by_ref_span) = by_ref_span { err.span_label(by_ref_span, "both by-ref and by-move used"); } - for span in span_vec.iter(){ + for span in span_vec.iter() { err.span_label(*span, "by-move pattern here"); } err.emit(); } } -/// Ensures that a pattern guard doesn't borrow by mutable reference or assign. -// -// FIXME: this should be done by borrowck. -fn check_for_mutation_in_guard(cx: &MatchVisitor<'_, '_>, guard: &hir::Guard) { - let mut checker = MutationChecker { - cx, - }; - match guard { - hir::Guard::If(expr) => - ExprUseVisitor::new(&mut checker, - cx.tcx, - cx.body_owner, - cx.param_env, - cx.region_scope_tree, - cx.tables, - None).walk_expr(expr), - }; -} - -struct MutationChecker<'a, 'tcx> { - cx: &'a MatchVisitor<'a, 'tcx>, -} - -impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> { - fn matched_pat(&mut self, _: &Pat, _: &cmt_<'_>, _: euv::MatchMode) {} - fn consume(&mut self, _: hir::HirId, _: Span, _: &cmt_<'_>, _: ConsumeMode) {} - fn consume_pat(&mut self, _: &Pat, _: &cmt_<'_>, _: ConsumeMode) {} - fn borrow(&mut self, - _: hir::HirId, - span: Span, - _: &cmt_<'_>, - _: ty::Region<'tcx>, - kind:ty:: BorrowKind, - _: LoanCause) { - match kind { - ty::MutBorrow => { - let mut err = struct_span_err!(self.cx.tcx.sess, span, E0301, - "cannot mutably borrow in a pattern guard"); - err.span_label(span, "borrowed mutably in pattern guard"); - if self.cx.tcx.sess.opts.unstable_features.is_nightly_build() { - err.help("add `#![feature(bind_by_move_pattern_guards)]` to the \ - crate attributes to enable"); - } - err.emit(); - } - ty::ImmBorrow | ty::UniqueImmBorrow => {} - } - } - fn decl_without_init(&mut self, _: hir::HirId, _: Span) {} - fn mutate(&mut self, _: hir::HirId, span: Span, _: &cmt_<'_>, mode: MutateMode) { - match mode { - MutateMode::JustWrite | MutateMode::WriteAndRead => { - struct_span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard") - .span_label(span, "assignment in pattern guard") - .emit(); - } - MutateMode::Init => {} - } - } -} - /// Forbids bindings in `@` patterns. This is necessary for memory safety, /// because of the way rvalues are handled in the borrow check. (See issue /// #14587.) fn check_legality_of_bindings_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat) { - AtBindingPatternVisitor { cx: cx, bindings_allowed: true }.visit_pat(pat); + AtBindingPatternVisitor { cx, bindings_allowed: true }.visit_pat(pat); } struct AtBindingPatternVisitor<'a, 'b, 'tcx> { @@ -709,14 +639,14 @@ struct AtBindingPatternVisitor<'a, 'b, 'tcx> { bindings_allowed: bool } -impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> { +impl<'v> Visitor<'v> for AtBindingPatternVisitor<'_, '_, '_> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { NestedVisitorMap::None } fn visit_pat(&mut self, pat: &Pat) { - match pat.node { - PatKind::Binding(.., ref subpat) => { + match pat.kind { + hir::PatKind::Binding(.., ref subpat) => { if !self.bindings_allowed { struct_span_err!(self.cx.tcx.sess, pat.span, E0303, "pattern bindings are not allowed after an `@`") diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 5ecfb84b63236..58d741b9295a3 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -13,18 +13,18 @@ use crate::hair::constant::*; use rustc::lint; use rustc::mir::{Field, BorrowKind, Mutability}; use rustc::mir::{UserTypeProjection}; -use rustc::mir::interpret::{GlobalId, ConstValue, sign_extend, AllocId, Pointer}; +use rustc::mir::interpret::{GlobalId, ConstValue, get_slice_bytes, sign_extend}; use rustc::traits::{ObligationCause, PredicateObligation}; use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, UserType, DefIdTree}; use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations}; -use rustc::ty::subst::{SubstsRef, Kind}; -use rustc::ty::layout::{VariantIdx, Size}; -use rustc::hir::{self, PatKind, RangeEnd}; +use rustc::ty::subst::{SubstsRef, GenericArg}; +use rustc::ty::layout::VariantIdx; +use rustc::hir::{self, RangeEnd}; use rustc::hir::def::{CtorOf, Res, DefKind, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::hir::ptr::P; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use rustc_data_structures::fx::FxHashSet; use std::cmp::Ordering; @@ -48,25 +48,25 @@ pub enum BindingMode { } #[derive(Clone, Debug)] -pub struct FieldPattern<'tcx> { +pub struct FieldPat<'tcx> { pub field: Field, - pub pattern: Pattern<'tcx>, + pub pattern: Pat<'tcx>, } #[derive(Clone, Debug)] -pub struct Pattern<'tcx> { +pub struct Pat<'tcx> { pub ty: Ty<'tcx>, pub span: Span, - pub kind: Box>, + pub kind: Box>, } #[derive(Copy, Clone, Debug, PartialEq)] -pub struct PatternTypeProjection<'tcx> { +pub struct PatTyProj<'tcx> { pub user_ty: CanonicalUserType<'tcx>, } -impl<'tcx> PatternTypeProjection<'tcx> { +impl<'tcx> PatTyProj<'tcx> { pub(crate) fn from_user_type(user_annotation: CanonicalUserType<'tcx>) -> Self { Self { user_ty: user_annotation, @@ -92,7 +92,7 @@ impl<'tcx> PatternTypeProjection<'tcx> { #[derive(Copy, Clone, Debug, PartialEq)] pub struct Ascription<'tcx> { - pub user_ty: PatternTypeProjection<'tcx>, + pub user_ty: PatTyProj<'tcx>, /// Variance to use when relating the type `user_ty` to the **type of the value being /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must /// have a type that is some subtype of the ascribed type. @@ -116,12 +116,12 @@ pub struct Ascription<'tcx> { } #[derive(Clone, Debug)] -pub enum PatternKind<'tcx> { +pub enum PatKind<'tcx> { Wild, AscribeUserType { ascription: Ascription<'tcx>, - subpattern: Pattern<'tcx>, + subpattern: Pat<'tcx>, }, /// `x`, `ref x`, `x @ P`, etc. @@ -131,7 +131,7 @@ pub enum PatternKind<'tcx> { mode: BindingMode, var: hir::HirId, ty: Ty<'tcx>, - subpattern: Option>, + subpattern: Option>, }, /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with @@ -140,58 +140,75 @@ pub enum PatternKind<'tcx> { adt_def: &'tcx AdtDef, substs: SubstsRef<'tcx>, variant_index: VariantIdx, - subpatterns: Vec>, + subpatterns: Vec>, }, /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with /// a single variant. Leaf { - subpatterns: Vec>, + subpatterns: Vec>, }, /// `box P`, `&P`, `&mut P`, etc. Deref { - subpattern: Pattern<'tcx>, + subpattern: Pat<'tcx>, }, Constant { value: &'tcx ty::Const<'tcx>, }, - Range(PatternRange<'tcx>), + Range(PatRange<'tcx>), /// Matches against a slice, checking the length and extracting elements. /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty. /// e.g., `&[ref xs @ ..]`. Slice { - prefix: Vec>, - slice: Option>, - suffix: Vec>, + prefix: Vec>, + slice: Option>, + suffix: Vec>, }, /// Fixed match against an array; irrefutable. Array { - prefix: Vec>, - slice: Option>, - suffix: Vec>, + prefix: Vec>, + slice: Option>, + suffix: Vec>, + }, + + /// An or-pattern, e.g. `p | q`. + /// Invariant: `pats.len() >= 2`. + Or { + pats: Vec>, }, } #[derive(Copy, Clone, Debug, PartialEq)] -pub struct PatternRange<'tcx> { +pub struct PatRange<'tcx> { pub lo: &'tcx ty::Const<'tcx>, pub hi: &'tcx ty::Const<'tcx>, - pub ty: Ty<'tcx>, pub end: RangeEnd, } -impl<'tcx> fmt::Display for Pattern<'tcx> { +impl<'tcx> fmt::Display for Pat<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Printing lists is a chore. + let mut first = true; + let mut start_or_continue = |s| { + if first { + first = false; + "" + } else { + s + } + }; + let mut start_or_comma = || start_or_continue(", "); + match *self.kind { - PatternKind::Wild => write!(f, "_"), - PatternKind::AscribeUserType { ref subpattern, .. } => + PatKind::Wild => write!(f, "_"), + PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern), - PatternKind::Binding { mutability, name, mode, ref subpattern, .. } => { + PatKind::Binding { mutability, name, mode, ref subpattern, .. } => { let is_mut = match mode { BindingMode::ByValue => mutability == Mutability::Mut, BindingMode::ByRef(bk) => { @@ -208,13 +225,13 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { } Ok(()) } - PatternKind::Variant { ref subpatterns, .. } | - PatternKind::Leaf { ref subpatterns } => { + PatKind::Variant { ref subpatterns, .. } | + PatKind::Leaf { ref subpatterns } => { let variant = match *self.kind { - PatternKind::Variant { adt_def, variant_index, .. } => { + PatKind::Variant { adt_def, variant_index, .. } => { Some(&adt_def.variants[variant_index]) } - _ => if let ty::Adt(adt, _) = self.ty.sty { + _ => if let ty::Adt(adt, _) = self.ty.kind { if !adt.is_enum() { Some(&adt.variants[VariantIdx::new(0)]) } else { @@ -225,9 +242,6 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { } }; - let mut first = true; - let mut start_or_continue = || if first { first = false; "" } else { ", " }; - if let Some(variant) = variant { write!(f, "{}", variant.ident)?; @@ -238,16 +252,16 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { let mut printed = 0; for p in subpatterns { - if let PatternKind::Wild = *p.pattern.kind { + if let PatKind::Wild = *p.pattern.kind { continue; } let name = variant.fields[p.field.index()].ident; - write!(f, "{}{}: {}", start_or_continue(), name, p.pattern)?; + write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?; printed += 1; } if printed < variant.fields.len() { - write!(f, "{}..", start_or_continue())?; + write!(f, "{}..", start_or_comma())?; } return write!(f, " }}"); @@ -258,7 +272,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { if num_fields != 0 || variant.is_none() { write!(f, "(")?; for i in 0..num_fields { - write!(f, "{}", start_or_continue())?; + write!(f, "{}", start_or_comma())?; // Common case: the field is where we expect it. if let Some(p) = subpatterns.get(i) { @@ -280,8 +294,8 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { Ok(()) } - PatternKind::Deref { ref subpattern } => { - match self.ty.sty { + PatKind::Deref { ref subpattern } => { + match self.ty.kind { ty::Adt(def, _) if def.is_box() => write!(f, "box ")?, ty::Ref(_, _, mutbl) => { write!(f, "&")?; @@ -293,10 +307,10 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { } write!(f, "{}", subpattern) } - PatternKind::Constant { value } => { + PatKind::Constant { value } => { write!(f, "{}", value) } - PatternKind::Range(PatternRange { lo, hi, ty: _, end }) => { + PatKind::Range(PatRange { lo, hi, end }) => { write!(f, "{}", lo)?; match end { RangeEnd::Included => write!(f, "..=")?, @@ -304,32 +318,36 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { } write!(f, "{}", hi) } - PatternKind::Slice { ref prefix, ref slice, ref suffix } | - PatternKind::Array { ref prefix, ref slice, ref suffix } => { - let mut first = true; - let mut start_or_continue = || if first { first = false; "" } else { ", " }; + PatKind::Slice { ref prefix, ref slice, ref suffix } | + PatKind::Array { ref prefix, ref slice, ref suffix } => { write!(f, "[")?; for p in prefix { - write!(f, "{}{}", start_or_continue(), p)?; + write!(f, "{}{}", start_or_comma(), p)?; } if let Some(ref slice) = *slice { - write!(f, "{}", start_or_continue())?; + write!(f, "{}", start_or_comma())?; match *slice.kind { - PatternKind::Wild => {} + PatKind::Wild => {} _ => write!(f, "{}", slice)? } write!(f, "..")?; } for p in suffix { - write!(f, "{}{}", start_or_continue(), p)?; + write!(f, "{}{}", start_or_comma(), p)?; } write!(f, "]") } + PatKind::Or { ref pats } => { + for pat in pats { + write!(f, "{}{}", start_or_continue(" | "), pat)?; + } + Ok(()) + } } } } -pub struct PatternContext<'a, 'tcx> { +pub struct PatCtxt<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, pub param_env: ty::ParamEnv<'tcx>, pub tables: &'a ty::TypeckTables<'tcx>, @@ -338,31 +356,31 @@ pub struct PatternContext<'a, 'tcx> { include_lint_checks: bool, } -impl<'a, 'tcx> Pattern<'tcx> { +impl<'a, 'tcx> Pat<'tcx> { pub fn from_hir( tcx: TyCtxt<'tcx>, param_env_and_substs: ty::ParamEnvAnd<'tcx, SubstsRef<'tcx>>, tables: &'a ty::TypeckTables<'tcx>, pat: &'tcx hir::Pat, ) -> Self { - let mut pcx = PatternContext::new(tcx, param_env_and_substs, tables); + let mut pcx = PatCtxt::new(tcx, param_env_and_substs, tables); let result = pcx.lower_pattern(pat); if !pcx.errors.is_empty() { let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors); tcx.sess.delay_span_bug(pat.span, &msg); } - debug!("Pattern::from_hir({:?}) = {:?}", pat, result); + debug!("Pat::from_hir({:?}) = {:?}", pat, result); result } } -impl<'a, 'tcx> PatternContext<'a, 'tcx> { +impl<'a, 'tcx> PatCtxt<'a, 'tcx> { pub fn new( tcx: TyCtxt<'tcx>, param_env_and_substs: ty::ParamEnvAnd<'tcx, SubstsRef<'tcx>>, tables: &'a ty::TypeckTables<'tcx>, ) -> Self { - PatternContext { + PatCtxt { tcx, param_env: param_env_and_substs.param_env, tables, @@ -377,7 +395,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { self } - pub fn lower_pattern(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> { + pub fn lower_pattern(&mut self, pat: &'tcx hir::Pat) -> Pat<'tcx> { // When implicit dereferences have been inserted in this pattern, the unadjusted lowered // pattern has the type that results *after* dereferencing. For example, in this code: // @@ -394,7 +412,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { // `vec![&&Option, &Option]`. // // Applying the adjustments, we want to instead output `&&Some(n)` (as a HAIR pattern). So - // we wrap the unadjusted pattern in `PatternKind::Deref` repeatedly, consuming the + // we wrap the unadjusted pattern in `PatKind::Deref` repeatedly, consuming the // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted // gets the least-dereferenced type). let unadjusted_pat = self.lower_pattern_unadjusted(pat); @@ -406,10 +424,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { .rev() .fold(unadjusted_pat, |pat, ref_ty| { debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty); - Pattern { + Pat { span: pat.span, ty: ref_ty, - kind: Box::new(PatternKind::Deref { subpattern: pat }), + kind: Box::new(PatKind::Deref { subpattern: pat }), } }, ) @@ -418,30 +436,32 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { fn lower_range_expr( &mut self, expr: &'tcx hir::Expr, - ) -> (PatternKind<'tcx>, Option>) { + ) -> (PatKind<'tcx>, Option>) { match self.lower_lit(expr) { - PatternKind::AscribeUserType { + PatKind::AscribeUserType { ascription: lo_ascription, - subpattern: Pattern { kind: box kind, .. }, + subpattern: Pat { kind: box kind, .. }, } => (kind, Some(lo_ascription)), kind => (kind, None), } } - fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> { + fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pat<'tcx> { let mut ty = self.tables.node_type(pat.hir_id); - let kind = match pat.node { - PatKind::Wild => PatternKind::Wild, + let kind = match pat.kind { + hir::PatKind::Wild => PatKind::Wild, - PatKind::Lit(ref value) => self.lower_lit(value), + hir::PatKind::Lit(ref value) => self.lower_lit(value), - PatKind::Range(ref lo_expr, ref hi_expr, end) => { + hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => { let (lo, lo_ascription) = self.lower_range_expr(lo_expr); let (hi, hi_ascription) = self.lower_range_expr(hi_expr); let mut kind = match (lo, hi) { - (PatternKind::Constant { value: lo }, PatternKind::Constant { value: hi }) => { + (PatKind::Constant { value: lo }, PatKind::Constant { value: hi }) => { + assert_eq!(lo.ty, ty); + assert_eq!(hi.ty, ty); let cmp = compare_const_vals( self.tcx, lo, @@ -451,7 +471,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ); match (end, cmp) { (RangeEnd::Excluded, Some(Ordering::Less)) => - PatternKind::Range(PatternRange { lo, hi, ty, end }), + PatKind::Range(PatRange { lo, hi, end }), (RangeEnd::Excluded, _) => { span_err!( self.tcx.sess, @@ -459,13 +479,13 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { E0579, "lower range bound must be less than upper", ); - PatternKind::Wild + PatKind::Wild } (RangeEnd::Included, Some(Ordering::Equal)) => { - PatternKind::Constant { value: lo } + PatKind::Constant { value: lo } } (RangeEnd::Included, Some(Ordering::Less)) => { - PatternKind::Range(PatternRange { lo, hi, ty, end }) + PatKind::Range(PatRange { lo, hi, end }) } (RangeEnd::Included, _) => { let mut err = struct_span_err!( @@ -486,7 +506,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { to be less than or equal to the end of the range."); } err.emit(); - PatternKind::Wild + PatKind::Wild } } }, @@ -499,7 +519,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ), ); - PatternKind::Wild + PatKind::Wild }, }; @@ -508,9 +528,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { // constants somewhere. Have them on the range pattern. for ascription in &[lo_ascription, hi_ascription] { if let Some(ascription) = ascription { - kind = PatternKind::AscribeUserType { + kind = PatKind::AscribeUserType { ascription: *ascription, - subpattern: Pattern { span: pat.span, ty, kind: Box::new(kind), }, + subpattern: Pat { span: pat.span, ty, kind: Box::new(kind), }, }; } } @@ -518,20 +538,20 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { kind } - PatKind::Path(ref qpath) => { + hir::PatKind::Path(ref qpath) => { return self.lower_path(qpath, pat.hir_id, pat.span); } - PatKind::Ref(ref subpattern, _) | - PatKind::Box(ref subpattern) => { - PatternKind::Deref { subpattern: self.lower_pattern(subpattern) } + hir::PatKind::Ref(ref subpattern, _) | + hir::PatKind::Box(ref subpattern) => { + PatKind::Deref { subpattern: self.lower_pattern(subpattern) } } - PatKind::Slice(ref prefix, ref slice, ref suffix) => { - match ty.sty { + hir::PatKind::Slice(ref prefix, ref slice, ref suffix) => { + match ty.kind { ty::Ref(_, ty, _) => - PatternKind::Deref { - subpattern: Pattern { + PatKind::Deref { + subpattern: Pat { ty, span: pat.span, kind: Box::new(self.slice_or_array_pattern( @@ -542,7 +562,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ty::Array(..) => self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix), ty::Error => { // Avoid ICE - return Pattern { span: pat.span, ty, kind: Box::new(PatternKind::Wild) }; + return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) }; } _ => span_bug!( @@ -552,32 +572,32 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } - PatKind::Tuple(ref subpatterns, ddpos) => { - match ty.sty { + hir::PatKind::Tuple(ref subpatterns, ddpos) => { + match ty.kind { ty::Tuple(ref tys) => { let subpatterns = subpatterns.iter() .enumerate_and_adjust(tys.len(), ddpos) - .map(|(i, subpattern)| FieldPattern { + .map(|(i, subpattern)| FieldPat { field: Field::new(i), pattern: self.lower_pattern(subpattern) }) .collect(); - PatternKind::Leaf { subpatterns } + PatKind::Leaf { subpatterns } } ty::Error => { // Avoid ICE (#50577) - return Pattern { span: pat.span, ty, kind: Box::new(PatternKind::Wild) }; + return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) }; } _ => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", ty), } } - PatKind::Binding(_, id, ident, ref sub) => { + hir::PatKind::Binding(_, id, ident, ref sub) => { let var_ty = self.tables.node_type(pat.hir_id); - if let ty::Error = var_ty.sty { + if let ty::Error = var_ty.kind { // Avoid ICE - return Pattern { span: pat.span, ty, kind: Box::new(PatternKind::Wild) }; + return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) }; }; let bm = *self.tables.pat_binding_modes().get(pat.hir_id) .expect("missing binding mode"); @@ -597,14 +617,14 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { // A ref x pattern is the same node used for x, and as such it has // x's type, which is &T, where we want T (the type being matched). if let ty::BindByReference(_) = bm { - if let ty::Ref(_, rty, _) = ty.sty { + if let ty::Ref(_, rty, _) = ty.kind { ty = rty; } else { bug!("`ref {}` has wrong type {}", ident, ty); } } - PatternKind::Binding { + PatKind::Binding { mutability, mode, name: ident.name, @@ -614,12 +634,12 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } - PatKind::TupleStruct(ref qpath, ref subpatterns, ddpos) => { + hir::PatKind::TupleStruct(ref qpath, ref subpatterns, ddpos) => { let res = self.tables.qpath_res(qpath, pat.hir_id); - let adt_def = match ty.sty { + let adt_def = match ty.kind { ty::Adt(adt_def, _) => adt_def, ty::Error => { // Avoid ICE (#50585) - return Pattern { span: pat.span, ty, kind: Box::new(PatternKind::Wild) }; + return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) }; } _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT {:?}", @@ -630,7 +650,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let subpatterns = subpatterns.iter() .enumerate_and_adjust(variant_def.fields.len(), ddpos) - .map(|(i, field)| FieldPattern { + .map(|(i, field)| FieldPat { field: Field::new(i), pattern: self.lower_pattern(field), }) @@ -639,45 +659,51 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns) } - PatKind::Struct(ref qpath, ref fields, _) => { + hir::PatKind::Struct(ref qpath, ref fields, _) => { let res = self.tables.qpath_res(qpath, pat.hir_id); let subpatterns = fields.iter() .map(|field| { - FieldPattern { - field: Field::new(self.tcx.field_index(field.node.hir_id, + FieldPat { + field: Field::new(self.tcx.field_index(field.hir_id, self.tables)), - pattern: self.lower_pattern(&field.node.pat), + pattern: self.lower_pattern(&field.pat), } }) .collect(); self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns) } + + hir::PatKind::Or(ref pats) => { + PatKind::Or { + pats: pats.iter().map(|p| self.lower_pattern(p)).collect(), + } + } }; - Pattern { + Pat { span: pat.span, ty, kind: Box::new(kind), } } - fn lower_patterns(&mut self, pats: &'tcx [P]) -> Vec> { + fn lower_patterns(&mut self, pats: &'tcx [P]) -> Vec> { pats.iter().map(|p| self.lower_pattern(p)).collect() } - fn lower_opt_pattern(&mut self, pat: &'tcx Option>) -> Option> + fn lower_opt_pattern(&mut self, pat: &'tcx Option>) -> Option> { pat.as_ref().map(|p| self.lower_pattern(p)) } fn flatten_nested_slice_patterns( &mut self, - prefix: Vec>, - slice: Option>, - suffix: Vec>) - -> (Vec>, Option>, Vec>) + prefix: Vec>, + slice: Option>, + suffix: Vec>) + -> (Vec>, Option>, Vec>) { let orig_slice = match slice { Some(orig_slice) => orig_slice, @@ -689,8 +715,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { // dance because of intentional borrow-checker stupidity. let kind = *orig_slice.kind; match kind { - PatternKind::Slice { prefix, slice, mut suffix } | - PatternKind::Array { prefix, slice, mut suffix } => { + PatKind::Slice { prefix, slice, mut suffix } | + PatKind::Array { prefix, slice, mut suffix } => { let mut orig_prefix = orig_prefix; orig_prefix.extend(prefix); @@ -699,7 +725,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { (orig_prefix, slice, suffix) } _ => { - (orig_prefix, Some(Pattern { + (orig_prefix, Some(Pat { kind: box kind, ..orig_slice }), orig_suffix) } @@ -713,7 +739,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { prefix: &'tcx [P], slice: &'tcx Option>, suffix: &'tcx [P]) - -> PatternKind<'tcx> + -> PatKind<'tcx> { let prefix = self.lower_patterns(prefix); let slice = self.lower_opt_pattern(slice); @@ -721,17 +747,17 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let (prefix, slice, suffix) = self.flatten_nested_slice_patterns(prefix, slice, suffix); - match ty.sty { + match ty.kind { ty::Slice(..) => { // matching a slice or fixed-length array - PatternKind::Slice { prefix: prefix, slice: slice, suffix: suffix } + PatKind::Slice { prefix: prefix, slice: slice, suffix: suffix } } ty::Array(_, len) => { // fixed-length array let len = len.eval_usize(self.tcx, self.param_env); assert!(len >= prefix.len() as u64 + suffix.len() as u64); - PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix } + PatKind::Array { prefix: prefix, slice: slice, suffix: suffix } } _ => { @@ -746,8 +772,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { hir_id: hir::HirId, span: Span, ty: Ty<'tcx>, - subpatterns: Vec>, - ) -> PatternKind<'tcx> { + subpatterns: Vec>, + ) -> PatKind<'tcx> { let res = match res { Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => { let variant_id = self.tcx.parent(variant_ctor_id).unwrap(); @@ -761,22 +787,22 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let enum_id = self.tcx.parent(variant_id).unwrap(); let adt_def = self.tcx.adt_def(enum_id); if adt_def.is_enum() { - let substs = match ty.sty { + let substs = match ty.kind { ty::Adt(_, substs) | ty::FnDef(_, substs) => substs, ty::Error => { // Avoid ICE (#50585) - return PatternKind::Wild; + return PatKind::Wild; } _ => bug!("inappropriate type for def: {:?}", ty), }; - PatternKind::Variant { + PatKind::Variant { adt_def, substs, variant_index: adt_def.variant_index_with_id(variant_id), subpatterns, } } else { - PatternKind::Leaf { subpatterns } + PatKind::Leaf { subpatterns } } } @@ -787,25 +813,25 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { | Res::Def(DefKind::AssocTy, _) | Res::SelfTy(..) | Res::SelfCtor(..) => { - PatternKind::Leaf { subpatterns } + PatKind::Leaf { subpatterns } } _ => { self.errors.push(PatternError::NonConstPath(span)); - PatternKind::Wild + PatKind::Wild } }; if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) { debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span); - kind = PatternKind::AscribeUserType { - subpattern: Pattern { + kind = PatKind::AscribeUserType { + subpattern: Pat { span, ty, kind: Box::new(kind), }, ascription: Ascription { - user_ty: PatternTypeProjection::from_user_type(user_ty), + user_ty: PatTyProj::from_user_type(user_ty), user_ty_span: span, variance: ty::Variance::Covariant, }, @@ -822,7 +848,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { qpath: &hir::QPath, id: hir::HirId, span: Span) - -> Pattern<'tcx> { + -> Pat<'tcx> { let ty = self.tables.node_type(id); let res = self.tables.qpath_res(qpath, id); let is_associated_const = match res { @@ -852,11 +878,11 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let user_provided_types = self.tables().user_provided_types(); return if let Some(u_ty) = user_provided_types.get(id) { - let user_ty = PatternTypeProjection::from_user_type(*u_ty); - Pattern { + let user_ty = PatTyProj::from_user_type(*u_ty); + Pat { span, kind: Box::new( - PatternKind::AscribeUserType { + PatKind::AscribeUserType { subpattern: pattern, ascription: Ascription { /// Note that use `Contravariant` here. See the @@ -878,7 +904,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { span, "could not evaluate constant pattern", ); - PatternKind::Wild + PatKind::Wild } } }, @@ -888,14 +914,14 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } else { PatternError::StaticInPattern(span) }); - PatternKind::Wild + PatKind::Wild }, } } _ => self.lower_variant_or_leaf(res, id, span, ty, vec![]), }; - Pattern { + Pat { span, ty, kind: Box::new(kind), @@ -906,8 +932,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { /// The special case for negation exists to allow things like `-128_i8` /// which would overflow if we tried to evaluate `128_i8` and then negate /// afterwards. - fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> { - match expr.node { + fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatKind<'tcx> { + match expr.kind { hir::ExprKind::Lit(ref lit) => { let ty = self.tables.expr_ty(expr); match lit_to_const(&lit.node, self.tcx, ty, false) { @@ -920,15 +946,15 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { }, Err(LitToConstError::UnparseableFloat) => { self.errors.push(PatternError::FloatBug); - PatternKind::Wild + PatKind::Wild }, - Err(LitToConstError::Reported) => PatternKind::Wild, + Err(LitToConstError::Reported) => PatKind::Wild, } }, hir::ExprKind::Path(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind, hir::ExprKind::Unary(hir::UnNeg, ref expr) => { let ty = self.tables.expr_ty(expr); - let lit = match expr.node { + let lit = match expr.kind { hir::ExprKind::Lit(ref lit) => lit, _ => span_bug!(expr.span, "not a literal: {:?}", expr), }; @@ -942,9 +968,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { }, Err(LitToConstError::UnparseableFloat) => { self.errors.push(PatternError::FloatBug); - PatternKind::Wild + PatKind::Wild }, - Err(LitToConstError::Reported) => PatternKind::Wild, + Err(LitToConstError::Reported) => PatKind::Wild, } } _ => span_bug!(expr.span, "not a literal: {:?}", expr), @@ -960,7 +986,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { cv: &'tcx ty::Const<'tcx>, id: hir::HirId, span: Span, - ) -> Pattern<'tcx> { + ) -> Pat<'tcx> { // This method is just a warpper handling a validity check; the heavy lifting is // performed by the recursive const_to_pat_inner method, which is not meant to be // invoked except by this method. @@ -1031,7 +1057,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { // value, so that we will not subsequently issue an irrelevant // lint for the same const value. saw_const_match_error: &mut bool, - ) -> Pattern<'tcx> { + ) -> Pat<'tcx> { let mut adt_subpattern = |i, variant_opt| { let field = Field::new(i); @@ -1043,7 +1069,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let mut adt_subpatterns = |n, variant_opt| { (0..n).map(|i| { let field = Field::new(i); - FieldPattern { + FieldPat { field, pattern: adt_subpattern(i, variant_opt), } @@ -1051,7 +1077,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { }; - let kind = match cv.ty.sty { + let kind = match cv.ty.kind { ty::Float(_) => { self.tcx.lint_hir( ::rustc::lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, @@ -1059,7 +1085,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { span, "floating-point types cannot be used in patterns", ); - PatternKind::Constant { + PatKind::Constant { value: cv, } } @@ -1067,7 +1093,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { // Matching on union fields is unsafe, we can't hide it in constants *saw_const_match_error = true; self.tcx.sess.span_err(span, "cannot use unions in constant patterns"); - PatternKind::Wild + PatKind::Wild } // keep old code until future-compat upgraded to errors. ty::Adt(adt_def, _) if !self.tcx.has_attr(adt_def.did, sym::structural_match) => { @@ -1080,13 +1106,13 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ); *saw_const_match_error = true; self.tcx.sess.span_err(span, &msg); - PatternKind::Wild + PatKind::Wild } // keep old code until future-compat upgraded to errors. - ty::Ref(_, ty::TyS { sty: ty::Adt(adt_def, _), .. }, _) + ty::Ref(_, ty::TyS { kind: ty::Adt(adt_def, _), .. }, _) if !self.tcx.has_attr(adt_def.did, sym::structural_match) => { // HACK(estebank): Side-step ICE #53708, but anything other than erroring here - // would be wrong. Returnging `PatternKind::Wild` is not technically correct. + // would be wrong. Returnging `PatKind::Wild` is not technically correct. let path = self.tcx.def_path_str(adt_def.did); let msg = format!( "to use a constant of type `{}` in a pattern, \ @@ -1096,7 +1122,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ); *saw_const_match_error = true; self.tcx.sess.span_err(span, &msg); - PatternKind::Wild + PatKind::Wild } ty::Adt(adt_def, substs) if adt_def.is_enum() => { let variant_index = const_variant_index(self.tcx, self.param_env, cv); @@ -1104,7 +1130,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { adt_def.variants[variant_index].fields.len(), Some(variant_index), ); - PatternKind::Variant { + PatKind::Variant { adt_def, substs, variant_index, @@ -1113,17 +1139,17 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } ty::Adt(adt_def, _) => { let struct_var = adt_def.non_enum_variant(); - PatternKind::Leaf { + PatKind::Leaf { subpatterns: adt_subpatterns(struct_var.fields.len(), None), } } ty::Tuple(fields) => { - PatternKind::Leaf { + PatKind::Leaf { subpatterns: adt_subpatterns(fields.len(), None), } } ty::Array(_, n) => { - PatternKind::Array { + PatKind::Array { prefix: (0..n.eval_usize(self.tcx, self.param_env)) .map(|i| adt_subpattern(i as usize, None)) .collect(), @@ -1132,13 +1158,13 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } _ => { - PatternKind::Constant { + PatKind::Constant { value: cv, } } }; - Pattern { + Pat { span, ty: cv.ty, kind: Box::new(kind), @@ -1198,12 +1224,18 @@ fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>, fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { debug!("Search visiting ty: {:?}", ty); - let (adt_def, substs) = match ty.sty { + let (adt_def, substs) = match ty.kind { ty::Adt(adt_def, substs) => (adt_def, substs), ty::RawPtr(..) => { // `#[structural_match]` ignores substructure of // `*const _`/`*mut _`, so skip super_visit_with - + // + // (But still tell caller to continue search.) + return false; + } + ty::FnDef(..) | ty::FnPtr(..) => { + // types of formals and return in `fn(_) -> _` are also irrelevant + // // (But still tell caller to continue search.) return false; } @@ -1261,7 +1293,7 @@ fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>, } } -impl UserAnnotatedTyHelpers<'tcx> for PatternContext<'_, 'tcx> { +impl UserAnnotatedTyHelpers<'tcx> for PatCtxt<'_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -1281,11 +1313,11 @@ pub trait PatternFoldable<'tcx> : Sized { } pub trait PatternFolder<'tcx> : Sized { - fn fold_pattern(&mut self, pattern: &Pattern<'tcx>) -> Pattern<'tcx> { + fn fold_pattern(&mut self, pattern: &Pat<'tcx>) -> Pat<'tcx> { pattern.super_fold_with(self) } - fn fold_pattern_kind(&mut self, kind: &PatternKind<'tcx>) -> PatternKind<'tcx> { + fn fold_pattern_kind(&mut self, kind: &PatKind<'tcx>) -> PatKind<'tcx> { kind.super_fold_with(self) } } @@ -1325,26 +1357,26 @@ macro_rules! CloneImpls { CloneImpls!{ <'tcx> Span, Field, Mutability, ast::Name, hir::HirId, usize, ty::Const<'tcx>, Region<'tcx>, Ty<'tcx>, BindingMode, &'tcx AdtDef, - SubstsRef<'tcx>, &'tcx Kind<'tcx>, UserType<'tcx>, - UserTypeProjection, PatternTypeProjection<'tcx> + SubstsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>, + UserTypeProjection, PatTyProj<'tcx> } -impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> { +impl<'tcx> PatternFoldable<'tcx> for FieldPat<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { - FieldPattern { + FieldPat { field: self.field.fold_with(folder), pattern: self.pattern.fold_with(folder) } } } -impl<'tcx> PatternFoldable<'tcx> for Pattern<'tcx> { +impl<'tcx> PatternFoldable<'tcx> for Pat<'tcx> { fn fold_with>(&self, folder: &mut F) -> Self { folder.fold_pattern(self) } fn super_fold_with>(&self, folder: &mut F) -> Self { - Pattern { + Pat { ty: self.ty.fold_with(folder), span: self.span.fold_with(folder), kind: self.kind.fold_with(folder) @@ -1352,22 +1384,22 @@ impl<'tcx> PatternFoldable<'tcx> for Pattern<'tcx> { } } -impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { +impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> { fn fold_with>(&self, folder: &mut F) -> Self { folder.fold_pattern_kind(self) } fn super_fold_with>(&self, folder: &mut F) -> Self { match *self { - PatternKind::Wild => PatternKind::Wild, - PatternKind::AscribeUserType { + PatKind::Wild => PatKind::Wild, + PatKind::AscribeUserType { ref subpattern, ascription: Ascription { variance, ref user_ty, user_ty_span, }, - } => PatternKind::AscribeUserType { + } => PatKind::AscribeUserType { subpattern: subpattern.fold_with(folder), ascription: Ascription { user_ty: user_ty.fold_with(folder), @@ -1375,14 +1407,14 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { user_ty_span, }, }, - PatternKind::Binding { + PatKind::Binding { mutability, name, mode, var, ty, ref subpattern, - } => PatternKind::Binding { + } => PatKind::Binding { mutability: mutability.fold_with(folder), name: name.fold_with(folder), mode: mode.fold_with(folder), @@ -1390,61 +1422,52 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { ty: ty.fold_with(folder), subpattern: subpattern.fold_with(folder), }, - PatternKind::Variant { + PatKind::Variant { adt_def, substs, variant_index, ref subpatterns, - } => PatternKind::Variant { + } => PatKind::Variant { adt_def: adt_def.fold_with(folder), substs: substs.fold_with(folder), variant_index, subpatterns: subpatterns.fold_with(folder) }, - PatternKind::Leaf { + PatKind::Leaf { ref subpatterns, - } => PatternKind::Leaf { + } => PatKind::Leaf { subpatterns: subpatterns.fold_with(folder), }, - PatternKind::Deref { + PatKind::Deref { ref subpattern, - } => PatternKind::Deref { + } => PatKind::Deref { subpattern: subpattern.fold_with(folder), }, - PatternKind::Constant { + PatKind::Constant { value - } => PatternKind::Constant { + } => PatKind::Constant { value, }, - PatternKind::Range(PatternRange { - lo, - hi, - ty, - end, - }) => PatternKind::Range(PatternRange { - lo, - hi, - ty: ty.fold_with(folder), - end, - }), - PatternKind::Slice { + PatKind::Range(range) => PatKind::Range(range), + PatKind::Slice { ref prefix, ref slice, ref suffix, - } => PatternKind::Slice { + } => PatKind::Slice { prefix: prefix.fold_with(folder), slice: slice.fold_with(folder), suffix: suffix.fold_with(folder) }, - PatternKind::Array { + PatKind::Array { ref prefix, ref slice, ref suffix - } => PatternKind::Array { + } => PatKind::Array { prefix: prefix.fold_with(folder), slice: slice.fold_with(folder), suffix: suffix.fold_with(folder) }, + PatKind::Or { ref pats } => PatKind::Or { pats: pats.fold_with(folder) }, } } } @@ -1478,7 +1501,7 @@ pub fn compare_const_vals<'tcx>( if let (Some(a), Some(b)) = (a_bits, b_bits) { use ::rustc_apfloat::Float; - return match ty.sty { + return match ty.kind { ty::Float(ast::FloatTy::F32) => { let l = ::rustc_apfloat::ieee::Single::from_bits(a); let r = ::rustc_apfloat::ieee::Single::from_bits(b); @@ -1501,29 +1524,12 @@ pub fn compare_const_vals<'tcx>( } } - if let ty::Str = ty.sty { + if let ty::Str = ty.kind { match (a.val, b.val) { - ( - ConstValue::Slice { data: alloc_a, start: offset_a, end: end_a }, - ConstValue::Slice { data: alloc_b, start: offset_b, end: end_b }, - ) => { - let len_a = end_a - offset_a; - let len_b = end_b - offset_b; - let a = alloc_a.get_bytes( - &tcx, - // invent a pointer, only the offset is relevant anyway - Pointer::new(AllocId(0), Size::from_bytes(offset_a as u64)), - Size::from_bytes(len_a as u64), - ); - let b = alloc_b.get_bytes( - &tcx, - // invent a pointer, only the offset is relevant anyway - Pointer::new(AllocId(0), Size::from_bytes(offset_b as u64)), - Size::from_bytes(len_b as u64), - ); - if let (Ok(a), Ok(b)) = (a, b) { - return from_bool(a == b); - } + (ConstValue::Slice { .. }, ConstValue::Slice { .. }) => { + let a_bytes = get_slice_bytes(&tcx, a.val); + let b_bytes = get_slice_bytes(&tcx, b.val); + return from_bool(a_bytes == b_bytes); } _ => (), } diff --git a/src/librustc_mir/hair/util.rs b/src/librustc_mir/hair/util.rs index 4e014855df5e0..d63541f7a3f56 100644 --- a/src/librustc_mir/hair/util.rs +++ b/src/librustc_mir/hair/util.rs @@ -17,7 +17,7 @@ crate trait UserAnnotatedTyHelpers<'tcx> { let mut user_ty = *user_provided_types.get(hir_id)?; debug!("user_subts_applied_to_ty_of_hir_id: user_ty={:?}", user_ty); let ty = self.tables().node_type(hir_id); - match ty.sty { + match ty.kind { ty::Adt(adt_def, ..) => { if let UserType::TypeOf(ref mut did, _) = &mut user_ty.value { *did = adt_def.did; diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 26cfbfe53a35c..9ab347957f97a 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -1,4 +1,4 @@ -use rustc::ty::{self, Ty, TypeAndMut}; +use rustc::ty::{self, Ty, TypeAndMut, TypeFoldable}; use rustc::ty::layout::{self, TyLayout, Size}; use rustc::ty::adjustment::{PointerCast}; use syntax::ast::FloatTy; @@ -34,17 +34,24 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Pointer(PointerCast::ReifyFnPointer) => { // The src operand does not matter, just its type - match src.layout.ty.sty { + match src.layout.ty.kind { ty::FnDef(def_id, substs) => { + // All reifications must be monomorphic, bail out otherwise. + if src.layout.ty.needs_subst() { + throw_inval!(TooGeneric); + } + if self.tcx.has_attr(def_id, sym::rustc_args_required_const) { bug!("reifying a fn ptr that requires const arguments"); } - let instance = ty::Instance::resolve( + + let instance = ty::Instance::resolve_for_fn_ptr( *self.tcx, self.param_env, def_id, substs, ).ok_or_else(|| err_inval!(TooGeneric))?; + let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?; } @@ -54,7 +61,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Pointer(PointerCast::UnsafeFnPointer) => { let src = self.read_immediate(src)?; - match dest.layout.ty.sty { + match dest.layout.ty.kind { ty::FnPtr(_) => { // No change to value self.write_immediate(*src, dest)?; @@ -65,9 +72,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Pointer(PointerCast::ClosureFnPointer(_)) => { // The src operand does not matter, just its type - match src.layout.ty.sty { + match src.layout.ty.kind { ty::Closure(def_id, substs) => { - let substs = self.subst_and_normalize_erasing_regions(substs)?; + // All reifications must be monomorphic, bail out otherwise. + if src.layout.ty.needs_subst() { + throw_inval!(TooGeneric); + } + let instance = ty::Instance::resolve_closure( *self.tcx, def_id, @@ -93,7 +104,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { use rustc::ty::TyKind::*; trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, dest_layout.ty); - match src.layout.ty.sty { + match src.layout.ty.kind { // Floating point Float(FloatTy::F32) => return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, dest_layout.ty)?.into()), @@ -172,7 +183,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; trace!("cast_from_int: {}, {}, {}", v, src_layout.ty, dest_layout.ty); use rustc::ty::TyKind::*; - match dest_layout.ty.sty { + match dest_layout.ty.kind { Int(_) | Uint(_) | RawPtr(_) => { let v = self.truncate(v, dest_layout); Ok(Scalar::from_uint(v, dest_layout.size)) @@ -210,7 +221,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { where F: Float + Into> + FloatConvert + FloatConvert { use rustc::ty::TyKind::*; - match dest_ty.sty { + match dest_ty.kind { // float -> uint Uint(t) => { let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize); @@ -240,14 +251,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { src: OpTy<'tcx, M::PointerTag>, dest: PlaceTy<'tcx, M::PointerTag>, // The pointee types - sty: Ty<'tcx>, - dty: Ty<'tcx>, + source_ty: Ty<'tcx>, + dest_ty: Ty<'tcx>, ) -> InterpResult<'tcx> { // A -> A conversion let (src_pointee_ty, dest_pointee_ty) = - self.tcx.struct_lockstep_tails_erasing_lifetimes(sty, dty, self.param_env); + self.tcx.struct_lockstep_tails_erasing_lifetimes(source_ty, dest_ty, self.param_env); - match (&src_pointee_ty.sty, &dest_pointee_ty.sty) { + match (&src_pointee_ty.kind, &dest_pointee_ty.kind) { (&ty::Array(_, length), &ty::Slice(_)) => { let ptr = self.read_immediate(src)?.to_scalar_ptr()?; // u64 cast is from usize to u64, which is always good @@ -283,7 +294,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { dest: PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { trace!("Unsizing {:?} into {:?}", src, dest); - match (&src.layout.ty.sty, &dest.layout.ty.sty) { + match (&src.layout.ty.kind, &dest.layout.ty.kind) { (&ty::Ref(_, s, _), &ty::Ref(_, d, _)) | (&ty::Ref(_, s, _), &ty::RawPtr(TypeAndMut { ty: d, .. })) | (&ty::RawPtr(TypeAndMut { ty: s, .. }), diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 1f23d8c017ccd..e1c45132103b4 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -9,12 +9,11 @@ use rustc::mir; use rustc::ty::layout::{ self, Size, Align, HasDataLayout, LayoutOf, TyLayout }; -use rustc::ty::subst::{Subst, SubstsRef}; +use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::query::TyCtxtAt; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::vec::IndexVec; use rustc::mir::interpret::{ - ErrorHandled, GlobalId, Scalar, Pointer, FrameInfo, AllocId, InterpResult, truncate, sign_extend, }; @@ -291,44 +290,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty.is_freeze(*self.tcx, self.param_env, DUMMY_SP) } - pub(super) fn subst_and_normalize_erasing_regions>( - &self, - substs: T, - ) -> InterpResult<'tcx, T> { - match self.stack.last() { - Some(frame) => Ok(self.tcx.subst_and_normalize_erasing_regions( - frame.instance.substs, - self.param_env, - &substs, - )), - None => if substs.needs_subst() { - throw_inval!(TooGeneric) - } else { - Ok(substs) - }, - } - } - - pub(super) fn resolve( - &self, - def_id: DefId, - substs: SubstsRef<'tcx> - ) -> InterpResult<'tcx, ty::Instance<'tcx>> { - trace!("resolve: {:?}, {:#?}", def_id, substs); - trace!("param_env: {:#?}", self.param_env); - let substs = self.subst_and_normalize_erasing_regions(substs)?; - trace!("substs: {:#?}", substs); - ty::Instance::resolve( - *self.tcx, - self.param_env, - def_id, - substs, - ).ok_or_else(|| err_inval!(TooGeneric).into()) - } - pub fn load_mir( &self, instance: ty::InstanceDef<'tcx>, + promoted: Option, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { // do not continue if typeck errors occurred (can only occur in local crate) let did = instance.def_id(); @@ -338,7 +303,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { { throw_inval!(TypeckError) } - trace!("load mir {:?}", instance); + trace!("load mir(instance={:?}, promoted={:?})", instance, promoted); + if let Some(promoted) = promoted { + return Ok(&self.tcx.promoted_mir(did)[promoted]); + } match instance { ty::InstanceDef::Item(def_id) => if self.tcx.is_mir_available(did) { Ok(self.tcx.optimized_mir(did)) @@ -349,34 +317,34 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - pub(super) fn monomorphize + Subst<'tcx>>( + /// Call this on things you got out of the MIR (so it is as generic as the current + /// stack frame), to bring it into the proper environment for this interpreter. + pub(super) fn subst_from_frame_and_normalize_erasing_regions>( &self, - t: T, - ) -> InterpResult<'tcx, T> { - match self.stack.last() { - Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)?), - None => if t.needs_subst() { - throw_inval!(TooGeneric) - } else { - Ok(t) - }, - } + value: T, + ) -> T { + self.tcx.subst_and_normalize_erasing_regions( + self.frame().instance.substs, + self.param_env, + &value, + ) } - fn monomorphize_with_substs + Subst<'tcx>>( + /// The `substs` are assumed to already be in our interpreter "universe" (param_env). + pub(super) fn resolve( &self, - t: T, + def_id: DefId, substs: SubstsRef<'tcx> - ) -> InterpResult<'tcx, T> { - // miri doesn't care about lifetimes, and will choke on some crazy ones - // let's simply get rid of them - let substituted = t.subst(*self.tcx, substs); - - if substituted.needs_subst() { - throw_inval!(TooGeneric) - } - - Ok(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted)) + ) -> InterpResult<'tcx, ty::Instance<'tcx>> { + trace!("resolve: {:?}, {:#?}", def_id, substs); + trace!("param_env: {:#?}", self.param_env); + trace!("substs: {:#?}", substs); + ty::Instance::resolve( + *self.tcx, + self.param_env, + def_id, + substs, + ).ok_or_else(|| err_inval!(TooGeneric).into()) } pub fn layout_of_local( @@ -385,15 +353,23 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { local: mir::Local, layout: Option>, ) -> InterpResult<'tcx, TyLayout<'tcx>> { - match frame.locals[local].layout.get() { + // `const_prop` runs into this with an invalid (empty) frame, so we + // have to support that case (mostly by skipping all caching). + match frame.locals.get(local).and_then(|state| state.layout.get()) { None => { let layout = crate::interpret::operand::from_known_layout(layout, || { let local_ty = frame.body.local_decls[local].ty; - let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs)?; + let local_ty = self.tcx.subst_and_normalize_erasing_regions( + frame.instance.substs, + self.param_env, + &local_ty, + ); self.layout_of(local_ty) })?; - // Layouts of locals are requested a lot, so we cache them. - frame.locals[local].layout.set(Some(layout)); + if let Some(state) = frame.locals.get(local) { + // Layouts of locals are requested a lot, so we cache them. + state.layout.set(Some(layout)); + } Ok(layout) } Some(layout) => Ok(layout), @@ -411,7 +387,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if !layout.is_unsized() { return Ok(Some((layout.size, layout.align.abi))); } - match layout.ty.sty { + match layout.ty.kind { ty::Adt(..) | ty::Tuple(..) => { // First get the size of all statically known fields. // Don't use type_of::sizing_type_of because that expects t to be sized, @@ -465,27 +441,30 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Issue #27023: must add any necessary padding to `size` // (to make it a multiple of `align`) before returning it. - // - // Namely, the returned size should be, in C notation: - // - // `size + ((size & (align-1)) ? align : 0)` - // - // emulated via the semi-standard fast bit trick: - // - // `(size + (align-1)) & -align` - - Ok(Some((size.align_to(align), align))) + let size = size.align_to(align); + + // Check if this brought us over the size limit. + if size.bytes() >= self.tcx.data_layout().obj_size_bound() { + throw_ub_format!("wide pointer metadata contains invalid information: \ + total size is bigger than largest supported object"); + } + Ok(Some((size, align))) } ty::Dynamic(..) => { let vtable = metadata.expect("dyn trait fat ptr must have vtable"); - // the second entry in the vtable is the dynamic size of the object. + // Read size and align from vtable (already checks size). Ok(Some(self.read_size_and_align_from_vtable(vtable)?)) } ty::Slice(_) | ty::Str => { let len = metadata.expect("slice fat ptr must have vtable").to_usize(self)?; let elem = layout.field(self, 0)?; - Ok(Some((elem.size * len, elem.align.abi))) + + // Make sure the slice is not too big. + let size = elem.size.checked_mul(len, &*self.tcx) + .ok_or_else(|| err_ub_format!("invalid slice: \ + total size is bigger than largest supported object"))?; + Ok(Some((size, elem.align.abi))) } ty::Foreign(_) => { @@ -692,14 +671,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Our result will later be validated anyway, and there seems no good reason // to have to fail early here. This is also more consistent with // `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles. - let val = self.tcx.const_eval_raw(param_env.and(gid)).map_err(|err| { - match err { - ErrorHandled::Reported => - err_inval!(ReferencedConstant), - ErrorHandled::TooGeneric => - err_inval!(TooGeneric), - } - })?; + let val = self.tcx.const_eval_raw(param_env.and(gid))?; self.raw_const_to_mplace(val) } diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index 1074ab941a761..ec06b6298e112 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -3,7 +3,7 @@ //! After a const evaluation has computed a value, before we destroy the const evaluator's session //! memory, we need to extract all memory allocations to the global memory pool so they stay around. -use rustc::ty::{Ty, TyCtxt, ParamEnv, self}; +use rustc::ty::{Ty, self}; use rustc::mir::interpret::{InterpResult, ErrorHandled}; use rustc::hir; use rustc::hir::def_id::DefId; @@ -11,32 +11,29 @@ use super::validity::RefTracking; use rustc_data_structures::fx::FxHashSet; use syntax::ast::Mutability; -use syntax_pos::Span; use super::{ - ValueVisitor, MemoryKind, Pointer, AllocId, MPlaceTy, Scalar, + ValueVisitor, MemoryKind, AllocId, MPlaceTy, Scalar, }; use crate::const_eval::{CompileTimeInterpreter, CompileTimeEvalContext}; struct InternVisitor<'rt, 'mir, 'tcx> { - /// previously encountered safe references - ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>, + /// The ectx from which we intern. ecx: &'rt mut CompileTimeEvalContext<'mir, 'tcx>, - param_env: ParamEnv<'tcx>, + /// Previously encountered safe references. + ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>, + /// A list of all encountered allocations. After type-based interning, we traverse this list to + /// also intern allocations that are only referenced by a raw pointer or inside a union. + leftover_allocations: &'rt mut FxHashSet, /// The root node of the value that we're looking at. This field is never mutated and only used /// for sanity assertions that will ICE when `const_qualif` screws up. mode: InternMode, /// This field stores the mutability of the value *currently* being checked. - /// It is set to mutable when an `UnsafeCell` is encountered - /// When recursing across a reference, we don't recurse but store the - /// value to be checked in `ref_tracking` together with the mutability at which we are checking - /// the value. - /// When encountering an immutable reference, we treat everything as immutable that is behind - /// it. + /// When encountering a mutable reference, we determine the pointee mutability + /// taking into account the mutability of the context: `& &mut i32` is entirely immutable, + /// despite the nested mutable reference! + /// The field gets updated when an `UnsafeCell` is encountered. mutability: Mutability, - /// A list of all encountered relocations. After type-based interning, we traverse this list to - /// also intern allocations that are only referenced by a raw pointer or inside a union. - leftover_relocations: &'rt mut FxHashSet, } #[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)] @@ -45,9 +42,10 @@ enum InternMode { /// `static`. In a `static mut` we start out as mutable and thus can also contain further `&mut` /// that will actually be treated as mutable. Static, - /// UnsafeCell is OK in the value of a constant, but not behind references in a constant + /// UnsafeCell is OK in the value of a constant: `const FOO = Cell::new(0)` creates + /// a new cell every time it is used. ConstBase, - /// `UnsafeCell` ICEs + /// `UnsafeCell` ICEs. Const, } @@ -55,48 +53,100 @@ enum InternMode { /// into the memory of other constants or statics struct IsStaticOrFn; +/// Intern an allocation without looking at its children. +/// `mode` is the mode of the environment where we found this pointer. +/// `mutablity` is the mutability of the place to be interned; even if that says +/// `immutable` things might become mutable if `ty` is not frozen. +/// `ty` can be `None` if there is no potential interior mutability +/// to account for (e.g. for vtables). +fn intern_shallow<'rt, 'mir, 'tcx>( + ecx: &'rt mut CompileTimeEvalContext<'mir, 'tcx>, + leftover_allocations: &'rt mut FxHashSet, + mode: InternMode, + alloc_id: AllocId, + mutability: Mutability, + ty: Option>, +) -> InterpResult<'tcx, Option> { + trace!( + "InternVisitor::intern {:?} with {:?}", + alloc_id, mutability, + ); + // remove allocation + let tcx = ecx.tcx; + let memory = ecx.memory_mut(); + let (kind, mut alloc) = match memory.alloc_map.remove(&alloc_id) { + Some(entry) => entry, + None => { + // Pointer not found in local memory map. It is either a pointer to the global + // map, or dangling. + // If the pointer is dangling (neither in local nor global memory), we leave it + // to validation to error. The `delay_span_bug` ensures that we don't forget such + // a check in validation. + if tcx.alloc_map.lock().get(alloc_id).is_none() { + tcx.sess.delay_span_bug(ecx.tcx.span, "tried to intern dangling pointer"); + } + // treat dangling pointers like other statics + // just to stop trying to recurse into them + return Ok(Some(IsStaticOrFn)); + }, + }; + // This match is just a canary for future changes to `MemoryKind`, which most likely need + // changes in this function. + match kind { + MemoryKind::Stack | MemoryKind::Vtable => {}, + } + // Set allocation mutability as appropriate. This is used by LLVM to put things into + // read-only memory, and also by Miri when evluating other constants/statics that + // access this one. + if mode == InternMode::Static { + // When `ty` is `None`, we assume no interior mutability. + let frozen = ty.map_or(true, |ty| ty.is_freeze( + ecx.tcx.tcx, + ecx.param_env, + ecx.tcx.span, + )); + // For statics, allocation mutability is the combination of the place mutability and + // the type mutability. + // The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere. + if mutability == Mutability::Immutable && frozen { + alloc.mutability = Mutability::Immutable; + } else { + // Just making sure we are not "upgrading" an immutable allocation to mutable. + assert_eq!(alloc.mutability, Mutability::Mutable); + } + } else { + // We *could* be non-frozen at `ConstBase`, for constants like `Cell::new(0)`. + // But we still intern that as immutable as the memory cannot be changed once the + // initial value was computed. + // Constants are never mutable. + assert_eq!( + mutability, Mutability::Immutable, + "Something went very wrong: mutability requested for a constant" + ); + alloc.mutability = Mutability::Immutable; + }; + // link the alloc id to the actual allocation + let alloc = tcx.intern_const_alloc(alloc); + leftover_allocations.extend(alloc.relocations().iter().map(|&(_, ((), reloc))| reloc)); + tcx.alloc_map.lock().set_alloc_id_memory(alloc_id, alloc); + Ok(None) +} + impl<'rt, 'mir, 'tcx> InternVisitor<'rt, 'mir, 'tcx> { - /// Intern an allocation without looking at its children fn intern_shallow( &mut self, - ptr: Pointer, + alloc_id: AllocId, mutability: Mutability, + ty: Option>, ) -> InterpResult<'tcx, Option> { - trace!( - "InternVisitor::intern {:?} with {:?}", - ptr, mutability, - ); - // remove allocation - let tcx = self.ecx.tcx; - let memory = self.ecx.memory_mut(); - let (kind, mut alloc) = match memory.alloc_map.remove(&ptr.alloc_id) { - Some(entry) => entry, - None => { - // if the pointer is dangling (neither in local nor global memory), we leave it - // to validation to error. The `delay_span_bug` ensures that we don't forget such - // a check in validation. - if tcx.alloc_map.lock().get(ptr.alloc_id).is_none() { - tcx.sess.delay_span_bug(self.ecx.tcx.span, "tried to intern dangling pointer"); - } - // treat dangling pointers like other statics - // just to stop trying to recurse into them - return Ok(Some(IsStaticOrFn)); - }, - }; - // This match is just a canary for future changes to `MemoryKind`, which most likely need - // changes in this function. - match kind { - MemoryKind::Stack | MemoryKind::Vtable => {}, - } - // Ensure llvm knows to only put this into immutable memory if the value is immutable either - // by being behind a reference or by being part of a static or const without interior - // mutability - alloc.mutability = mutability; - // link the alloc id to the actual allocation - let alloc = tcx.intern_const_alloc(alloc); - self.leftover_relocations.extend(alloc.relocations.iter().map(|&(_, ((), reloc))| reloc)); - tcx.alloc_map.lock().set_alloc_id_memory(ptr.alloc_id, alloc); - Ok(None) + intern_shallow( + self.ecx, + self.leftover_allocations, + self.mode, + alloc_id, + mutability, + ty, + ) } } @@ -119,14 +169,16 @@ for ) -> InterpResult<'tcx> { if let Some(def) = mplace.layout.ty.ty_adt_def() { if Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() { - // We are crossing over an `UnsafeCell`, we can mutate again + // We are crossing over an `UnsafeCell`, we can mutate again. This means that + // References we encounter inside here are interned as pointing to mutable + // allocations. let old = std::mem::replace(&mut self.mutability, Mutability::Mutable); assert_ne!( self.mode, InternMode::Const, "UnsafeCells are not allowed behind references in constants. This should have \ been prevented statically by const qualification. If this were allowed one \ - would be able to change a constant at one use site and other use sites may \ - arbitrarily decide to change, too.", + would be able to change a constant at one use site and other use sites could \ + observe that mutation.", ); let walked = self.walk_aggregate(mplace, fields); self.mutability = old; @@ -140,17 +192,18 @@ for // Handle Reference types, as these are the only relocations supported by const eval. // Raw pointers (and boxes) are handled by the `leftover_relocations` logic. let ty = mplace.layout.ty; - if let ty::Ref(_, referenced_ty, mutability) = ty.sty { + if let ty::Ref(_, referenced_ty, mutability) = ty.kind { let value = self.ecx.read_immediate(mplace.into())?; // Handle trait object vtables if let Ok(meta) = value.to_meta() { if let ty::Dynamic(..) = - self.ecx.tcx.struct_tail_erasing_lifetimes(referenced_ty, self.param_env).sty + self.ecx.tcx.struct_tail_erasing_lifetimes( + referenced_ty, self.ecx.param_env).kind { if let Ok(vtable) = meta.unwrap().to_ptr() { // explitly choose `Immutable` here, since vtables are immutable, even // if the reference of the fat pointer is mutable - self.intern_shallow(vtable, Mutability::Immutable)?; + self.intern_shallow(vtable.alloc_id, Mutability::Immutable, None)?; } } } @@ -175,9 +228,9 @@ for // we statically prevent `&mut T` via `const_qualif` and double check this here (InternMode::ConstBase, hir::Mutability::MutMutable) | (InternMode::Const, hir::Mutability::MutMutable) => { - match referenced_ty.sty { + match referenced_ty.kind { ty::Array(_, n) - if n.eval_usize(self.ecx.tcx.tcx, self.param_env) == 0 => {} + if n.eval_usize(self.ecx.tcx.tcx, self.ecx.param_env) == 0 => {} ty::Slice(_) if value.to_meta().unwrap().unwrap().to_usize(self.ecx)? == 0 => {} _ => bug!("const qualif failed to prevent mutable references"), @@ -195,21 +248,13 @@ for (Mutability::Mutable, hir::Mutability::MutMutable) => Mutability::Mutable, _ => Mutability::Immutable, }; - // Compute the mutability of the allocation - let intern_mutability = intern_mutability( - self.ecx.tcx.tcx, - self.param_env, - mplace.layout.ty, - self.ecx.tcx.span, - mutability, - ); // Recursing behind references changes the intern mode for constants in order to // cause assertions to trigger if we encounter any `UnsafeCell`s. let mode = match self.mode { InternMode::ConstBase => InternMode::Const, other => other, }; - match self.intern_shallow(ptr, intern_mutability)? { + match self.intern_shallow(ptr.alloc_id, mutability, Some(mplace.layout.ty))? { // No need to recurse, these are interned already and statics may have // cycles, so we don't want to recurse there Some(IsStaticOrFn) => {}, @@ -224,69 +269,45 @@ for } } -/// Figure out the mutability of the allocation. -/// Mutable if it has interior mutability *anywhere* in the type. -fn intern_mutability<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span, - mutability: Mutability, -) -> Mutability { - let has_interior_mutability = !ty.is_freeze(tcx, param_env, span); - if has_interior_mutability { - Mutability::Mutable - } else { - mutability - } -} - pub fn intern_const_alloc_recursive( ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, def_id: DefId, ret: MPlaceTy<'tcx>, - // FIXME(oli-obk): can we scrap the param env? I think we can, the final value of a const eval - // must always be monomorphic, right? - param_env: ty::ParamEnv<'tcx>, ) -> InterpResult<'tcx> { let tcx = ecx.tcx; // this `mutability` is the mutability of the place, ignoring the type - let (mutability, base_intern_mode) = match tcx.static_mutability(def_id) { + let (base_mutability, base_intern_mode) = match tcx.static_mutability(def_id) { Some(hir::Mutability::MutImmutable) => (Mutability::Immutable, InternMode::Static), - None => (Mutability::Immutable, InternMode::ConstBase), // `static mut` doesn't care about interior mutability, it's mutable anyway Some(hir::Mutability::MutMutable) => (Mutability::Mutable, InternMode::Static), + // consts, promoteds. FIXME: what about array lengths, array initializers? + None => (Mutability::Immutable, InternMode::ConstBase), }; - // type based interning - let mut ref_tracking = RefTracking::new((ret, mutability, base_intern_mode)); - let leftover_relocations = &mut FxHashSet::default(); - - // This mutability is the combination of the place mutability and the type mutability. If either - // is mutable, `alloc_mutability` is mutable. This exists because the entire allocation needs - // to be mutable if it contains an `UnsafeCell` anywhere. The other `mutability` exists so that - // the visitor does not treat everything outside the `UnsafeCell` as mutable. - let alloc_mutability = intern_mutability( - tcx.tcx, param_env, ret.layout.ty, tcx.span, mutability, - ); + // Type based interning. + // `ref_tracking` tracks typed references we have seen and still need to crawl for + // more typed information inside them. + // `leftover_allocations` collects *all* allocations we see, because some might not + // be available in a typed way. They get interned at the end. + let mut ref_tracking = RefTracking::new((ret, base_mutability, base_intern_mode)); + let leftover_allocations = &mut FxHashSet::default(); // start with the outermost allocation - InternVisitor { - ref_tracking: &mut ref_tracking, + intern_shallow( ecx, - mode: base_intern_mode, - leftover_relocations, - param_env, - mutability, - }.intern_shallow(ret.ptr.to_ptr()?, alloc_mutability)?; + leftover_allocations, + base_intern_mode, + ret.ptr.to_ptr()?.alloc_id, + base_mutability, + Some(ret.layout.ty) + )?; while let Some(((mplace, mutability, mode), _)) = ref_tracking.todo.pop() { let interned = InternVisitor { ref_tracking: &mut ref_tracking, ecx, mode, - leftover_relocations, - param_env, + leftover_allocations, mutability, }.visit_value(mplace); if let Err(error) = interned { @@ -296,11 +317,7 @@ pub fn intern_const_alloc_recursive( let err = crate::const_eval::error_to_const_error(&ecx, error); match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") { Ok(mut diag) => { - diag.note("The rules on what exactly is undefined behavior aren't clear, \ - so this check might be overzealous. Please open an issue on the rust \ - compiler repository if you believe it should not be considered \ - undefined behavior", - ); + diag.note(crate::const_eval::note_on_undefined_behavior_error()); diag.emit(); } Err(ErrorHandled::TooGeneric) | @@ -313,15 +330,23 @@ pub fn intern_const_alloc_recursive( // Intern the rest of the allocations as mutable. These might be inside unions, padding, raw // pointers, ... So we can't intern them according to their type rules - let mut todo: Vec<_> = leftover_relocations.iter().cloned().collect(); + let mut todo: Vec<_> = leftover_allocations.iter().cloned().collect(); while let Some(alloc_id) = todo.pop() { - if let Some((_, alloc)) = ecx.memory_mut().alloc_map.remove(&alloc_id) { - // We can't call the `intern` method here, as its logic is tailored to safe references. - // So we hand-roll the interning logic here again + if let Some((_, mut alloc)) = ecx.memory_mut().alloc_map.remove(&alloc_id) { + // We can't call the `intern_shallow` method here, as its logic is tailored to safe + // references and a `leftover_allocations` set (where we only have a todo-list here). + // So we hand-roll the interning logic here again. + if base_intern_mode != InternMode::Static { + // If it's not a static, it *must* be immutable. + // We cannot have mutable memory inside a constant. + // FIXME: ideally we would assert that they already are immutable, to double- + // check our static checks. + alloc.mutability = Mutability::Immutable; + } let alloc = tcx.intern_const_alloc(alloc); tcx.alloc_map.lock().set_alloc_id_memory(alloc_id, alloc); - for &(_, ((), reloc)) in alloc.relocations.iter() { - if leftover_relocations.insert(reloc) { + for &(_, ((), reloc)) in alloc.relocations().iter() { + if leftover_allocations.insert(reloc) { todo.push(reloc); } } diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 89c5be137a4e5..5fc23b4a69ec5 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -5,17 +5,18 @@ use syntax::symbol::Symbol; use rustc::ty; use rustc::ty::layout::{LayoutOf, Primitive, Size}; +use rustc::ty::subst::SubstsRef; +use rustc::hir::def_id::DefId; +use rustc::ty::TyCtxt; use rustc::mir::BinOp; -use rustc::mir::interpret::{InterpResult, Scalar}; +use rustc::mir::interpret::{InterpResult, Scalar, GlobalId, ConstValue}; use super::{ - Machine, PlaceTy, OpTy, InterpCx, Immediate, + Machine, PlaceTy, OpTy, InterpCx, }; mod type_name; -pub use type_name::*; - fn numeric_intrinsic<'tcx, Tag>( name: &str, bits: u128, @@ -37,6 +38,50 @@ fn numeric_intrinsic<'tcx, Tag>( Ok(Scalar::from_uint(bits_out, size)) } +/// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated +/// inside an `InterpCx` and instead have their value computed directly from rustc internal info. +crate fn eval_nullary_intrinsic<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + def_id: DefId, + substs: SubstsRef<'tcx>, +) -> InterpResult<'tcx, &'tcx ty::Const<'tcx>> { + let tp_ty = substs.type_at(0); + let name = &*tcx.item_name(def_id).as_str(); + Ok(match name { + "type_name" => { + let alloc = type_name::alloc_type_name(tcx, tp_ty); + tcx.mk_const(ty::Const { + val: ConstValue::Slice { + data: alloc, + start: 0, + end: alloc.len(), + }, + ty: tcx.mk_static_str(), + }) + }, + "needs_drop" => ty::Const::from_bool(tcx, tp_ty.needs_drop(tcx, param_env)), + "size_of" | + "min_align_of" | + "pref_align_of" => { + let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?; + let n = match name { + "pref_align_of" => layout.align.pref.bytes(), + "min_align_of" => layout.align.abi.bytes(), + "size_of" => layout.size.bytes(), + _ => bug!(), + }; + ty::Const::from_usize(tcx, n) + }, + "type_id" => ty::Const::from_bits( + tcx, + tcx.type_id_hash(tp_ty).into(), + param_env.and(tcx.types.u64), + ), + other => bug!("`{}` is not a zero arg intrinsic", other), + }) +} + impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Returns `true` if emulation happened. pub fn emulate_intrinsic( @@ -49,41 +94,19 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { - "min_align_of" => { - let elem_ty = substs.type_at(0); - let elem_align = self.layout_of(elem_ty)?.align.abi.bytes(); - let align_val = Scalar::from_uint(elem_align, dest.layout.size); - self.write_scalar(align_val, dest)?; - } - - "needs_drop" => { - let ty = substs.type_at(0); - let ty_needs_drop = ty.needs_drop(self.tcx.tcx, self.param_env); - let val = Scalar::from_bool(ty_needs_drop); - self.write_scalar(val, dest)?; - } - - "size_of" => { - let ty = substs.type_at(0); - let size = self.layout_of(ty)?.size.bytes() as u128; - let size_val = Scalar::from_uint(size, dest.layout.size); - self.write_scalar(size_val, dest)?; - } - - "type_id" => { - let ty = substs.type_at(0); - let type_id = self.tcx.type_id_hash(ty) as u128; - let id_val = Scalar::from_uint(type_id, dest.layout.size); - self.write_scalar(id_val, dest)?; - } - + "min_align_of" | + "pref_align_of" | + "needs_drop" | + "size_of" | + "type_id" | "type_name" => { - let alloc = alloc_type_name(self.tcx.tcx, substs.type_at(0)); - let name_id = self.tcx.alloc_map.lock().create_memory_alloc(alloc); - let id_ptr = self.memory.tag_static_base_pointer(name_id.into()); - let alloc_len = alloc.bytes.len() as u64; - let name_val = Immediate::new_slice(Scalar::Ptr(id_ptr), alloc_len, self); - self.write_immediate(name_val, dest)?; + let gid = GlobalId { + instance, + promoted: None, + }; + let val = self.tcx.const_eval(self.param_env.and(gid))?; + let val = self.eval_const_to_op(val, None)?; + self.copy_op(val, dest)?; } | "ctpop" @@ -95,7 +118,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | "bitreverse" => { let ty = substs.type_at(0); let layout_of = self.layout_of(ty)?; - let bits = self.read_scalar(args[0])?.to_bits(layout_of.size)?; + let val = self.read_scalar(args[0])?.not_undef()?; + let bits = self.force_bits(val, layout_of.size)?; let kind = match layout_of.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, _ => throw_unsup!(TypeNotPrimitive(ty)), @@ -110,18 +134,18 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; self.write_scalar(out_val, dest)?; } - | "overflowing_add" - | "overflowing_sub" - | "overflowing_mul" + | "wrapping_add" + | "wrapping_sub" + | "wrapping_mul" | "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => { let lhs = self.read_immediate(args[0])?; let rhs = self.read_immediate(args[1])?; let (bin_op, ignore_overflow) = match intrinsic_name { - "overflowing_add" => (BinOp::Add, true), - "overflowing_sub" => (BinOp::Sub, true), - "overflowing_mul" => (BinOp::Mul, true), + "wrapping_add" => (BinOp::Add, true), + "wrapping_sub" => (BinOp::Sub, true), + "wrapping_mul" => (BinOp::Mul, true), "add_with_overflow" => (BinOp::Add, false), "sub_with_overflow" => (BinOp::Sub, false), "mul_with_overflow" => (BinOp::Mul, false), @@ -137,7 +161,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let l = self.read_immediate(args[0])?; let r = self.read_immediate(args[1])?; let is_add = intrinsic_name == "saturating_add"; - let (val, overflowed) = self.binary_op(if is_add { + let (val, overflowed, _ty) = self.overflowing_binary_op(if is_add { BinOp::Add } else { BinOp::Sub @@ -149,7 +173,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // term since the sign of the second term can be inferred from this and // the fact that the operation has overflowed (if either is 0 no // overflow can occur) - let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?; + let first_term: u128 = self.force_bits(l.to_scalar()?, l.layout.size)?; let first_term_positive = first_term & (1 << (num_bits-1)) == 0; if first_term_positive { // Negative overflow not possible since the positive first term @@ -184,10 +208,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { "unchecked_shr" => BinOp::Shr, _ => bug!("Already checked for int ops") }; - let (val, overflowed) = self.binary_op(bin_op, l, r)?; + let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, l, r)?; if overflowed { let layout = self.layout_of(substs.type_at(0))?; - let r_val = r.to_scalar()?.to_bits(layout.size)?; + let r_val = self.force_bits(r.to_scalar()?, layout.size)?; throw_ub_format!("Overflowing shift by {} in `{}`", r_val, intrinsic_name); } self.write_scalar(val, dest)?; @@ -196,8 +220,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW)) // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW)) let layout = self.layout_of(substs.type_at(0))?; - let val_bits = self.read_scalar(args[0])?.to_bits(layout.size)?; - let raw_shift_bits = self.read_scalar(args[1])?.to_bits(layout.size)?; + let val = self.read_scalar(args[0])?.not_undef()?; + let val_bits = self.force_bits(val, layout.size)?; + let raw_shift = self.read_scalar(args[1])?.not_undef()?; + let raw_shift_bits = self.force_bits(raw_shift, layout.size)?; let width_bits = layout.size.bits() as u128; let shift_bits = raw_shift_bits % width_bits; let inv_shift_bits = (width_bits - shift_bits) % width_bits; @@ -213,7 +239,52 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { "transmute" => { self.copy_op_transmute(args[0], dest)?; } + "simd_insert" => { + let index = self.read_scalar(args[1])?.to_u32()? as u64; + let scalar = args[2]; + let input = args[0]; + let (len, e_ty) = self.read_vector_ty(input); + assert!( + index < len, + "Index `{}` must be in bounds of vector type `{}`: `[0, {})`", + index, e_ty, len + ); + assert_eq!( + input.layout, dest.layout, + "Return type `{}` must match vector type `{}`", + dest.layout.ty, input.layout.ty + ); + assert_eq!( + scalar.layout.ty, e_ty, + "Scalar type `{}` must match vector element type `{}`", + scalar.layout.ty, e_ty + ); + for i in 0..len { + let place = self.place_field(dest, i)?; + let value = if i == index { + scalar + } else { + self.operand_field(input, i)? + }; + self.copy_op(value, place)?; + } + } + "simd_extract" => { + let index = self.read_scalar(args[1])?.to_u32()? as _; + let (len, e_ty) = self.read_vector_ty(args[0]); + assert!( + index < len, + "index `{}` is out-of-bounds of vector type `{}` with length `{}`", + index, e_ty, len + ); + assert_eq!( + e_ty, dest.layout.ty, + "Return type `{}` must match vector element type `{}`", + dest.layout.ty, e_ty + ); + self.copy_op(self.operand_field(args[0], index)?, dest)?; + } _ => return Ok(false), } diff --git a/src/librustc_mir/interpret/intrinsics/type_name.rs b/src/librustc_mir/interpret/intrinsics/type_name.rs index f207cfc6b39cd..f9200f8c1c042 100644 --- a/src/librustc_mir/interpret/intrinsics/type_name.rs +++ b/src/librustc_mir/interpret/intrinsics/type_name.rs @@ -1,13 +1,13 @@ use rustc::ty::{ TyCtxt, Ty, - subst::{UnpackedKind, Kind}, + subst::{GenericArgKind, GenericArg}, print::{Printer, PrettyPrinter, Print}, self, }; use rustc::hir::map::{DefPathData, DisambiguatedDefPathData}; use rustc::hir::def_id::CrateNum; use std::fmt::Write; -use rustc::mir::interpret::{Allocation, ConstValue}; +use rustc::mir::interpret::Allocation; struct AbsolutePathPrinter<'tcx> { tcx: TyCtxt<'tcx>, @@ -32,7 +32,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { } fn print_type(mut self, ty: Ty<'tcx>) -> Result { - match ty.sty { + match ty.kind { // Types without identity. | ty::Bool | ty::Char @@ -67,9 +67,8 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { | ty::Opaque(def_id, substs) | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) | ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs }) - | ty::Closure(def_id, ty::ClosureSubsts { substs }) - | ty::Generator(def_id, ty::GeneratorSubsts { substs }, _) - => self.print_def_path(def_id, substs), + | ty::Closure(def_id, substs) + | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs), ty::Foreign(def_id) => self.print_def_path(def_id, &[]), ty::GeneratorWitness(_) => { @@ -156,12 +155,12 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { fn path_generic_args( mut self, print_prefix: impl FnOnce(Self) -> Result, - args: &[Kind<'tcx>], + args: &[GenericArg<'tcx>], ) -> Result { self = print_prefix(self)?; let args = args.iter().cloned().filter(|arg| { match arg.unpack() { - UnpackedKind::Lifetime(_) => false, + GenericArgKind::Lifetime(_) => false, _ => true, } }); @@ -213,22 +212,11 @@ impl Write for AbsolutePathPrinter<'_> { } } -/// Produces an absolute path representation of the given type. See also the documentation on -/// `std::any::type_name` -pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> { - let alloc = alloc_type_name(tcx, ty); - tcx.mk_const(ty::Const { - val: ConstValue::Slice { - data: alloc, - start: 0, - end: alloc.bytes.len(), - }, - ty: tcx.mk_static_str(), - }) -} - /// Directly returns an `Allocation` containing an absolute path representation of the given type. -pub(super) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Allocation { +crate fn alloc_type_name<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx> +) -> &'tcx Allocation { let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path; let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes()); tcx.intern_const_alloc(alloc) diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 33ffb1d320ec2..c30c59bbf10c8 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -7,11 +7,12 @@ use std::hash::Hash; use rustc::hir::def_id::DefId; use rustc::mir; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt}; use super::{ Allocation, AllocId, InterpResult, Scalar, AllocationExtra, InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory, + Frame, Operand, }; /// Whether this kind of memory is allowed to leak @@ -176,7 +177,7 @@ pub trait Machine<'mir, 'tcx>: Sized { bin_op: mir::BinOp, left: ImmTy<'tcx, Self::PointerTag>, right: ImmTy<'tcx, Self::PointerTag>, - ) -> InterpResult<'tcx, (Scalar, bool)>; + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; /// Heap allocations via the `box` keyword. fn box_alloc( @@ -184,6 +185,22 @@ pub trait Machine<'mir, 'tcx>: Sized { dest: PlaceTy<'tcx, Self::PointerTag>, ) -> InterpResult<'tcx>; + /// Called to read the specified `local` from the `frame`. + fn access_local( + _ecx: &InterpCx<'mir, 'tcx, Self>, + frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, + local: mir::Local, + ) -> InterpResult<'tcx, Operand> { + frame.locals[local].access() + } + + /// Called before a `StaticKind::Static` value is accessed. + fn before_access_static( + _allocation: &Allocation, + ) -> InterpResult<'tcx> { + Ok(()) + } + /// Called to initialize the "extra" state of an allocation and make the pointers /// it contains (in relocations) tagged. The way we construct allocations is /// to always first construct it without extra and then add the extra. diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index aef09df4537be..924474c53175c 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -210,7 +210,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { let new_ptr = self.allocate(new_size, new_align, kind); let old_size = match old_size_and_align { Some((size, _align)) => size, - None => Size::from_bytes(self.get(ptr.alloc_id)?.bytes.len() as u64), + None => self.get(ptr.alloc_id)?.size, }; self.copy( ptr, @@ -271,20 +271,20 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { )) } if let Some((size, align)) = old_size_and_align { - if size.bytes() != alloc.bytes.len() as u64 || align != alloc.align { - let bytes = Size::from_bytes(alloc.bytes.len() as u64); + if size != alloc.size || align != alloc.align { + let bytes = alloc.size; throw_unsup!(IncorrectAllocationInformation(size, bytes, align, alloc.align)) } } // Let the machine take some extra action - let size = Size::from_bytes(alloc.bytes.len() as u64); + let size = alloc.size; AllocationExtra::memory_deallocated(&mut alloc, ptr, size)?; // Don't forget to remember size and align of this now-dead allocation let old = self.dead_alloc_map.insert( ptr.alloc_id, - (Size::from_bytes(alloc.bytes.len() as u64), alloc.align) + (alloc.size, alloc.align) ); if old.is_some() { bug!("Nothing can be deallocated twice"); @@ -297,7 +297,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { /// and `align`. On success, returns `None` for zero-sized accesses (where /// nothing else is left to do) and a `Pointer` to use for the actual access otherwise. /// Crucially, if the input is a `Pointer`, we will test it for liveness - /// *even of* the size is 0. + /// *even if* the size is 0. /// /// Everyone accessing memory based on a `Scalar` should use this method to get the /// `Pointer` they need. And even if you already have a `Pointer`, call this method @@ -368,7 +368,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // It is sufficient to check this for the end pointer. The addition // checks for overflow. let end_ptr = ptr.offset(size, self)?; - end_ptr.check_in_alloc(allocation_size, CheckInAllocMsg::MemoryAccessTest)?; + end_ptr.check_inbounds_alloc(allocation_size, CheckInAllocMsg::MemoryAccessTest)?; // Test align. Check this last; if both bounds and alignment are violated // we want the error to be about the bounds. if let Some(align) = align { @@ -400,7 +400,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { ) -> bool { let (size, _align) = self.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead) .expect("alloc info with MaybeDead cannot fail"); - ptr.check_in_alloc(size, CheckInAllocMsg::NullPointerTest).is_err() + ptr.check_inbounds_alloc(size, CheckInAllocMsg::NullPointerTest).is_err() } } @@ -462,6 +462,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // Make sure we use the ID of the resolved memory, not the lazy one! let id = raw_const.alloc_id; let allocation = tcx.alloc_map.lock().unwrap_memory(id); + + M::before_access_static(allocation)?; Cow::Borrowed(allocation) } } @@ -555,7 +557,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // a) cause cycles in case `id` refers to a static // b) duplicate a static's allocation in miri if let Some((_, alloc)) = self.alloc_map.get(id) { - return Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)); + return Ok((alloc.size, alloc.align)); } // # Function pointers @@ -583,7 +585,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { Some(GlobalAlloc::Memory(alloc)) => // Need to duplicate the logic here, because the global allocations have // different associated types than the interpreter-local ones. - Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)), + Ok((alloc.size, alloc.align)), Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"), // The rest must be dead. @@ -645,17 +647,22 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { let prefix_len = msg.len(); let mut relocations = vec![]; - for i in 0..(alloc.bytes.len() as u64) { + for i in 0..alloc.size.bytes() { let i = Size::from_bytes(i); - if let Some(&(_, target_id)) = alloc.relocations.get(&i) { + if let Some(&(_, target_id)) = alloc.relocations().get(&i) { if allocs_seen.insert(target_id) { allocs_to_print.push_back(target_id); } relocations.push((i, target_id)); } - if alloc.undef_mask.is_range_defined(i, i + Size::from_bytes(1)).is_ok() { + if alloc.undef_mask().is_range_defined(i, i + Size::from_bytes(1)).is_ok() { // this `as usize` is fine, since `i` came from a `usize` - write!(msg, "{:02x} ", alloc.bytes[i.bytes() as usize]).unwrap(); + let i = i.bytes() as usize; + + // Checked definedness (and thus range) and relocations. This access also doesn't + // influence interpreter execution but is only for debugging. + let bytes = alloc.inspect_with_undef_and_ptr_outside_interpreter(i..i+1); + write!(msg, "{:02x} ", bytes[0]).unwrap(); } else { msg.push_str("__ "); } @@ -664,7 +671,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { trace!( "{}({} bytes, alignment {}){}", msg, - alloc.bytes.len(), + alloc.size.bytes(), alloc.align.bytes(), extra ); @@ -803,32 +810,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // since we don't want to keep any relocations at the target. // (`get_bytes_with_undef_and_ptr` below checks that there are no // relocations overlapping the edges; those would not be handled correctly). - let relocations = { - let relocations = self.get(src.alloc_id)?.relocations(self, src, size); - if relocations.is_empty() { - // nothing to copy, ignore even the `length` loop - Vec::new() - } else { - let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize)); - for i in 0..length { - new_relocations.extend( - relocations - .iter() - .map(|&(offset, reloc)| { - // compute offset for current repetition - let dest_offset = dest.offset + (i * size); - ( - // shift offsets from source allocation to destination allocation - offset + dest_offset - src.offset, - reloc, - ) - }) - ); - } - - new_relocations - } - }; + let relocations = self.get(src.alloc_id)? + .prepare_relocation_copy(self, src, size, dest, length); let tcx = self.tcx.tcx; @@ -875,7 +858,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // copy definedness to the destination self.copy_undef_mask(src, dest, size, length)?; // copy the relocations to the destination - self.get_mut(dest.alloc_id)?.relocations.insert_presorted(relocations); + self.get_mut(dest.alloc_id)?.mark_relocation_range(relocations); Ok(()) } @@ -894,65 +877,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // The bits have to be saved locally before writing to dest in case src and dest overlap. assert_eq!(size.bytes() as usize as u64, size.bytes()); - let undef_mask = &self.get(src.alloc_id)?.undef_mask; - - // Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`), - // a naive undef mask copying algorithm would repeatedly have to read the undef mask from - // the source and write it to the destination. Even if we optimized the memory accesses, - // we'd be doing all of this `repeat` times. - // Therefor we precompute a compressed version of the undef mask of the source value and - // then write it back `repeat` times without computing any more information from the source. - - // a precomputed cache for ranges of defined/undefined bits - // 0000010010001110 will become - // [5, 1, 2, 1, 3, 3, 1] - // where each element toggles the state - let mut ranges = smallvec::SmallVec::<[u64; 1]>::new(); - let first = undef_mask.get(src.offset); - let mut cur_len = 1; - let mut cur = first; - for i in 1..size.bytes() { - // FIXME: optimize to bitshift the current undef block's bits and read the top bit - if undef_mask.get(src.offset + Size::from_bytes(i)) == cur { - cur_len += 1; - } else { - ranges.push(cur_len); - cur_len = 1; - cur = !cur; - } - } + let src_alloc = self.get(src.alloc_id)?; + let compressed = src_alloc.compress_undef_range(src, size); // now fill in all the data let dest_allocation = self.get_mut(dest.alloc_id)?; - // an optimization where we can just overwrite an entire range of definedness bits if - // they are going to be uniformly `1` or `0`. - if ranges.is_empty() { - dest_allocation.undef_mask.set_range_inbounds( - dest.offset, - dest.offset + size * repeat, - first, - ); - return Ok(()) - } + dest_allocation.mark_compressed_undef_range(&compressed, dest, size, repeat); - // remember to fill in the trailing bits - ranges.push(cur_len); - - for mut j in 0..repeat { - j *= size.bytes(); - j += dest.offset.bytes(); - let mut cur = first; - for range in &ranges { - let old_j = j; - j += range; - dest_allocation.undef_mask.set_range_inbounds( - Size::from_bytes(old_j), - Size::from_bytes(j), - cur, - ); - cur = !cur; - } - } Ok(()) } diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index 45d24347e4efd..0c61be283dfd0 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -34,6 +34,6 @@ pub use self::visitor::{ValueVisitor, MutValueVisitor}; pub use self::validity::RefTracking; -pub(super) use self::intrinsics::type_name; - pub use self::intern::intern_const_alloc_recursive; + +crate use self::intrinsics::eval_nullary_intrinsic; diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index f778eb1734c4b..4bdd71f9602ac 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -1,11 +1,11 @@ //! Functions concerning immediate values and operands, and reading from operands. //! All high-level functions to read from memory work on operands as sources. -use std::convert::TryInto; +use std::convert::{TryInto, TryFrom}; use rustc::{mir, ty}; use rustc::ty::layout::{ - self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt, VariantIdx, + self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt, PrimitiveExt, VariantIdx, }; use rustc::mir::interpret::{ @@ -108,7 +108,7 @@ impl<'tcx, Tag> Immediate { // as input for binary and cast operations. #[derive(Copy, Clone, Debug)] pub struct ImmTy<'tcx, Tag=()> { - pub imm: Immediate, + pub(crate) imm: Immediate, pub layout: TyLayout<'tcx>, } @@ -155,7 +155,7 @@ impl Operand { #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct OpTy<'tcx, Tag=()> { - op: Operand, + op: Operand, // Keep this private, it helps enforce invariants pub layout: TyLayout<'tcx>, } @@ -187,13 +187,22 @@ impl<'tcx, Tag> From> for OpTy<'tcx, Tag> { } } -impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag> -{ +impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag> { #[inline] pub fn from_scalar(val: Scalar, layout: TyLayout<'tcx>) -> Self { ImmTy { imm: val.into(), layout } } + #[inline] + pub fn from_uint(i: impl Into, layout: TyLayout<'tcx>) -> Self { + Self::from_scalar(Scalar::from_uint(i, layout.size), layout) + } + + #[inline] + pub fn from_int(i: impl Into, layout: TyLayout<'tcx>) -> Self { + Self::from_scalar(Scalar::from_int(i, layout.size), layout) + } + #[inline] pub fn to_bits(self) -> InterpResult<'tcx, u128> { self.to_scalar()?.to_bits(self.layout.size) @@ -246,7 +255,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return Ok(None); } - let ptr = match self.check_mplace_access(mplace, None)? { + let ptr = match self.check_mplace_access(mplace, None) + .expect("places should be checked on creation") + { Some(ptr) => ptr, None => return Ok(Some(ImmTy { // zero-sized type imm: Scalar::zst().into(), @@ -324,6 +335,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } + /// Read vector length and element type + pub fn read_vector_ty( + &self, op: OpTy<'tcx, M::PointerTag> + ) -> (u64, &rustc::ty::TyS<'tcx>) { + if let layout::Abi::Vector { .. } = op.layout.abi { + (op.layout.ty.simd_size(*self.tcx) as _, op.layout.ty.simd_type(*self.tcx)) + } else { + bug!("Type `{}` is not a SIMD vector type", op.layout.ty) + } + } + /// Read a scalar from a place pub fn read_scalar( &self, @@ -436,7 +458,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Do not read from ZST, they might not be initialized Operand::Immediate(Scalar::zst().into()) } else { - frame.locals[local].access()? + M::access_local(&self, frame, local)? }; Ok(OpTy { op, layout }) } @@ -459,41 +481,40 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Evaluate a place with the goal of reading from it. This lets us sometimes // avoid allocations. - pub(super) fn eval_place_to_op( + pub fn eval_place_to_op( &self, - mir_place: &mir::Place<'tcx>, + place: &mir::Place<'tcx>, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { use rustc::mir::PlaceBase; - mir_place.iterate(|place_base, place_projection| { - let mut op = match place_base { - PlaceBase::Local(mir::RETURN_PLACE) => - throw_unsup!(ReadFromReturnPointer), - PlaceBase::Local(local) => { - // Do not use the layout passed in as argument if the base we are looking at - // here is not the entire place. - // FIXME use place_projection.is_empty() when is available - let layout = if mir_place.projection.is_none() { - layout - } else { - None - }; - - self.access_local(self.frame(), *local, layout)? - } - PlaceBase::Static(place_static) => { - self.eval_static_to_mplace(place_static)?.into() - } - }; + let base_op = match &place.base { + PlaceBase::Local(mir::RETURN_PLACE) => + throw_unsup!(ReadFromReturnPointer), + PlaceBase::Local(local) => { + // Do not use the layout passed in as argument if the base we are looking at + // here is not the entire place. + // FIXME use place_projection.is_empty() when is available + let layout = if place.projection.is_empty() { + layout + } else { + None + }; - for proj in place_projection { - op = self.operand_projection(op, &proj.elem)? + self.access_local(self.frame(), *local, layout)? + } + PlaceBase::Static(place_static) => { + self.eval_static_to_mplace(&place_static)?.into() } + }; - trace!("eval_place_to_op: got {:?}", *op); - Ok(op) - }) + let op = place.projection.iter().try_fold( + base_op, + |op, elem| self.operand_projection(op, elem) + )?; + + trace!("eval_place_to_op: got {:?}", *op); + Ok(op) } /// Evaluate the operand, returning a place where you can then find the data. @@ -511,7 +532,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Move(ref place) => self.eval_place_to_op(place, layout)?, - Constant(ref constant) => self.eval_const_to_op(constant.literal, layout)?, + Constant(ref constant) => { + let val = self.subst_from_frame_and_normalize_erasing_regions(constant.literal); + self.eval_const_to_op(val, layout)? + } }; trace!("{:?}: {:?}", mir_op, *op); Ok(op) @@ -529,6 +553,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Used when the miri-engine runs into a constant and for extracting information from constants // in patterns via the `const_eval` module + /// The `val` and `layout` are assumed to already be in our interpreter + /// "universe" (param_env). crate fn eval_const_to_op( &self, val: &'tcx ty::Const<'tcx>, @@ -541,7 +567,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Early-return cases. match val.val { ConstValue::Param(_) => - // FIXME(oli-obk): try to monomorphize throw_inval!(TooGeneric), ConstValue::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; @@ -554,7 +579,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } // Other cases need layout. let layout = from_known_layout(layout, || { - self.layout_of(self.monomorphize(val.ty)?) + self.layout_of(val.ty) })?; let op = match val.val { ConstValue::ByRef { alloc, offset } => { @@ -595,15 +620,20 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx, (u128, VariantIdx)> { trace!("read_discriminant_value {:#?}", rval.layout); - let (discr_kind, discr_index) = match rval.layout.variants { + let (discr_layout, discr_kind, discr_index) = match rval.layout.variants { layout::Variants::Single { index } => { let discr_val = rval.layout.ty.discriminant_for_variant(*self.tcx, index).map_or( index.as_u32() as u128, |discr| discr.val); return Ok((discr_val, index)); } - layout::Variants::Multiple { ref discr_kind, discr_index, .. } => - (discr_kind, discr_index), + layout::Variants::Multiple { + discr: ref discr_layout, + ref discr_kind, + discr_index, + .. + } => + (discr_layout, discr_kind, discr_index), }; // read raw discriminant value @@ -614,14 +644,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // post-process Ok(match *discr_kind { layout::DiscriminantKind::Tag => { - let bits_discr = match raw_discr.to_bits(discr_val.layout.size) { - Ok(raw_discr) => raw_discr, - Err(_) => - throw_unsup!(InvalidDiscriminant(raw_discr.erase_tag())), - }; + let bits_discr = raw_discr + .not_undef() + .and_then(|raw_discr| self.force_bits(raw_discr, discr_val.layout.size)) + .map_err(|_| err_unsup!(InvalidDiscriminant(raw_discr.erase_tag())))?; let real_discr = if discr_val.layout.ty.is_signed() { // going from layout tag type to typeck discriminant type - // requires first sign extending with the layout discriminant + // requires first sign extending with the discriminant layout let sexted = sign_extend(bits_discr, discr_val.layout.size) as i128; // and then zeroing with the typeck discriminant type let discr_ty = rval.layout.ty @@ -635,14 +664,18 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { bits_discr }; // Make sure we catch invalid discriminants - let index = match &rval.layout.ty.sty { + let index = match rval.layout.ty.kind { ty::Adt(adt, _) => adt .discriminants(self.tcx.tcx) .find(|(_, var)| var.val == real_discr), - ty::Generator(def_id, substs, _) => substs - .discriminants(*def_id, self.tcx.tcx) - .find(|(_, var)| var.val == real_discr), + ty::Generator(def_id, substs, _) => { + let substs = substs.as_generator(); + substs + .discriminants(def_id, self.tcx.tcx) + .find(|(_, var)| var.val == real_discr) + } _ => bug!("tagged layout for non-adt non-generator"), + }.ok_or_else( || err_unsup!(InvalidDiscriminant(raw_discr.erase_tag())) )?; @@ -653,8 +686,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ref niche_variants, niche_start, } => { - let variants_start = niche_variants.start().as_u32() as u128; - let variants_end = niche_variants.end().as_u32() as u128; + let variants_start = niche_variants.start().as_u32(); + let variants_end = niche_variants.end().as_u32(); let raw_discr = raw_discr.not_undef().map_err(|_| { err_unsup!(InvalidDiscriminant(ScalarMaybeUndef::Undef)) })?; @@ -669,18 +702,34 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (dataful_variant.as_u32() as u128, dataful_variant) }, Ok(raw_discr) => { - let adjusted_discr = raw_discr.wrapping_sub(niche_start) - .wrapping_add(variants_start); - if variants_start <= adjusted_discr && adjusted_discr <= variants_end { - let index = adjusted_discr as usize; - assert_eq!(index as u128, adjusted_discr); - assert!(index < rval.layout.ty + // We need to use machine arithmetic to get the relative variant idx: + // variant_index_relative = discr_val - niche_start_val + let discr_layout = self.layout_of(discr_layout.value.to_int_ty(*self.tcx))?; + let discr_val = ImmTy::from_uint(raw_discr, discr_layout); + let niche_start_val = ImmTy::from_uint(niche_start, discr_layout); + let variant_index_relative_val = self.binary_op( + mir::BinOp::Sub, + discr_val, + niche_start_val, + )?; + let variant_index_relative = variant_index_relative_val + .to_scalar()? + .assert_bits(discr_val.layout.size); + // Check if this is in the range that indicates an actual discriminant. + if variant_index_relative <= u128::from(variants_end - variants_start) { + let variant_index_relative = u32::try_from(variant_index_relative) + .expect("we checked that this fits into a u32"); + // Then computing the absolute variant idx should not overflow any more. + let variant_index = variants_start + .checked_add(variant_index_relative) + .expect("oveflow computing absolute variant idx"); + assert!((variant_index as usize) < rval.layout.ty .ty_adt_def() .expect("tagged layout for non adt") .variants.len()); - (adjusted_discr, VariantIdx::from_usize(index)) + (u128::from(variant_index), VariantIdx::from_u32(variant_index)) } else { - (dataful_variant.as_u32() as u128, dataful_variant) + (u128::from(dataful_variant.as_u32()), dataful_variant) } }, } diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index e638ebcc34265..176b084f22587 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -1,5 +1,5 @@ use rustc::mir; -use rustc::ty::{self, layout::TyLayout}; +use rustc::ty::{self, Ty, layout::{TyLayout, LayoutOf}}; use syntax::ast::FloatTy; use rustc_apfloat::Float; use rustc::mir::interpret::{InterpResult, Scalar}; @@ -17,7 +17,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { right: ImmTy<'tcx, M::PointerTag>, dest: PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { - let (val, overflowed) = self.binary_op(op, left, right)?; + let (val, overflowed, ty) = self.overflowing_binary_op(op, left, right)?; + debug_assert_eq!( + self.tcx.intern_tup(&[ty, self.tcx.types.bool]), + dest.layout.ty, + "type mismatch for result of {:?}", op, + ); let val = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into()); self.write_immediate(val, dest) } @@ -31,7 +36,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { right: ImmTy<'tcx, M::PointerTag>, dest: PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { - let (val, _overflowed) = self.binary_op(op, left, right)?; + let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?; + assert_eq!(ty, dest.layout.ty, "type mismatch for result of {:?}", op); self.write_scalar(val, dest) } } @@ -42,7 +48,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { bin_op: mir::BinOp, l: char, r: char, - ) -> (Scalar, bool) { + ) -> (Scalar, bool, Ty<'tcx>) { use rustc::mir::BinOp::*; let res = match bin_op { @@ -54,7 +60,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ge => l >= r, _ => bug!("Invalid operation on char: {:?}", bin_op), }; - return (Scalar::from_bool(res), false); + return (Scalar::from_bool(res), false, self.tcx.types.bool); } fn binary_bool_op( @@ -62,7 +68,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { bin_op: mir::BinOp, l: bool, r: bool, - ) -> (Scalar, bool) { + ) -> (Scalar, bool, Ty<'tcx>) { use rustc::mir::BinOp::*; let res = match bin_op { @@ -77,32 +83,33 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { BitXor => l ^ r, _ => bug!("Invalid operation on bool: {:?}", bin_op), }; - return (Scalar::from_bool(res), false); + return (Scalar::from_bool(res), false, self.tcx.types.bool); } fn binary_float_op>>( &self, bin_op: mir::BinOp, + ty: Ty<'tcx>, l: F, r: F, - ) -> (Scalar, bool) { + ) -> (Scalar, bool, Ty<'tcx>) { use rustc::mir::BinOp::*; - let val = match bin_op { - Eq => Scalar::from_bool(l == r), - Ne => Scalar::from_bool(l != r), - Lt => Scalar::from_bool(l < r), - Le => Scalar::from_bool(l <= r), - Gt => Scalar::from_bool(l > r), - Ge => Scalar::from_bool(l >= r), - Add => (l + r).value.into(), - Sub => (l - r).value.into(), - Mul => (l * r).value.into(), - Div => (l / r).value.into(), - Rem => (l % r).value.into(), + let (val, ty) = match bin_op { + Eq => (Scalar::from_bool(l == r), self.tcx.types.bool), + Ne => (Scalar::from_bool(l != r), self.tcx.types.bool), + Lt => (Scalar::from_bool(l < r), self.tcx.types.bool), + Le => (Scalar::from_bool(l <= r), self.tcx.types.bool), + Gt => (Scalar::from_bool(l > r), self.tcx.types.bool), + Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool), + Add => ((l + r).value.into(), ty), + Sub => ((l - r).value.into(), ty), + Mul => ((l * r).value.into(), ty), + Div => ((l / r).value.into(), ty), + Rem => ((l % r).value.into(), ty), _ => bug!("invalid float op: `{:?}`", bin_op), }; - return (val, false); + return (val, false, ty); } fn binary_int_op( @@ -113,7 +120,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { left_layout: TyLayout<'tcx>, r: u128, right_layout: TyLayout<'tcx>, - ) -> InterpResult<'tcx, (Scalar, bool)> { + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { use rustc::mir::BinOp::*; // Shift ops can have an RHS with a different numeric type. @@ -142,7 +149,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } }; let truncated = self.truncate(result, left_layout); - return Ok((Scalar::from_uint(truncated, size), oflo)); + return Ok((Scalar::from_uint(truncated, size), oflo, left_layout.ty)); } // For the remaining ops, the types must be the same on both sides @@ -167,7 +174,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if let Some(op) = op { let l = self.sign_extend(l, left_layout) as i128; let r = self.sign_extend(r, right_layout) as i128; - return Ok((Scalar::from_bool(op(&l, &r)), false)); + return Ok((Scalar::from_bool(op(&l, &r)), false, self.tcx.types.bool)); } let op: Option (i128, bool)> = match bin_op { Div if r == 0 => throw_panic!(DivisionByZero), @@ -187,7 +194,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Rem | Div => { // int_min / -1 if r == -1 && l == (1 << (size.bits() - 1)) { - return Ok((Scalar::from_uint(l, size), true)); + return Ok((Scalar::from_uint(l, size), true, left_layout.ty)); } }, _ => {}, @@ -202,25 +209,24 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // this may be out-of-bounds for the result type, so we have to truncate ourselves let result = result as u128; let truncated = self.truncate(result, left_layout); - return Ok((Scalar::from_uint(truncated, size), oflo)); + return Ok((Scalar::from_uint(truncated, size), oflo, left_layout.ty)); } } let size = left_layout.size; - // only ints left - let val = match bin_op { - Eq => Scalar::from_bool(l == r), - Ne => Scalar::from_bool(l != r), + let (val, ty) = match bin_op { + Eq => (Scalar::from_bool(l == r), self.tcx.types.bool), + Ne => (Scalar::from_bool(l != r), self.tcx.types.bool), - Lt => Scalar::from_bool(l < r), - Le => Scalar::from_bool(l <= r), - Gt => Scalar::from_bool(l > r), - Ge => Scalar::from_bool(l >= r), + Lt => (Scalar::from_bool(l < r), self.tcx.types.bool), + Le => (Scalar::from_bool(l <= r), self.tcx.types.bool), + Gt => (Scalar::from_bool(l > r), self.tcx.types.bool), + Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool), - BitOr => Scalar::from_uint(l | r, size), - BitAnd => Scalar::from_uint(l & r, size), - BitXor => Scalar::from_uint(l ^ r, size), + BitOr => (Scalar::from_uint(l | r, size), left_layout.ty), + BitAnd => (Scalar::from_uint(l & r, size), left_layout.ty), + BitXor => (Scalar::from_uint(l ^ r, size), left_layout.ty), Add | Sub | Mul | Rem | Div => { debug_assert!(!left_layout.abi.is_signed()); @@ -236,7 +242,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; let (result, oflo) = op(l, r); let truncated = self.truncate(result, left_layout); - return Ok((Scalar::from_uint(truncated, size), oflo || truncated != result)); + return Ok(( + Scalar::from_uint(truncated, size), + oflo || truncated != result, + left_layout.ty, + )); } _ => { @@ -250,21 +260,21 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } }; - Ok((val, false)) + Ok((val, false, ty)) } - /// Returns the result of the specified operation and whether it overflowed. - #[inline] - pub fn binary_op( + /// Returns the result of the specified operation, whether it overflowed, and + /// the result type. + pub fn overflowing_binary_op( &self, bin_op: mir::BinOp, left: ImmTy<'tcx, M::PointerTag>, right: ImmTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, (Scalar, bool)> { + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})", bin_op, *left, left.layout.ty, *right, right.layout.ty); - match left.layout.ty.sty { + match left.layout.ty.kind { ty::Char => { assert_eq!(left.layout.ty, right.layout.ty); let left = left.to_scalar()?; @@ -279,11 +289,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } ty::Float(fty) => { assert_eq!(left.layout.ty, right.layout.ty); + let ty = left.layout.ty; let left = left.to_scalar()?; let right = right.to_scalar()?; Ok(match fty { - FloatTy::F32 => self.binary_float_op(bin_op, left.to_f32()?, right.to_f32()?), - FloatTy::F64 => self.binary_float_op(bin_op, left.to_f64()?, right.to_f64()?), + FloatTy::F32 => + self.binary_float_op(bin_op, ty, left.to_f32()?, right.to_f32()?), + FloatTy::F64 => + self.binary_float_op(bin_op, ty, left.to_f64()?, right.to_f64()?), }) } _ if left.layout.ty.is_integral() => { @@ -312,25 +325,37 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } + /// Typed version of `checked_binary_op`, returning an `ImmTy`. Also ignores overflows. + #[inline] + pub fn binary_op( + &self, + bin_op: mir::BinOp, + left: ImmTy<'tcx, M::PointerTag>, + right: ImmTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> { + let (val, _overflow, ty) = self.overflowing_binary_op(bin_op, left, right)?; + Ok(ImmTy::from_scalar(val, self.layout_of(ty)?)) + } + pub fn unary_op( &self, un_op: mir::UnOp, val: ImmTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> { use rustc::mir::UnOp::*; let layout = val.layout; let val = val.to_scalar()?; trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty); - match layout.ty.sty { + match layout.ty.kind { ty::Bool => { let val = val.to_bool()?; let res = match un_op { Not => !val, _ => bug!("Invalid bool op {:?}", un_op) }; - Ok(Scalar::from_bool(res)) + Ok(ImmTy::from_scalar(Scalar::from_bool(res), self.layout_of(self.tcx.types.bool)?)) } ty::Float(fty) => { let res = match (un_op, fty) { @@ -338,7 +363,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?), _ => bug!("Invalid float op {:?}", un_op) }; - Ok(res) + Ok(ImmTy::from_scalar(res, layout)) } _ => { assert!(layout.ty.is_integral()); @@ -351,7 +376,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } }; // res needs tuncating - Ok(Scalar::from_uint(self.truncate(res, layout), layout.size)) + Ok(ImmTy::from_uint(self.truncate(res, layout), layout)) } } } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index f66c4adf76397..3ba989529f18f 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -8,7 +8,9 @@ use std::hash::Hash; use rustc::mir; use rustc::mir::interpret::truncate; use rustc::ty::{self, Ty}; -use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx}; +use rustc::ty::layout::{ + self, Size, Abi, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx, PrimitiveExt +}; use rustc::ty::TypeFoldable; use super::{ @@ -45,7 +47,7 @@ pub enum Place { #[derive(Copy, Clone, Debug)] pub struct PlaceTy<'tcx, Tag=()> { - place: Place, + place: Place, // Keep this private, it helps enforce invariants pub layout: TyLayout<'tcx>, } @@ -191,7 +193,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { pub(super) fn len(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { if self.layout.is_unsized() { // We need to consult `meta` metadata - match self.layout.ty.sty { + match self.layout.ty.kind { ty::Slice(..) | ty::Str => return self.mplace.meta.unwrap().to_usize(cx), _ => bug!("len not supported on unsized type {:?}", self.layout.ty), @@ -208,7 +210,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { #[inline] pub(super) fn vtable(self) -> Scalar { - match self.layout.ty.sty { + match self.layout.ty.kind { ty::Dynamic(..) => self.mplace.meta.unwrap(), _ => bug!("vtable not supported on type {:?}", self.layout.ty), } @@ -277,6 +279,10 @@ where { /// Take a value, which represents a (thin or fat) reference, and make it a place. /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`. + /// + /// Only call this if you are sure the place is "valid" (aligned and inbounds), or do not + /// want to ever use the place for memory access! + /// Generally prefer `deref_operand`. pub fn ref_to_mplace( &self, val: ImmTy<'tcx, M::PointerTag>, @@ -304,7 +310,8 @@ where ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { let val = self.read_immediate(src)?; trace!("deref to {} on {:?}", val.layout.ty, *val); - self.ref_to_mplace(val) + let place = self.ref_to_mplace(val)?; + self.mplace_access_checked(place) } /// Check if the given place is good for memory access with the given @@ -327,6 +334,23 @@ where self.memory.check_ptr_access(place.ptr, size, place.align) } + /// Return the "access-checked" version of this `MPlace`, where for non-ZST + /// this is definitely a `Pointer`. + pub fn mplace_access_checked( + &self, + mut place: MPlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + let (size, align) = self.size_and_align_of_mplace(place)? + .unwrap_or((place.layout.size, place.layout.align.abi)); + assert!(place.mplace.align <= align, "dynamic alignment less strict than static one?"); + place.mplace.align = align; // maximally strict checking + // When dereferencing a pointer, it must be non-NULL, aligned, and live. + if let Some(ptr) = self.check_mplace_access(place, Some(size))? { + place.mplace.ptr = ptr.into(); + } + Ok(place) + } + /// Force `place.ptr` to a `Pointer`. /// Can be helpful to avoid lots of `force_ptr` calls later, if this place is used a lot. pub fn force_mplace_ptr( @@ -361,6 +385,10 @@ where stride * field } layout::FieldPlacement::Union(count) => { + // FIXME(#64506) `UninhabitedValue` can be removed when this issue is resolved + if base.layout.abi == Abi::Uninhabited { + throw_unsup!(UninhabitedValue); + } assert!(field < count as u64, "Tried to access field {} of union with {} fields", field, count); // Offset is always 0 @@ -435,7 +463,7 @@ where // Compute meta and new layout let inner_len = len - to - from; - let (meta, ty) = match base.layout.ty.sty { + let (meta, ty) = match base.layout.ty.kind { // It is not nice to match on the type, but that seems to be the only way to // implement this. ty::Array(inner, _) => @@ -563,19 +591,27 @@ where use rustc::mir::StaticKind; Ok(match place_static.kind { - StaticKind::Promoted(promoted) => { - let instance = self.frame().instance; + StaticKind::Promoted(promoted, promoted_substs) => { + let substs = self.subst_from_frame_and_normalize_erasing_regions(promoted_substs); + let instance = ty::Instance::new(place_static.def_id, substs); + + // Even after getting `substs` from the frame, this instance may still be + // polymorphic because `ConstProp` will try to promote polymorphic MIR. + if instance.needs_subst() { + throw_inval!(TooGeneric); + } + self.const_eval_raw(GlobalId { instance, promoted: Some(promoted), })? } - StaticKind::Static(def_id) => { + StaticKind::Static => { let ty = place_static.ty; assert!(!ty.needs_subst()); let layout = self.layout_of(ty)?; - let instance = ty::Instance::mono(*self.tcx, def_id); + let instance = ty::Instance::mono(*self.tcx, place_static.def_id); let cid = GlobalId { instance, promoted: None @@ -606,42 +642,43 @@ where /// place; for reading, a more efficient alternative is `eval_place_for_read`. pub fn eval_place( &mut self, - mir_place: &mir::Place<'tcx>, + place: &mir::Place<'tcx>, ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { use rustc::mir::PlaceBase; - mir_place.iterate(|place_base, place_projection| { - let mut place = match place_base { - PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place { - Some(return_place) => { - // We use our layout to verify our assumption; caller will validate - // their layout on return. - PlaceTy { - place: *return_place, - layout: self - .layout_of(self.monomorphize(self.frame().body.return_ty())?)?, - } + let mut place_ty = match &place.base { + PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place { + Some(return_place) => { + // We use our layout to verify our assumption; caller will validate + // their layout on return. + PlaceTy { + place: *return_place, + layout: self.layout_of( + self.subst_from_frame_and_normalize_erasing_regions( + self.frame().body.return_ty() + ) + )?, } - None => throw_unsup!(InvalidNullPointerUsage), - }, - PlaceBase::Local(local) => PlaceTy { - // This works even for dead/uninitialized locals; we check further when writing - place: Place::Local { - frame: self.cur_frame(), - local: *local, - }, - layout: self.layout_of_local(self.frame(), *local, None)?, + } + None => throw_unsup!(InvalidNullPointerUsage), + }, + PlaceBase::Local(local) => PlaceTy { + // This works even for dead/uninitialized locals; we check further when writing + place: Place::Local { + frame: self.cur_frame(), + local: *local, }, - PlaceBase::Static(place_static) => self.eval_static_to_mplace(place_static)?.into(), - }; + layout: self.layout_of_local(self.frame(), *local, None)?, + }, + PlaceBase::Static(place_static) => self.eval_static_to_mplace(&place_static)?.into(), + }; - for proj in place_projection { - place = self.place_projection(place, &proj.elem)? - } + for elem in place.projection.iter() { + place_ty = self.place_projection(place_ty, elem)? + } - self.dump_place(place.place); - Ok(place) - }) + self.dump_place(place_ty.place); + Ok(place_ty) } /// Write a scalar to a place @@ -750,7 +787,9 @@ where // to handle padding properly, which is only correct if we never look at this data with the // wrong type. - let ptr = match self.check_mplace_access(dest, None)? { + let ptr = match self.check_mplace_access(dest, None) + .expect("places should be checked on creation") + { Some(ptr) => ptr, None => return Ok(()), // zero-sized access }; @@ -853,8 +892,10 @@ where }); assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances"); - let src = self.check_mplace_access(src, Some(size))?; - let dest = self.check_mplace_access(dest, Some(size))?; + let src = self.check_mplace_access(src, Some(size)) + .expect("places should be checked on creation"); + let dest = self.check_mplace_access(dest, Some(size)) + .expect("places should be checked on creation"); let (src_ptr, dest_ptr) = match (src, dest) { (Some(src_ptr), Some(dest_ptr)) => (src_ptr, dest_ptr), (None, None) => return Ok(()), // zero-sized copy @@ -999,7 +1040,7 @@ where } layout::Variants::Multiple { discr_kind: layout::DiscriminantKind::Tag, - ref discr, + discr: ref discr_layout, discr_index, .. } => { @@ -1010,7 +1051,7 @@ where // raw discriminants for enums are isize or bigger during // their computation, but the in-memory tag is the smallest possible // representation - let size = discr.value.size(self); + let size = discr_layout.value.size(self); let discr_val = truncate(discr_val, size); let discr_dest = self.place_field(dest, discr_index as u64)?; @@ -1022,6 +1063,7 @@ where ref niche_variants, niche_start, }, + discr: ref discr_layout, discr_index, .. } => { @@ -1029,15 +1071,24 @@ where variant_index.as_usize() < dest.layout.ty.ty_adt_def().unwrap().variants.len(), ); if variant_index != dataful_variant { - let niche_dest = - self.place_field(dest, discr_index as u64)?; - let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); - let niche_value = (niche_value as u128) - .wrapping_add(niche_start); - self.write_scalar( - Scalar::from_uint(niche_value, niche_dest.layout.size), - niche_dest + let variants_start = niche_variants.start().as_u32(); + let variant_index_relative = variant_index.as_u32() + .checked_sub(variants_start) + .expect("overflow computing relative variant idx"); + // We need to use machine arithmetic when taking into account `niche_start`: + // discr_val = variant_index_relative + niche_start_val + let discr_layout = self.layout_of(discr_layout.value.to_int_ty(*self.tcx))?; + let niche_start_val = ImmTy::from_uint(niche_start, discr_layout); + let variant_index_relative_val = + ImmTy::from_uint(variant_index_relative, discr_layout); + let discr_val = self.binary_op( + mir::BinOp::Add, + variant_index_relative_val, + niche_start_val, )?; + // Write result. + let niche_dest = self.place_field(dest, discr_index as u64)?; + self.write_immediate(*discr_val, niche_dest)?; } } } diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index fad9fafbb0803..7ce151e087a6b 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -15,9 +15,9 @@ use rustc::mir::interpret::{ }; use rustc::ty::{self, TyCtxt}; -use rustc::ty::layout::Align; +use rustc::ty::layout::{Align, Size}; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::vec::IndexVec; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use syntax::ast::Mutability; use syntax::source_map::Span; @@ -52,9 +52,9 @@ impl<'mir, 'tcx> InfiniteLoopDetector<'mir, 'tcx> { ) -> InterpResult<'tcx, ()> { // Compute stack's hash before copying anything let mut hcx = tcx.get_stable_hashing_context(); - let mut hasher = StableHasher::::new(); + let mut hasher = StableHasher::new(); stack.hash_stable(&mut hcx, &mut hasher); - let hash = hasher.finish(); + let hash = hasher.finish::(); // Check if we know that hash already if self.hashes.is_empty() { @@ -276,6 +276,7 @@ struct AllocationSnapshot<'a> { relocations: Relocations<(), AllocIdSnapshot<'a>>, undef_mask: &'a UndefMask, align: &'a Align, + size: &'a Size, mutability: &'a Mutability, } @@ -285,12 +286,28 @@ impl<'a, Ctx> Snapshot<'a, Ctx> for &'a Allocation type Item = AllocationSnapshot<'a>; fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { - let Allocation { bytes, relocations, undef_mask, align, mutability, extra: () } = self; + let Allocation { + size, + align, + mutability, + extra: (), + .. + } = self; + + let all_bytes = 0..self.len(); + // This 'inspect' is okay since following access respects undef and relocations. This does + // influence interpreter exeuction, but only to detect the error of cycles in evalution + // dependencies. + let bytes = self.inspect_with_undef_and_ptr_outside_interpreter(all_bytes); + + let undef_mask = self.undef_mask(); + let relocations = self.relocations(); AllocationSnapshot { bytes, undef_mask, align, + size, mutability, relocations: relocations.snapshot(ctx), } @@ -304,7 +321,7 @@ impl_stable_hash_for!(enum crate::interpret::eval_context::StackPopCleanup { #[derive(Eq, PartialEq)] struct FrameSnapshot<'a, 'tcx> { - instance: &'a ty::Instance<'tcx>, + instance: ty::Instance<'tcx>, span: Span, return_to_block: &'a StackPopCleanup, return_place: Option>>, @@ -344,7 +361,7 @@ impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx> } = self; FrameSnapshot { - instance, + instance: *instance, span: *span, return_to_block, block, @@ -411,9 +428,9 @@ impl<'mir, 'tcx> Hash for InterpSnapshot<'mir, 'tcx> { fn hash(&self, state: &mut H) { // Implement in terms of hash stable, so that k1 == k2 -> hash(k1) == hash(k2) let mut hcx = self.memory.tcx.get_stable_hashing_context(); - let mut hasher = StableHasher::::new(); + let mut hasher = StableHasher::new(); self.hash_stable(&mut hcx, &mut hasher); - hasher.finish().hash(state) + hasher.finish::().hash(state) } } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index d152e2b50fa1b..daca7a25787ca 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -82,7 +82,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.memory.tcx.span = stmt.source_info.span; match stmt.kind { - Assign(ref place, ref rvalue) => self.eval_rvalue_into_place(rvalue, place)?, + Assign(box(ref place, ref rvalue)) => self.eval_rvalue_into_place(rvalue, place)?, SetDiscriminant { ref place, @@ -132,7 +132,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue /// type writes its results directly into the memory specified by the place. - fn eval_rvalue_into_place( + pub fn eval_rvalue_into_place( &mut self, rvalue: &mir::Rvalue<'tcx>, place: &mir::Place<'tcx>, @@ -177,7 +177,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // The operand always has the same type as the result. let val = self.read_immediate(self.eval_operand(operand, Some(dest.layout))?)?; let val = self.unary_op(un_op, val)?; - self.write_scalar(val, dest)?; + assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op); + self.write_immediate(*val, dest)?; } Aggregate(ref kind, ref operands) => { @@ -240,8 +241,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ref(_, _, ref place) => { let src = self.eval_place(place)?; - let val = self.force_allocation(src)?; - self.write_immediate(val.to_ref(), dest)?; + let place = self.force_allocation(src)?; + if place.layout.size.bytes() > 0 { + // definitely not a ZST + assert!(place.ptr.is_ptr(), "non-ZST places should be normalized to `Pointer`"); + } + self.write_immediate(place.to_ref(), dest)?; } NullaryOp(mir::NullOp::Box, _) => { @@ -249,7 +254,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } NullaryOp(mir::NullOp::SizeOf, ty) => { - let ty = self.monomorphize(ty)?; + let ty = self.subst_from_frame_and_normalize_erasing_regions(ty); let layout = self.layout_of(ty)?; assert!(!layout.is_unsized(), "SizeOf nullary MIR operator called for unsized type"); diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index a0c6fb026dd4b..11c7cd0d901d0 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -7,7 +7,7 @@ use syntax::source_map::Span; use rustc_target::spec::abi::Abi; use super::{ - InterpResult, PointerArithmetic, Scalar, + InterpResult, PointerArithmetic, InterpCx, Machine, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal, }; @@ -50,11 +50,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { for (index, &const_int) in values.iter().enumerate() { // Compare using binary_op, to also support pointer values - let const_int = Scalar::from_uint(const_int, discr.layout.size); - let (res, _) = self.binary_op(mir::BinOp::Eq, + let res = self.overflowing_binary_op(mir::BinOp::Eq, discr, - ImmTy::from_scalar(const_int, discr.layout), - )?; + ImmTy::from_uint(const_int, discr.layout), + )?.0; if res.to_bool()? { target_block = targets[index]; break; @@ -76,7 +75,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; let func = self.eval_operand(func, None)?; - let (fn_val, abi) = match func.layout.ty.sty { + let (fn_val, abi) = match func.layout.ty.kind { ty::FnPtr(sig) => { let caller_abi = sig.abi(); let fn_ptr = self.read_scalar(func)?.not_undef()?; @@ -250,9 +249,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match instance.def { ty::InstanceDef::Intrinsic(..) => { - if caller_abi != Abi::RustIntrinsic { - throw_unsup!(FunctionAbiMismatch(caller_abi, Abi::RustIntrinsic)) - } // The intrinsic itself cannot diverge, so if we got here without a return // place... (can happen e.g., for transmute returning `!`) let dest = match dest { @@ -267,6 +263,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(()) } ty::InstanceDef::VtableShim(..) | + ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::DropGlue(..) | @@ -276,7 +273,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { { let callee_abi = { let instance_ty = instance.ty(*self.tcx); - match instance_ty.sty { + match instance_ty.kind { ty::FnDef(..) => instance_ty.fn_sig(*self.tcx).abi(), ty::Closure(..) => Abi::RustCall, @@ -392,7 +389,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Don't forget to check the return type! if let Some(caller_ret) = dest { let callee_ret = self.eval_place( - &mir::Place::RETURN_PLACE + &mir::Place::return_place() )?; if !Self::check_argument_compat( rust_abi, @@ -405,9 +402,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } else { let local = mir::RETURN_PLACE; - let ty = self.frame().body.local_decls[local].ty; - if !self.tcx.is_ty_uninhabited_from_any_module(ty) { - throw_unsup!(FunctionRetMismatch(self.tcx.types.never, ty)) + let callee_layout = self.layout_of_local(self.frame(), local, None)?; + if !callee_layout.abi.is_uninhabited() { + throw_unsup!(FunctionRetMismatch( + self.tcx.types.never, callee_layout.ty + )) } } Ok(()) @@ -481,7 +480,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // implementation fail -- a problem shared by rustc. let place = self.force_allocation(place)?; - let (instance, place) = match place.layout.ty.sty { + let (instance, place) = match place.layout.ty.kind { ty::Dynamic(..) => { // Dropping a trait object. self.unpack_dyn_trait(place)? diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index e55b0d0fb1f2a..10b767ebba191 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -1,5 +1,5 @@ -use rustc::ty::{self, Ty, Instance}; -use rustc::ty::layout::{Size, Align, LayoutOf}; +use rustc::ty::{self, Ty, Instance, TypeFoldable}; +use rustc::ty::layout::{Size, Align, LayoutOf, HasDataLayout}; use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic,}; use super::{InterpCx, Machine, MemoryKind, FnVal}; @@ -20,6 +20,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (ty, poly_trait_ref) = self.tcx.erase_regions(&(ty, poly_trait_ref)); + // All vtables must be monomorphic, bail out otherwise. + if ty.needs_subst() || poly_trait_ref.needs_subst() { + throw_inval!(TooGeneric); + } + if let Some(&vtable) = self.vtables.get(&(ty, poly_trait_ref)) { // This means we guarantee that there are no duplicate vtables, we will // always use the same vtable for the same (Type, Trait) combination. @@ -77,7 +82,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { for (i, method) in methods.iter().enumerate() { if let Some((def_id, substs)) = *method { // resolve for vtable: insert shims where needed - let substs = self.subst_and_normalize_erasing_regions(substs)?; let instance = ty::Instance::resolve_for_vtable( *self.tcx, self.param_env, @@ -140,11 +144,18 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let size = alloc.read_ptr_sized( self, vtable.offset(pointer_size, self)? - )?.to_bits(pointer_size)? as u64; + )?.not_undef()?; + let size = self.force_bits(size, pointer_size)? as u64; let align = alloc.read_ptr_sized( self, vtable.offset(pointer_size * 2, self)?, - )?.to_bits(pointer_size)? as u64; + )?.not_undef()?; + let align = self.force_bits(align, pointer_size)? as u64; + + if size >= self.tcx.data_layout().obj_size_bound() { + throw_ub_format!("invalid vtable: \ + size is bigger than largest supported object"); + } Ok((Size::from_bytes(size), Align::from_bytes(align).unwrap())) } } diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 82d6d7db01c8d..853fcb1beabf5 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -1,3 +1,9 @@ +//! Check the validity invariant of a given value, and tell the user +//! where in the value it got violated. +//! In const context, this goes even further and tries to approximate const safety. +//! That's useful because it means other passes (e.g. promotion) can rely on `const`s +//! to be const-safe. + use std::fmt::Write; use std::ops::RangeInclusive; @@ -11,7 +17,7 @@ use std::hash::Hash; use super::{ GlobalAlloc, InterpResult, - OpTy, Machine, InterpCx, ValueVisitor, MPlaceTy, + Scalar, OpTy, Machine, InterpCx, ValueVisitor, MPlaceTy, }; macro_rules! throw_validation_failure { @@ -182,7 +188,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M layout: TyLayout<'tcx>, field: usize, ) -> PathElem { - match layout.ty.sty { + match layout.ty.kind { // generators and closures. ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { let mut name = None; @@ -194,7 +200,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M if let Some((&var_hir_id, _)) = upvars.get_index(field) { let node = self.ecx.tcx.hir().get(var_hir_id); if let hir::Node::Binding(pat) = node { - if let hir::PatKind::Binding(_, _, ident, _) = pat.node { + if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { name = Some(ident.name); } } @@ -250,6 +256,47 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M self.path.truncate(path_len); Ok(()) } + + fn check_wide_ptr_meta( + &mut self, + meta: Option>, + pointee: TyLayout<'tcx>, + ) -> InterpResult<'tcx> { + let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env); + match tail.kind { + ty::Dynamic(..) => { + let vtable = meta.unwrap(); + try_validation!( + self.ecx.memory.check_ptr_access( + vtable, + 3*self.ecx.tcx.data_layout.pointer_size, // drop, size, align + self.ecx.tcx.data_layout.pointer_align.abi, + ), + "dangling or unaligned vtable pointer in wide pointer or too small vtable", + self.path + ); + try_validation!(self.ecx.read_drop_type_from_vtable(vtable), + "invalid drop fn in vtable", self.path); + try_validation!(self.ecx.read_size_and_align_from_vtable(vtable), + "invalid size or align in vtable", self.path); + // FIXME: More checks for the vtable. + } + ty::Slice(..) | ty::Str => { + let _len = try_validation!(meta.unwrap().to_usize(self.ecx), + "non-integer slice length in wide pointer", self.path); + // We do not check that `len * elem_size <= isize::MAX`: + // that is only required for references, and there it falls out of the + // "dereferencable" check performed by Stacked Borrows. + } + ty::Foreign(..) => { + // Unsized, but not wide. + } + _ => + bug!("Unexpected unsized type tail: {:?}", tail), + } + + Ok(()) + } } impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> @@ -280,7 +327,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> variant_id: VariantIdx, new_op: OpTy<'tcx, M::PointerTag> ) -> InterpResult<'tcx> { - let name = match old_op.layout.ty.sty { + let name = match old_op.layout.ty.kind { ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].ident.name), // Generators also have variants ty::Generator(..) => PathElem::GeneratorState(variant_id), @@ -315,7 +362,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> let value = self.ecx.read_immediate(value)?; // Go over all the primitive types let ty = value.layout.ty; - match ty.sty { + match ty.kind { ty::Bool => { let value = value.to_scalar_or_undef(); try_validation!(value.to_bool(), @@ -341,56 +388,34 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } } ty::RawPtr(..) => { + // Check pointer part. if self.ref_tracking_for_consts.is_some() { // Integers/floats in CTFE: For consistency with integers, we do not // accept undef. let _ptr = try_validation!(value.to_scalar_ptr(), "undefined address in raw pointer", self.path); - let _meta = try_validation!(value.to_meta(), - "uninitialized data in raw fat pointer metadata", self.path); } else { // Remain consistent with `usize`: Accept anything. } + + // Check metadata. + let meta = try_validation!(value.to_meta(), + "uninitialized data in wide pointer metadata", self.path); + let layout = self.ecx.layout_of(value.layout.ty.builtin_deref(true).unwrap().ty)?; + if layout.is_unsized() { + self.check_wide_ptr_meta(meta, layout)?; + } } _ if ty.is_box() || ty.is_region_ptr() => { - // Handle fat pointers. + // Handle wide pointers. // Check metadata early, for better diagnostics let ptr = try_validation!(value.to_scalar_ptr(), "undefined address in pointer", self.path); let meta = try_validation!(value.to_meta(), - "uninitialized data in fat pointer metadata", self.path); + "uninitialized data in wide pointer metadata", self.path); let layout = self.ecx.layout_of(value.layout.ty.builtin_deref(true).unwrap().ty)?; if layout.is_unsized() { - let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(layout.ty, - self.ecx.param_env); - match tail.sty { - ty::Dynamic(..) => { - let vtable = meta.unwrap(); - try_validation!( - self.ecx.memory.check_ptr_access( - vtable, - 3*self.ecx.tcx.data_layout.pointer_size, // drop, size, align - self.ecx.tcx.data_layout.pointer_align.abi, - ), - "dangling or unaligned vtable pointer or too small vtable", - self.path - ); - try_validation!(self.ecx.read_drop_type_from_vtable(vtable), - "invalid drop fn in vtable", self.path); - try_validation!(self.ecx.read_size_and_align_from_vtable(vtable), - "invalid size or align in vtable", self.path); - // FIXME: More checks for the vtable. - } - ty::Slice(..) | ty::Str => { - try_validation!(meta.unwrap().to_usize(self.ecx), - "non-integer slice length in fat pointer", self.path); - } - ty::Foreign(..) => { - // Unsized, but not fat. - } - _ => - bug!("Unexpected unsized type tail: {:?}", tail), - } + self.check_wide_ptr_meta(meta, layout)?; } // Make sure this is dereferencable and all. let (size, align) = self.ecx.size_and_align_of(meta, layout)? @@ -556,7 +581,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> op: OpTy<'tcx, M::PointerTag>, fields: impl Iterator>, ) -> InterpResult<'tcx> { - match op.layout.ty.sty { + match op.layout.ty.kind { ty::Str => { let mplace = op.assert_mem_place(); // strings are never immediate try_validation!(self.ecx.read_str(mplace), @@ -565,7 +590,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> ty::Array(tys, ..) | ty::Slice(tys) if { // This optimization applies only for integer and floating point types // (i.e., types that can hold arbitrary bytes). - match tys.sty { + match tys.kind { ty::Int(..) | ty::Uint(..) | ty::Float(..) => true, _ => false, } diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index 91fbd307db121..427f94f4fbb02 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -239,7 +239,7 @@ macro_rules! make_value_visitor { // Even for single variants, we might be able to get a more refined type: // If it is a trait object, switch to the actual type that was used to create it. - match v.layout().ty.sty { + match v.layout().ty.kind { ty::Dynamic(..) => { // immediate trait objects are not a thing let dest = v.to_op(self.ecx())?.assert_mem_place(); diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 20d5e54d2ce49..a837c34e8d474 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -6,6 +6,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(nll)] #![feature(in_band_lifetimes)] +#![feature(inner_deref)] #![feature(slice_patterns)] #![feature(box_patterns)] #![feature(box_syntax)] @@ -14,7 +15,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(const_fn)] #![feature(decl_macro)] #![feature(exhaustive_patterns)] -#![feature(rustc_diagnostic_macros)] #![feature(never_type)] #![feature(specialization)] #![feature(try_trait)] @@ -22,7 +22,9 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(slice_concat_ext)] #![feature(trusted_len)] #![feature(try_blocks)] -#![feature(mem_take)] +#![feature(associated_type_bounds)] +#![feature(range_is_empty)] +#![feature(stmt_expr_attributes)] #![recursion_limit="256"] @@ -31,11 +33,11 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #[macro_use] extern crate rustc_data_structures; #[macro_use] extern crate syntax; -mod error_codes; +pub mod error_codes; mod borrow_check; mod build; -mod dataflow; +pub mod dataflow; mod hair; mod lints; mod shim; @@ -59,7 +61,4 @@ pub fn provide(providers: &mut Providers<'_>) { let (param_env, (value, field)) = param_env_and_value.into_parts(); const_eval::const_field(tcx, param_env, None, field, value) }; - providers.type_name = interpret::type_name; } - -__build_diagnostic_array! { librustc_mir, DIAGNOSTICS } diff --git a/src/librustc_mir/lints.rs b/src/librustc_mir/lints.rs index 8c815a51b5d65..da3fead1f9dd7 100644 --- a/src/librustc_mir/lints.rs +++ b/src/librustc_mir/lints.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::bit_set::BitSet; +use rustc_index::bit_set::BitSet; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::FnKind; use rustc::hir::map::blocks::FnLikeNode; @@ -86,7 +86,7 @@ fn check_fn_for_unconditional_recursion( TerminatorKind::Call { ref func, .. } => { let func_ty = func.ty(body, tcx); - if let ty::FnDef(fn_def_id, substs) = func_ty.sty { + if let ty::FnDef(fn_def_id, substs) = func_ty.kind { let (call_fn_id, call_substs) = if let Some(instance) = Instance::resolve(tcx, param_env, diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 12d763bb7910a..ee7452d3e8b46 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -180,12 +180,12 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::mir::interpret::{AllocId, ConstValue}; use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem}; -use rustc::ty::subst::{InternalSubsts, SubstsRef}; +use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc::ty::{self, TypeFoldable, Ty, TyCtxt, GenericParamDefKind, Instance}; use rustc::ty::print::obsolete::DefPathBasedNames; use rustc::ty::adjustment::{CustomCoerceUnsized, PointerCast}; use rustc::session::config::EntryFnType; -use rustc::mir::{self, Location, PlaceBase, Promoted, Static, StaticKind}; +use rustc::mir::{self, Location, PlaceBase, Static, StaticKind}; use rustc::mir::visit::Visitor as MirVisitor; use rustc::mir::mono::{MonoItem, InstantiationMode}; use rustc::mir::interpret::{Scalar, GlobalId, GlobalAlloc, ErrorHandled}; @@ -194,7 +194,7 @@ use crate::monomorphize; use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; use rustc::util::common::time; -use rustc_data_structures::bit_set::GrowableBitSet; +use rustc_index::bit_set::GrowableBitSet; use rustc_data_structures::sync::{MTRef, MTLock, ParallelIterator, par_iter}; use std::iter; @@ -285,7 +285,11 @@ pub fn collect_crate_mono_items( tcx: TyCtxt<'_>, mode: MonoItemCollectionMode, ) -> (FxHashSet>, InliningMap<'_>) { + let _prof_timer = tcx.prof.generic_activity("monomorphization_collector"); + let roots = time(tcx.sess, "collecting roots", || { + let _prof_timer = tcx.prof + .generic_activity("monomorphization_collector_root_collections"); collect_roots(tcx, mode) }); @@ -295,6 +299,9 @@ pub fn collect_crate_mono_items( let mut inlining_map = MTLock::new(InliningMap::new()); { + let _prof_timer = tcx.prof + .generic_activity("monomorphization_collector_graph_walk"); + let visited: MTRef<'_, _> = &mut visited; let inlining_map: MTRef<'_, _> = &mut inlining_map; @@ -578,10 +585,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { ty::ParamEnv::reveal_all(), &source_ty, ); - match source_ty.sty { + match source_ty.kind { ty::Closure(def_id, substs) => { let instance = Instance::resolve_closure( - self.tcx, def_id, substs, ty::ClosureKind::FnOnce); + self.tcx, def_id, + substs, ty::ClosureKind::FnOnce); if should_monomorphize_locally(self.tcx, &instance) { self.output.push(create_fn_mono_item(instance)); } @@ -661,7 +669,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { _context: mir::visit::PlaceContext, location: Location) { match place_base { - PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), .. }) => { + PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => { debug!("visiting static {:?} @ {:?}", def_id, location); let tcx = self.tcx; @@ -670,8 +678,24 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.output.push(MonoItem::Static(*def_id)); } } - PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }) => { - // FIXME: should we handle promoteds here instead of eagerly in collect_neighbours? + PlaceBase::Static(box Static { + kind: StaticKind::Promoted(promoted, substs), + def_id, + .. + }) => { + let param_env = ty::ParamEnv::reveal_all(); + let cid = GlobalId { + instance: Instance::new(*def_id, substs.subst(self.tcx, self.param_substs)), + promoted: Some(*promoted), + }; + match self.tcx.const_eval(param_env.and(cid)) { + Ok(val) => collect_const(self.tcx, val, substs, self.output), + Err(ErrorHandled::Reported) => {}, + Err(ErrorHandled::TooGeneric) => { + let span = self.tcx.promoted_mir(*def_id)[*promoted].span; + span_bug!(span, "collection encountered polymorphic constant") + }, + } } PlaceBase::Local(_) => { // Locals have no relevance for collector @@ -696,11 +720,13 @@ fn visit_fn_use<'tcx>( is_direct_call: bool, output: &mut Vec>, ) { - if let ty::FnDef(def_id, substs) = ty.sty { - let instance = ty::Instance::resolve(tcx, - ty::ParamEnv::reveal_all(), - def_id, - substs).unwrap(); + if let ty::FnDef(def_id, substs) = ty.kind { + let resolver = if is_direct_call { + ty::Instance::resolve + } else { + ty::Instance::resolve_for_fn_ptr + }; + let instance = resolver(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap(); visit_instance_use(tcx, instance, is_direct_call, output); } } @@ -723,6 +749,7 @@ fn visit_instance_use<'tcx>( } } ty::InstanceDef::VtableShim(..) | + ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::Virtual(..) | ty::InstanceDef::DropGlue(_, None) => { // don't need to emit shim if we are calling directly. @@ -749,6 +776,7 @@ fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx let def_id = match instance.def { ty::InstanceDef::Item(def_id) => def_id, ty::InstanceDef::VtableShim(..) | + ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::Virtual(..) | ty::InstanceDef::FnPtrShim(..) | @@ -858,7 +886,7 @@ fn find_vtable_types_for_unsizing<'tcx>( return false; } let tail = tcx.struct_tail_erasing_lifetimes(ty, param_env); - match tail.sty { + match tail.kind { ty::Foreign(..) => false, ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, _ => bug!("unexpected unsized tail: {:?}", tail), @@ -871,7 +899,7 @@ fn find_vtable_types_for_unsizing<'tcx>( } }; - match (&source_ty.sty, &target_ty.sty) { + match (&source_ty.kind, &target_ty.kind) { (&ty::Ref(_, a, _), &ty::Ref(_, b, _)) | (&ty::Ref(_, a, _), @@ -929,7 +957,7 @@ fn create_mono_items_for_vtable_methods<'tcx>( assert!(!trait_ty.needs_subst() && !trait_ty.has_escaping_bound_vars() && !impl_ty.needs_subst() && !impl_ty.has_escaping_bound_vars()); - if let ty::Dynamic(ref trait_ty, ..) = trait_ty.sty { + if let ty::Dynamic(ref trait_ty, ..) = trait_ty.kind { if let Some(principal) = trait_ty.principal() { let poly_trait_ref = principal.with_self_ty(tcx, impl_ty); assert!(!poly_trait_ref.has_escaping_bound_vars()); @@ -965,7 +993,7 @@ struct RootCollector<'a, 'tcx> { impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { fn visit_item(&mut self, item: &'v hir::Item) { - match item.node { + match item.kind { hir::ItemKind::ExternCrate(..) | hir::ItemKind::Use(..) | hir::ItemKind::ForeignMod(..) | @@ -1042,7 +1070,7 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { } fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) { - match ii.node { + match ii.kind { hir::ImplItemKind::Method(hir::MethodSig { .. }, _) => { let def_id = self.tcx.hir().local_def_id(ii.hir_id); self.push_if_root(def_id); @@ -1125,7 +1153,7 @@ fn create_mono_items_for_default_impls<'tcx>( item: &'tcx hir::Item, output: &mut Vec>, ) { - match item.node { + match item.kind { hir::ItemKind::Impl(_, _, _, ref generics, .., ref impl_item_refs) => { for param in &generics.params { match param.kind { @@ -1202,7 +1230,7 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec { trace!("collecting {:?} with {:#?}", alloc_id, alloc); - for &((), inner) in alloc.relocations.values() { + for &((), inner) in alloc.relocations().values() { collect_miri(tcx, inner, output); } }, @@ -1222,6 +1250,7 @@ fn collect_neighbours<'tcx>( instance: Instance<'tcx>, output: &mut Vec>, ) { + debug!("collect_neighbours: {:?}", instance.def_id()); let body = tcx.instance_mir(instance.def); MirNeighborCollector { @@ -1230,22 +1259,6 @@ fn collect_neighbours<'tcx>( output, param_substs: instance.substs, }.visit_body(&body); - let param_env = ty::ParamEnv::reveal_all(); - for i in 0..body.promoted.len() { - use rustc_data_structures::indexed_vec::Idx; - let i = Promoted::new(i); - let cid = GlobalId { - instance, - promoted: Some(i), - }; - match tcx.const_eval(param_env.and(cid)) { - Ok(val) => collect_const(tcx, val, instance.substs, output), - Err(ErrorHandled::Reported) => {}, - Err(ErrorHandled::TooGeneric) => span_bug!( - body.promoted[i].span, "collection encountered polymorphic constant", - ), - } - } } fn def_id_to_string(tcx: TyCtxt<'_>, def_id: DefId) -> String { @@ -1263,22 +1276,23 @@ fn collect_const<'tcx>( ) { debug!("visiting const {:?}", constant); - match constant.val { + let param_env = ty::ParamEnv::reveal_all(); + let substituted_constant = tcx.subst_and_normalize_erasing_regions( + param_substs, + param_env, + &constant, + ); + + match substituted_constant.val { ConstValue::Scalar(Scalar::Ptr(ptr)) => collect_miri(tcx, ptr.alloc_id, output), ConstValue::Slice { data: alloc, start: _, end: _ } | ConstValue::ByRef { alloc, .. } => { - for &((), id) in alloc.relocations.values() { + for &((), id) in alloc.relocations().values() { collect_miri(tcx, id, output); } } ConstValue::Unevaluated(def_id, substs) => { - let param_env = ty::ParamEnv::reveal_all(); - let substs = tcx.subst_and_normalize_erasing_regions( - param_substs, - param_env, - &substs, - ); let instance = ty::Instance::resolve(tcx, param_env, def_id, @@ -1295,7 +1309,7 @@ fn collect_const<'tcx>( tcx.def_span(def_id), "collection encountered polymorphic constant", ), } - } + }, _ => {}, } } diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs deleted file mode 100644 index e63426281bf21..0000000000000 --- a/src/librustc_mir/monomorphize/item.rs +++ /dev/null @@ -1,204 +0,0 @@ -use rustc::hir::def_id::LOCAL_CRATE; -use rustc::mir::mono::MonoItem; -use rustc::session::config::OptLevel; -use rustc::ty::{self, TyCtxt, Instance}; -use rustc::ty::subst::InternalSubsts; -use rustc::ty::print::obsolete::DefPathBasedNames; -use syntax::attr::InlineAttr; -use std::fmt; -use rustc::mir::mono::Linkage; -use syntax_pos::symbol::InternedString; -use syntax::source_map::Span; - -/// Describes how a monomorphization will be instantiated in object files. -#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] -pub enum InstantiationMode { - /// There will be exactly one instance of the given MonoItem. It will have - /// external linkage so that it can be linked to from other codegen units. - GloballyShared { - /// In some compilation scenarios we may decide to take functions that - /// are typically `LocalCopy` and instead move them to `GloballyShared` - /// to avoid codegenning them a bunch of times. In this situation, - /// however, our local copy may conflict with other crates also - /// inlining the same function. - /// - /// This flag indicates that this situation is occurring, and informs - /// symbol name calculation that some extra mangling is needed to - /// avoid conflicts. Note that this may eventually go away entirely if - /// ThinLTO enables us to *always* have a globally shared instance of a - /// function within one crate's compilation. - may_conflict: bool, - }, - - /// Each codegen unit containing a reference to the given MonoItem will - /// have its own private copy of the function (with internal linkage). - LocalCopy, -} - -pub trait MonoItemExt<'tcx>: fmt::Debug { - fn as_mono_item(&self) -> &MonoItem<'tcx>; - - fn is_generic_fn(&self) -> bool { - match *self.as_mono_item() { - MonoItem::Fn(ref instance) => { - instance.substs.non_erasable_generics().next().is_some() - } - MonoItem::Static(..) | - MonoItem::GlobalAsm(..) => false, - } - } - - fn symbol_name(&self, tcx: TyCtxt<'tcx>) -> ty::SymbolName { - match *self.as_mono_item() { - MonoItem::Fn(instance) => tcx.symbol_name(instance), - MonoItem::Static(def_id) => { - tcx.symbol_name(Instance::mono(tcx, def_id)) - } - MonoItem::GlobalAsm(hir_id) => { - let def_id = tcx.hir().local_def_id(hir_id); - ty::SymbolName { - name: InternedString::intern(&format!("global_asm_{:?}", def_id)) - } - } - } - } - fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode { - let inline_in_all_cgus = - tcx.sess.opts.debugging_opts.inline_in_all_cgus.unwrap_or_else(|| { - tcx.sess.opts.optimize != OptLevel::No - }) && !tcx.sess.opts.cg.link_dead_code; - - match *self.as_mono_item() { - MonoItem::Fn(ref instance) => { - let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id); - // If this function isn't inlined or otherwise has explicit - // linkage, then we'll be creating a globally shared version. - if self.explicit_linkage(tcx).is_some() || - !instance.def.requires_local(tcx) || - Some(instance.def_id()) == entry_def_id - { - return InstantiationMode::GloballyShared { may_conflict: false } - } - - // At this point we don't have explicit linkage and we're an - // inlined function. If we're inlining into all CGUs then we'll - // be creating a local copy per CGU - if inline_in_all_cgus { - return InstantiationMode::LocalCopy - } - - // Finally, if this is `#[inline(always)]` we're sure to respect - // that with an inline copy per CGU, but otherwise we'll be - // creating one copy of this `#[inline]` function which may - // conflict with upstream crates as it could be an exported - // symbol. - match tcx.codegen_fn_attrs(instance.def_id()).inline { - InlineAttr::Always => InstantiationMode::LocalCopy, - _ => { - InstantiationMode::GloballyShared { may_conflict: true } - } - } - } - MonoItem::Static(..) | - MonoItem::GlobalAsm(..) => { - InstantiationMode::GloballyShared { may_conflict: false } - } - } - } - - fn explicit_linkage(&self, tcx: TyCtxt<'tcx>) -> Option { - let def_id = match *self.as_mono_item() { - MonoItem::Fn(ref instance) => instance.def_id(), - MonoItem::Static(def_id) => def_id, - MonoItem::GlobalAsm(..) => return None, - }; - - let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id); - codegen_fn_attrs.linkage - } - - /// Returns `true` if this instance is instantiable - whether it has no unsatisfied - /// predicates. - /// - /// In order to codegen an item, all of its predicates must hold, because - /// otherwise the item does not make sense. Type-checking ensures that - /// the predicates of every item that is *used by* a valid item *do* - /// hold, so we can rely on that. - /// - /// However, we codegen collector roots (reachable items) and functions - /// in vtables when they are seen, even if they are not used, and so they - /// might not be instantiable. For example, a programmer can define this - /// public function: - /// - /// pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone { - /// <&mut () as Clone>::clone(&s); - /// } - /// - /// That function can't be codegened, because the method `<&mut () as Clone>::clone` - /// does not exist. Luckily for us, that function can't ever be used, - /// because that would require for `&'a mut (): Clone` to hold, so we - /// can just not emit any code, or even a linker reference for it. - /// - /// Similarly, if a vtable method has such a signature, and therefore can't - /// be used, we can just not emit it and have a placeholder (a null pointer, - /// which will never be accessed) in its place. - fn is_instantiable(&self, tcx: TyCtxt<'tcx>) -> bool { - debug!("is_instantiable({:?})", self); - let (def_id, substs) = match *self.as_mono_item() { - MonoItem::Fn(ref instance) => (instance.def_id(), instance.substs), - MonoItem::Static(def_id) => (def_id, InternalSubsts::empty()), - // global asm never has predicates - MonoItem::GlobalAsm(..) => return true - }; - - tcx.substitute_normalize_and_test_predicates((def_id, &substs)) - } - - fn to_string(&self, tcx: TyCtxt<'tcx>, debug: bool) -> String { - return match *self.as_mono_item() { - MonoItem::Fn(instance) => { - to_string_internal(tcx, "fn ", instance, debug) - }, - MonoItem::Static(def_id) => { - let instance = Instance::new(def_id, tcx.intern_substs(&[])); - to_string_internal(tcx, "static ", instance, debug) - }, - MonoItem::GlobalAsm(..) => { - "global_asm".to_string() - } - }; - - fn to_string_internal<'a, 'tcx>( - tcx: TyCtxt<'tcx>, - prefix: &str, - instance: Instance<'tcx>, - debug: bool, - ) -> String { - let mut result = String::with_capacity(32); - result.push_str(prefix); - let printer = DefPathBasedNames::new(tcx, false, false); - printer.push_instance_as_string(instance, &mut result, debug); - result - } - } - - fn local_span(&self, tcx: TyCtxt<'tcx>) -> Option { - match *self.as_mono_item() { - MonoItem::Fn(Instance { def, .. }) => { - tcx.hir().as_local_hir_id(def.def_id()) - } - MonoItem::Static(def_id) => { - tcx.hir().as_local_hir_id(def_id) - } - MonoItem::GlobalAsm(hir_id) => { - Some(hir_id) - } - }.map(|hir_id| tcx.hir().span(hir_id)) - } -} - -impl MonoItemExt<'tcx> for MonoItem<'tcx> { - fn as_mono_item(&self) -> &MonoItem<'tcx> { - self - } -} diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index ad9db4e0aa8d8..b9d38028b72a8 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -134,10 +134,15 @@ pub fn partition<'tcx, I>( where I: Iterator>, { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning"); + // In the first step, we place all regular monomorphizations into their // respective 'home' codegen unit. Regular monomorphizations are all // functions and statics defined in the local crate. - let mut initial_partitioning = place_root_mono_items(tcx, mono_items); + let mut initial_partitioning = { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots"); + place_root_mono_items(tcx, mono_items) + }; initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); @@ -146,8 +151,8 @@ where // If the partitioning should produce a fixed count of codegen units, merge // until that count is reached. if let PartitioningStrategy::FixedUnitCount(count) = strategy { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); merge_codegen_units(tcx, &mut initial_partitioning, count); - debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter()); } @@ -155,8 +160,11 @@ where // monomorphizations have to go into each codegen unit. These additional // monomorphizations can be drop-glue, functions from external crates, and // local functions the definition of which is marked with `#[inline]`. - let mut post_inlining = place_inlined_mono_items(initial_partitioning, - inlining_map); + let mut post_inlining = { + let _prof_timer = + tcx.prof.generic_activity("cgu_partitioning_place_inline_items"); + place_inlined_mono_items(initial_partitioning, inlining_map) + }; post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); @@ -165,6 +173,8 @@ where // Next we try to make as many symbols "internal" as possible, so LLVM has // more freedom to optimize. if !tcx.sess.opts.cg.link_dead_code { + let _prof_timer = + tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); internalize_symbols(tcx, &mut post_inlining, inlining_map); } @@ -329,6 +339,7 @@ fn mono_item_visibility( // These are all compiler glue and such, never exported, always hidden. InstanceDef::VtableShim(..) | + InstanceDef::ReifyShim(..) | InstanceDef::FnPtrShim(..) | InstanceDef::Virtual(..) | InstanceDef::Intrinsic(..) | @@ -494,6 +505,9 @@ fn merge_codegen_units<'tcx>( for (k, v) in smallest.items_mut().drain() { second_smallest.items_mut().insert(k, v); } + debug!("CodegenUnit {} merged in to CodegenUnit {}", + smallest.name(), + second_smallest.name()); } let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); @@ -664,6 +678,7 @@ fn characteristic_def_id_of_mono_item<'tcx>( let def_id = match instance.def { ty::InstanceDef::Item(def_id) => def_id, ty::InstanceDef::VtableShim(..) | + ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::Intrinsic(..) | @@ -774,18 +789,19 @@ where if cfg!(debug_assertions) { debug!("{}", label); for cgu in cgus { - debug!("CodegenUnit {}:", cgu.name()); + debug!("CodegenUnit {} estimated size {} :", cgu.name(), cgu.size_estimate()); for (mono_item, linkage) in cgu.items() { - let symbol_name = mono_item.symbol_name(tcx).as_str(); + let symbol_name = mono_item.symbol_name(tcx).name.as_str(); let symbol_hash_start = symbol_name.rfind('h'); let symbol_hash = symbol_hash_start.map(|i| &symbol_name[i ..]) .unwrap_or(""); - debug!(" - {} [{:?}] [{}]", + debug!(" - {} [{:?}] [{}] estimated size {}", mono_item.to_string(tcx, true), linkage, - symbol_hash); + symbol_hash, + mono_item.size_estimate(tcx)); } debug!(""); diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 42945c79ddf0e..f532a18072fbd 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -6,7 +6,7 @@ use rustc::ty::layout::VariantIdx; use rustc::ty::subst::{Subst, InternalSubsts}; use rustc::ty::query::Providers; -use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use rustc_index::vec::{IndexVec, Idx}; use rustc_target::spec::abi::Abi; use syntax_pos::{Span, sym}; @@ -66,9 +66,12 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx Some(arg_tys) ) } - ty::InstanceDef::Virtual(def_id, _) => { - // We are generating a call back to our def-id, which the - // codegen backend knows to turn to an actual virtual call. + // We are generating a call back to our def-id, which the + // codegen backend knows to turn to an actual virtual call. + ty::InstanceDef::Virtual(def_id, _) | + // ...or we are generating a direct call to a function for which indirect calls must be + // codegen'd differently than direct ones (example: #[track_caller]) + ty::InstanceDef::ReifyShim(def_id) => { build_call_shim( tcx, def_id, @@ -79,7 +82,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx } ty::InstanceDef::ClosureOnceShim { call_once } => { let fn_mut = tcx.lang_items().fn_mut_trait().unwrap(); - let call_mut = tcx.global_tcx() + let call_mut = tcx .associated_items(fn_mut) .find(|it| it.kind == ty::AssocKind::Method) .unwrap().def_id; @@ -112,7 +115,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx }; debug!("make_shim({:?}) = untransformed {:?}", instance, result); - run_passes(tcx, &mut result, instance, MirPhase::Const, &[ + run_passes(tcx, &mut result, instance, None, MirPhase::Const, &[ &add_moves_for_packed_drops::AddMovesForPackedDrops, &no_landing_pads::NoLandingPads, &remove_noop_landing_pads::RemoveNoopLandingPads, @@ -167,9 +170,9 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty); // Check if this is a generator, if so, return the drop glue for it - if let Some(&ty::TyS { sty: ty::Generator(gen_def_id, substs, _), .. }) = ty { + if let Some(&ty::TyS { kind: ty::Generator(gen_def_id, substs, _), .. }) = ty { let body = &**tcx.optimized_mir(gen_def_id).generator_drop.as_ref().unwrap(); - return body.subst(tcx, substs.substs); + return body.subst(tcx, substs); } let substs = if let Some(ty) = ty { @@ -201,7 +204,6 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) SourceScopeData { span: span, parent_scope: None }, 1 ), ClearCrossCrate::Clear, - IndexVec::new(), None, local_decls_for_sig(&sig, span), IndexVec::new(), @@ -218,7 +220,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) // Function arguments should be retagged, and we make this one raw. body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement { source_info, - kind: StatementKind::Retag(RetagKind::Raw, dropee_ptr.clone()), + kind: StatementKind::Retag(RetagKind::Raw, box(dropee_ptr.clone())), }); } let patch = { @@ -309,10 +311,10 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) - let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty); let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env, builder.span); - let dest = Place::RETURN_PLACE; + let dest = Place::return_place(); let src = Place::from(Local::new(1+0)).deref(); - match self_ty.sty { + match self_ty.kind { _ if is_copy => builder.copy_shim(), ty::Array(ty, len) => { let len = len.eval_usize(tcx, param_env); @@ -321,10 +323,10 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) - ty::Closure(def_id, substs) => { builder.tuple_like_shim( dest, src, - substs.upvar_tys(def_id, tcx) + substs.as_closure().upvar_tys(def_id, tcx) ) } - ty::Tuple(tys) => builder.tuple_like_shim(dest, src, tys.iter().map(|k| k.expect_ty())), + ty::Tuple(..) => builder.tuple_like_shim(dest, src, self_ty.tuple_fields()), _ => { bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty) } @@ -369,7 +371,6 @@ impl CloneShimBuilder<'tcx> { SourceScopeData { span: self.span, parent_scope: None }, 1 ), ClearCrossCrate::Clear, - IndexVec::new(), None, self.local_decls, IndexVec::new(), @@ -417,8 +418,10 @@ impl CloneShimBuilder<'tcx> { let rcvr = Place::from(Local::new(1+0)).deref(); let ret_statement = self.make_statement( StatementKind::Assign( - Place::RETURN_PLACE, - box Rvalue::Use(Operand::Copy(rcvr)) + box( + Place::return_place(), + Rvalue::Use(Operand::Copy(rcvr)) + ) ) ); self.block(vec![ret_statement], TerminatorKind::Return, false); @@ -445,7 +448,6 @@ impl CloneShimBuilder<'tcx> { let func_ty = tcx.mk_fn_def(self.def_id, substs); let func = Operand::Constant(box Constant { span: self.span, - ty: func_ty, user_ty: None, literal: ty::Const::zero_sized(tcx, func_ty), }); @@ -461,8 +463,10 @@ impl CloneShimBuilder<'tcx> { // `let ref_loc: &ty = &src;` let statement = self.make_statement( StatementKind::Assign( - ref_loc.clone(), - box Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src) + box( + ref_loc.clone(), + Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src) + ) ) ); @@ -489,8 +493,10 @@ impl CloneShimBuilder<'tcx> { let cond = self.make_place(Mutability::Mut, tcx.types.bool); let compute_cond = self.make_statement( StatementKind::Assign( - cond.clone(), - box Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg)) + box( + cond.clone(), + Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg)) + ) ) ); @@ -505,7 +511,6 @@ impl CloneShimBuilder<'tcx> { fn make_usize(&self, value: u64) -> Box> { box Constant { span: self.span, - ty: self.tcx.types.usize, user_ty: None, literal: ty::Const::from_usize(self.tcx, value), } @@ -525,14 +530,18 @@ impl CloneShimBuilder<'tcx> { let inits = vec![ self.make_statement( StatementKind::Assign( - Place::from(beg), - box Rvalue::Use(Operand::Constant(self.make_usize(0))) + box( + Place::from(beg), + Rvalue::Use(Operand::Constant(self.make_usize(0))) + ) ) ), self.make_statement( StatementKind::Assign( - end.clone(), - box Rvalue::Use(Operand::Constant(self.make_usize(len))) + box( + end.clone(), + Rvalue::Use(Operand::Constant(self.make_usize(len))) + ) ) ) ]; @@ -563,11 +572,13 @@ impl CloneShimBuilder<'tcx> { let statements = vec![ self.make_statement( StatementKind::Assign( - Place::from(beg), - box Rvalue::BinaryOp( - BinOp::Add, - Operand::Copy(Place::from(beg)), - Operand::Constant(self.make_usize(1)) + box( + Place::from(beg), + Rvalue::BinaryOp( + BinOp::Add, + Operand::Copy(Place::from(beg)), + Operand::Constant(self.make_usize(1)) + ) ) ) ) @@ -586,8 +597,10 @@ impl CloneShimBuilder<'tcx> { let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span)); let init = self.make_statement( StatementKind::Assign( - Place::from(beg), - box Rvalue::Use(Operand::Constant(self.make_usize(0))) + box( + Place::from(beg), + Rvalue::Use(Operand::Constant(self.make_usize(0))) + ) ) ); self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true); @@ -613,11 +626,13 @@ impl CloneShimBuilder<'tcx> { // `goto #6;` let statement = self.make_statement( StatementKind::Assign( - Place::from(beg), - box Rvalue::BinaryOp( - BinOp::Add, - Operand::Copy(Place::from(beg)), - Operand::Constant(self.make_usize(1)) + box( + Place::from(beg), + Rvalue::BinaryOp( + BinOp::Add, + Operand::Copy(Place::from(beg)), + Operand::Constant(self.make_usize(1)) + ) ) ) ); @@ -710,7 +725,7 @@ fn build_call_shim<'tcx>( Adjustment::DerefMove => { // fn(Self, ...) -> fn(*mut Self, ...) let arg_ty = local_decls[rcvr_arg].ty; - assert!(arg_ty.is_self()); + debug_assert!(tcx.generics_of(def_id).has_self && arg_ty == tcx.types.self_param); local_decls[rcvr_arg].ty = tcx.mk_mut_ptr(arg_ty); Operand::Move(rcvr_l.deref()) @@ -731,8 +746,10 @@ fn build_call_shim<'tcx>( statements.push(Statement { source_info, kind: StatementKind::Assign( - Place::from(ref_rcvr), - box Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l) + box( + Place::from(ref_rcvr), + Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l) + ) ) }); Operand::Move(Place::from(ref_rcvr)) @@ -745,7 +762,6 @@ fn build_call_shim<'tcx>( let ty = tcx.type_of(def_id); (Operand::Constant(box Constant { span, - ty, user_ty: None, literal: ty::Const::zero_sized(tcx, ty), }), @@ -778,7 +794,7 @@ fn build_call_shim<'tcx>( block(&mut blocks, statements, TerminatorKind::Call { func: callee, args, - destination: Some((Place::RETURN_PLACE, + destination: Some((Place::return_place(), BasicBlock::new(1))), cleanup: if let Adjustment::RefMut = rcvr_adjustment { Some(BasicBlock::new(3)) @@ -816,7 +832,6 @@ fn build_call_shim<'tcx>( SourceScopeData { span: span, parent_scope: None }, 1 ), ClearCrossCrate::Clear, - IndexVec::new(), None, local_decls, IndexVec::new(), @@ -845,7 +860,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> { .expect("LBR in ADT constructor signature"); let sig = tcx.normalize_erasing_regions(param_env, sig); - let (adt_def, substs) = match sig.output().sty { + let (adt_def, substs) = match sig.output().kind { ty::Adt(adt_def, substs) => (adt_def, substs), _ => bug!("unexpected type for ADT ctor {:?}", sig.output()) }; @@ -874,7 +889,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> { debug!("build_ctor: variant_index={:?}", variant_index); let statements = expand_aggregate( - Place::RETURN_PLACE, + Place::return_place(), adt_def .variants[variant_index] .fields @@ -903,7 +918,6 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> { SourceScopeData { span: span, parent_scope: None }, 1 ), ClearCrossCrate::Clear, - IndexVec::new(), None, local_decls, IndexVec::new(), diff --git a/src/librustc_mir/transform/add_call_guards.rs b/src/librustc_mir/transform/add_call_guards.rs index c08c33bc6ff8b..bf3df1ae2fd84 100644 --- a/src/librustc_mir/transform/add_call_guards.rs +++ b/src/librustc_mir/transform/add_call_guards.rs @@ -1,6 +1,6 @@ use rustc::ty::TyCtxt; use rustc::mir::*; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_index::vec::{Idx, IndexVec}; use crate::transform::{MirPass, MirSource}; #[derive(PartialEq)] @@ -30,8 +30,8 @@ pub use self::AddCallGuards::*; * */ -impl MirPass for AddCallGuards { - fn run_pass<'tcx>(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for AddCallGuards { + fn run_pass(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { self.add_call_guards(body); } } diff --git a/src/librustc_mir/transform/add_moves_for_packed_drops.rs b/src/librustc_mir/transform/add_moves_for_packed_drops.rs index 426e16698d74d..052631ddff371 100644 --- a/src/librustc_mir/transform/add_moves_for_packed_drops.rs +++ b/src/librustc_mir/transform/add_moves_for_packed_drops.rs @@ -39,8 +39,8 @@ use crate::util; pub struct AddMovesForPackedDrops; -impl MirPass for AddMovesForPackedDrops { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for AddMovesForPackedDrops { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { debug!("add_moves_for_packed_drops({:?} @ {:?})", src, body.span); add_moves_for_packed_drops(tcx, body, src.def_id()); } diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs index d573423906c2a..b56a1b263fd6a 100644 --- a/src/librustc_mir/transform/add_retag.rs +++ b/src/librustc_mir/transform/add_retag.rs @@ -17,12 +17,11 @@ pub struct AddRetag; fn is_stable( place: PlaceRef<'_, '_>, ) -> bool { - if let Some(proj) = &place.projection { - match proj.elem { + place.projection.iter().all(|elem| { + match elem { // Which place this evaluates to can change with any memory write, // so cannot assume this to be stable. - ProjectionElem::Deref => - false, + ProjectionElem::Deref => false, // Array indices are intersting, but MIR building generates a *fresh* // temporary for every array access, so the index cannot be changed as // a side-effect. @@ -31,21 +30,14 @@ fn is_stable( ProjectionElem::Field { .. } | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | - ProjectionElem::Downcast { .. } => - is_stable(PlaceRef { - base: place.base, - projection: &proj.base, - }), + ProjectionElem::Downcast { .. } => true, } - } else { - true - } + }) } -/// Determine whether this type may have a reference in it, recursing below compound types but -/// not below references. -fn may_have_reference<'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> bool { - match ty.sty { +/// Determine whether this type may be a reference (or box), and thus needs retagging. +fn may_be_reference<'tcx>(ty: Ty<'tcx>) -> bool { + match ty.kind { // Primitive types that are not references ty::Bool | ty::Char | ty::Float(_) | ty::Int(_) | ty::Uint(_) | @@ -55,22 +47,19 @@ fn may_have_reference<'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> bool { // References ty::Ref(..) => true, ty::Adt(..) if ty.is_box() => true, - // Compound types - ty::Array(ty, ..) | ty::Slice(ty) => - may_have_reference(ty, tcx), - ty::Tuple(tys) => - tys.iter().any(|ty| may_have_reference(ty.expect_ty(), tcx)), - ty::Adt(adt, substs) => - adt.variants.iter().any(|v| v.fields.iter().any(|f| - may_have_reference(f.ty(tcx, substs), tcx) - )), + // Compound types are not references + ty::Array(..) | + ty::Slice(..) | + ty::Tuple(..) | + ty::Adt(..) => + false, // Conservative fallback _ => true, } } -impl MirPass for AddRetag { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for AddRetag { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { if !tcx.sess.opts.debugging_opts.mir_emit_retag { return; } @@ -80,7 +69,7 @@ impl MirPass for AddRetag { // FIXME: Instead of giving up for unstable places, we should introduce // a temporary and retag on that. is_stable(place.as_ref()) - && may_have_reference(place.ty(&*local_decls, tcx).ty, tcx) + && may_be_reference(place.ty(&*local_decls, tcx).ty) }; // PART 1 @@ -100,7 +89,7 @@ impl MirPass for AddRetag { basic_blocks[START_BLOCK].statements.splice(0..0, places.into_iter().map(|place| Statement { source_info, - kind: StatementKind::Retag(RetagKind::FnEntry, place), + kind: StatementKind::Retag(RetagKind::FnEntry, box(place)), }) ); } @@ -136,7 +125,7 @@ impl MirPass for AddRetag { for (source_info, dest_place, dest_block) in returns { basic_blocks[dest_block].statements.insert(0, Statement { source_info, - kind: StatementKind::Retag(RetagKind::Default, dest_place), + kind: StatementKind::Retag(RetagKind::Default, box(dest_place)), }); } @@ -148,11 +137,11 @@ impl MirPass for AddRetag { for i in (0..block_data.statements.len()).rev() { let (retag_kind, place) = match block_data.statements[i].kind { // If we are casting *from* a reference, we may have to retag-as-raw. - StatementKind::Assign(ref place, box Rvalue::Cast( + StatementKind::Assign(box(ref place, Rvalue::Cast( CastKind::Misc, ref src, dest_ty, - )) => { + ))) => { let src_ty = src.ty(&*local_decls, tcx); if src_ty.is_region_ptr() { // The only `Misc` casts on references are those creating raw pointers. @@ -166,7 +155,7 @@ impl MirPass for AddRetag { // Assignments of reference or ptr type are the ones where we may have // to update tags. This includes `x = &[mut] ...` and hence // we also retag after taking a reference! - StatementKind::Assign(ref place, box ref rvalue) if needs_retag(place) => { + StatementKind::Assign(box(ref place, ref rvalue)) if needs_retag(place) => { let kind = match rvalue { Rvalue::Ref(_, borrow_kind, _) if borrow_kind.allows_two_phase_borrow() @@ -184,7 +173,7 @@ impl MirPass for AddRetag { let source_info = block_data.statements[i].source_info; block_data.statements.insert(i+1, Statement { source_info, - kind: StatementKind::Retag(retag_kind, place), + kind: StatementKind::Retag(retag_kind, box(place)), }); } } diff --git a/src/librustc_mir/transform/check_consts/mod.rs b/src/librustc_mir/transform/check_consts/mod.rs new file mode 100644 index 0000000000000..3a959a86edd83 --- /dev/null +++ b/src/librustc_mir/transform/check_consts/mod.rs @@ -0,0 +1,52 @@ +//! Check the bodies of `const`s, `static`s and `const fn`s for illegal operations. +//! +//! This module will eventually replace the parts of `qualify_consts.rs` that check whether a local +//! has interior mutability or needs to be dropped, as well as the visitor that emits errors when +//! it finds operations that are invalid in a certain context. + +use rustc::hir::def_id::DefId; +use rustc::mir; +use rustc::ty::{self, TyCtxt}; + +pub use self::qualifs::Qualif; + +pub mod ops; +mod qualifs; +mod resolver; +pub mod validation; + +/// Information about the item currently being validated, as well as a reference to the global +/// context. +pub struct Item<'mir, 'tcx> { + body: &'mir mir::Body<'tcx>, + tcx: TyCtxt<'tcx>, + def_id: DefId, + param_env: ty::ParamEnv<'tcx>, + mode: validation::Mode, +} + +impl Item<'mir, 'tcx> { + pub fn new( + tcx: TyCtxt<'tcx>, + def_id: DefId, + body: &'mir mir::Body<'tcx>, + ) -> Self { + let param_env = tcx.param_env(def_id); + let mode = validation::Mode::for_item(tcx, def_id) + .expect("const validation must only be run inside a const context"); + + Item { + body, + tcx, + def_id, + param_env, + mode, + } + } +} + + +fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + Some(def_id) == tcx.lang_items().panic_fn() || + Some(def_id) == tcx.lang_items().begin_panic_fn() +} diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs new file mode 100644 index 0000000000000..f457b739949c1 --- /dev/null +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -0,0 +1,339 @@ +//! Concrete error types for all operations which may be invalid in a certain const context. + +use rustc::hir::def_id::DefId; +use rustc::mir::BorrowKind; +use rustc::session::config::nightly_options; +use rustc::ty::TyCtxt; +use syntax::feature_gate::{emit_feature_err, GateIssue}; +use syntax::symbol::sym; +use syntax_pos::{Span, Symbol}; + +use super::Item; +use super::validation::Mode; + +/// An operation that is not *always* allowed in a const context. +pub trait NonConstOp: std::fmt::Debug { + /// Whether this operation can be evaluated by miri. + const IS_SUPPORTED_IN_MIRI: bool = true; + + /// Returns a boolean indicating whether the feature gate that would allow this operation is + /// enabled, or `None` if such a feature gate does not exist. + fn feature_gate(_tcx: TyCtxt<'tcx>) -> Option { + None + } + + /// Returns `true` if this operation is allowed in the given item. + /// + /// This check should assume that we are not in a non-const `fn`, where all operations are + /// legal. + fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool { + Self::feature_gate(item.tcx).unwrap_or(false) + } + + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { + let mut err = struct_span_err!( + item.tcx.sess, + span, + E0019, + "{} contains unimplemented expression type", + item.mode + ); + if item.tcx.sess.teach(&err.get_code().unwrap()) { + err.note("A function call isn't allowed in the const's initialization expression \ + because the expression's value must be known at compile-time."); + err.note("Remember: you can't use a function call inside a const's initialization \ + expression! However, you can use it anywhere else."); + } + err.emit(); + } +} + +/// A `Downcast` projection. +#[derive(Debug)] +pub struct Downcast; +impl NonConstOp for Downcast {} + +/// A function call where the callee is a pointer. +#[derive(Debug)] +pub struct FnCallIndirect; +impl NonConstOp for FnCallIndirect { + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { + let mut err = item.tcx.sess.struct_span_err( + span, + &format!("function pointers are not allowed in const fn")); + err.emit(); + } +} + +/// A function call where the callee is not marked as `const`. +#[derive(Debug)] +pub struct FnCallNonConst(pub DefId); +impl NonConstOp for FnCallNonConst { + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { + let mut err = struct_span_err!( + item.tcx.sess, + span, + E0015, + "calls in {}s are limited to constant functions, \ + tuple structs and tuple variants", + item.mode, + ); + err.emit(); + } +} + +/// A function call where the callee is not a function definition or function pointer, e.g. a +/// closure. +/// +/// This can be subdivided in the future to produce a better error message. +#[derive(Debug)] +pub struct FnCallOther; +impl NonConstOp for FnCallOther { + const IS_SUPPORTED_IN_MIRI: bool = false; +} + +/// A call to a `#[unstable]` const fn or `#[rustc_const_unstable]` function. +/// +/// Contains the name of the feature that would allow the use of this function. +#[derive(Debug)] +pub struct FnCallUnstable(pub DefId, pub Symbol); +impl NonConstOp for FnCallUnstable { + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { + let FnCallUnstable(def_id, feature) = *self; + + let mut err = item.tcx.sess.struct_span_err(span, + &format!("`{}` is not yet stable as a const fn", + item.tcx.def_path_str(def_id))); + if nightly_options::is_nightly_build() { + help!(&mut err, + "add `#![feature({})]` to the \ + crate attributes to enable", + feature); + } + err.emit(); + } +} + +#[derive(Debug)] +pub struct HeapAllocation; +impl NonConstOp for HeapAllocation { + const IS_SUPPORTED_IN_MIRI: bool = false; + + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { + let mut err = struct_span_err!(item.tcx.sess, span, E0010, + "allocations are not allowed in {}s", item.mode); + err.span_label(span, format!("allocation not allowed in {}s", item.mode)); + if item.tcx.sess.teach(&err.get_code().unwrap()) { + err.note( + "The value of statics and constants must be known at compile time, \ + and they live for the entire lifetime of a program. Creating a boxed \ + value allocates memory on the heap at runtime, and therefore cannot \ + be done at compile time." + ); + } + err.emit(); + } +} + +#[derive(Debug)] +pub struct IfOrMatch; +impl NonConstOp for IfOrMatch {} + +#[derive(Debug)] +pub struct LiveDrop; +impl NonConstOp for LiveDrop { + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { + struct_span_err!(item.tcx.sess, span, E0493, + "destructors cannot be evaluated at compile-time") + .span_label(span, format!("{}s cannot evaluate destructors", + item.mode)) + .emit(); + } +} + +#[derive(Debug)] +pub struct Loop; +impl NonConstOp for Loop {} + +#[derive(Debug)] +pub struct MutBorrow(pub BorrowKind); +impl NonConstOp for MutBorrow { + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { + let kind = self.0; + if let BorrowKind::Mut { .. } = kind { + let mut err = struct_span_err!(item.tcx.sess, span, E0017, + "references in {}s may only refer \ + to immutable values", item.mode); + err.span_label(span, format!("{}s require immutable values", + item.mode)); + if item.tcx.sess.teach(&err.get_code().unwrap()) { + err.note("References in statics and constants may only refer \ + to immutable values.\n\n\ + Statics are shared everywhere, and if they refer to \ + mutable data one might violate memory safety since \ + holding multiple mutable references to shared data \ + is not allowed.\n\n\ + If you really want global mutable state, try using \ + static mut or a global UnsafeCell."); + } + err.emit(); + } else { + span_err!(item.tcx.sess, span, E0492, + "cannot borrow a constant which may contain \ + interior mutability, create a static instead"); + } + } +} + +#[derive(Debug)] +pub struct MutDeref; +impl NonConstOp for MutDeref {} + +#[derive(Debug)] +pub struct Panic; +impl NonConstOp for Panic { + fn feature_gate(tcx: TyCtxt<'_>) -> Option { + Some(tcx.features().const_panic) + } + + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { + emit_feature_err( + &item.tcx.sess.parse_sess, + sym::const_panic, + span, + GateIssue::Language, + &format!("panicking in {}s is unstable", item.mode), + ); + } +} + +#[derive(Debug)] +pub struct RawPtrComparison; +impl NonConstOp for RawPtrComparison { + fn feature_gate(tcx: TyCtxt<'_>) -> Option { + Some(tcx.features().const_compare_raw_pointers) + } + + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { + emit_feature_err( + &item.tcx.sess.parse_sess, + sym::const_compare_raw_pointers, + span, + GateIssue::Language, + &format!("comparing raw pointers inside {}", item.mode), + ); + } +} + +#[derive(Debug)] +pub struct RawPtrDeref; +impl NonConstOp for RawPtrDeref { + fn feature_gate(tcx: TyCtxt<'_>) -> Option { + Some(tcx.features().const_raw_ptr_deref) + } + + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { + emit_feature_err( + &item.tcx.sess.parse_sess, sym::const_raw_ptr_deref, + span, GateIssue::Language, + &format!( + "dereferencing raw pointers in {}s is unstable", + item.mode, + ), + ); + } +} + +#[derive(Debug)] +pub struct RawPtrToIntCast; +impl NonConstOp for RawPtrToIntCast { + fn feature_gate(tcx: TyCtxt<'_>) -> Option { + Some(tcx.features().const_raw_ptr_to_usize_cast) + } + + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { + emit_feature_err( + &item.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast, + span, GateIssue::Language, + &format!( + "casting pointers to integers in {}s is unstable", + item.mode, + ), + ); + } +} + +/// An access to a (non-thread-local) `static`. +#[derive(Debug)] +pub struct StaticAccess; +impl NonConstOp for StaticAccess { + fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool { + item.mode.is_static() + } + + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { + let mut err = struct_span_err!(item.tcx.sess, span, E0013, + "{}s cannot refer to statics, use \ + a constant instead", item.mode); + if item.tcx.sess.teach(&err.get_code().unwrap()) { + err.note( + "Static and const variables can refer to other const variables. \ + But a const variable cannot refer to a static variable." + ); + err.help( + "To fix this, the value can be extracted as a const and then used." + ); + } + err.emit(); + } +} + +/// An access to a thread-local `static`. +#[derive(Debug)] +pub struct ThreadLocalAccess; +impl NonConstOp for ThreadLocalAccess { + const IS_SUPPORTED_IN_MIRI: bool = false; + + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { + span_err!(item.tcx.sess, span, E0625, + "thread-local statics cannot be \ + accessed at compile-time"); + } +} + +#[derive(Debug)] +pub struct Transmute; +impl NonConstOp for Transmute { + fn feature_gate(tcx: TyCtxt<'_>) -> Option { + Some(tcx.features().const_transmute) + } + + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { + emit_feature_err( + &item.tcx.sess.parse_sess, sym::const_transmute, + span, GateIssue::Language, + &format!("The use of std::mem::transmute() \ + is gated in {}s", item.mode)); + } +} + +#[derive(Debug)] +pub struct UnionAccess; +impl NonConstOp for UnionAccess { + fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool { + // Union accesses are stable in all contexts except `const fn`. + item.mode != Mode::ConstFn || Self::feature_gate(item.tcx).unwrap() + } + + fn feature_gate(tcx: TyCtxt<'_>) -> Option { + Some(tcx.features().const_fn_union) + } + + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { + emit_feature_err( + &item.tcx.sess.parse_sess, sym::const_fn_union, + span, GateIssue::Language, + "unions in const fn are unstable", + ); + } +} diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs new file mode 100644 index 0000000000000..40007eb3c4a3e --- /dev/null +++ b/src/librustc_mir/transform/check_consts/qualifs.rs @@ -0,0 +1,289 @@ +//! A copy of the `Qualif` trait in `qualify_consts.rs` that is suitable for the new validator. + +use rustc::mir::*; +use rustc::mir::interpret::ConstValue; +use rustc::ty::{self, Ty}; +use rustc_index::bit_set::BitSet; +use syntax_pos::DUMMY_SP; + +use super::Item as ConstCx; +use super::validation::Mode; + +#[derive(Clone, Copy)] +pub struct QualifSet(u8); + +impl QualifSet { + fn contains(self) -> bool { + self.0 & (1 << Q::IDX) != 0 + } +} + +/// A "qualif"(-ication) is a way to look for something "bad" in the MIR that would disqualify some +/// code for promotion or prevent it from evaluating at compile time. So `return true` means +/// "I found something bad, no reason to go on searching". `false` is only returned if we +/// definitely cannot find anything bad anywhere. +/// +/// The default implementations proceed structurally. +pub trait Qualif { + const IDX: usize; + + /// The name of the file used to debug the dataflow analysis that computes this qualif. + const ANALYSIS_NAME: &'static str; + + /// Whether this `Qualif` is cleared when a local is moved from. + const IS_CLEARED_ON_MOVE: bool = false; + + /// Return the qualification that is (conservatively) correct for any value + /// of the type. + fn in_any_value_of_ty(_cx: &ConstCx<'_, 'tcx>, _ty: Ty<'tcx>) -> bool; + + fn in_static(_cx: &ConstCx<'_, 'tcx>, _static: &Static<'tcx>) -> bool { + // FIXME(eddyb) should we do anything here for value properties? + false + } + + fn in_projection_structurally( + cx: &ConstCx<'_, 'tcx>, + per_local: &BitSet, + place: PlaceRef<'_, 'tcx>, + ) -> bool { + if let [proj_base @ .., elem] = place.projection { + let base_qualif = Self::in_place(cx, per_local, PlaceRef { + base: place.base, + projection: proj_base, + }); + let qualif = base_qualif && Self::in_any_value_of_ty( + cx, + Place::ty_from(place.base, proj_base, cx.body, cx.tcx) + .projection_ty(cx.tcx, elem) + .ty, + ); + match elem { + ProjectionElem::Deref | + ProjectionElem::Subslice { .. } | + ProjectionElem::Field(..) | + ProjectionElem::ConstantIndex { .. } | + ProjectionElem::Downcast(..) => qualif, + + ProjectionElem::Index(local) => qualif || per_local.contains(*local), + } + } else { + bug!("This should be called if projection is not empty"); + } + } + + fn in_projection( + cx: &ConstCx<'_, 'tcx>, + per_local: &BitSet, + place: PlaceRef<'_, 'tcx>, + ) -> bool { + Self::in_projection_structurally(cx, per_local, place) + } + + fn in_place( + cx: &ConstCx<'_, 'tcx>, + per_local: &BitSet, + place: PlaceRef<'_, 'tcx>, + ) -> bool { + match place { + PlaceRef { + base: PlaceBase::Local(local), + projection: [], + } => per_local.contains(*local), + PlaceRef { + base: PlaceBase::Static(box Static { + kind: StaticKind::Promoted(..), + .. + }), + projection: [], + } => bug!("qualifying already promoted MIR"), + PlaceRef { + base: PlaceBase::Static(static_), + projection: [], + } => { + Self::in_static(cx, static_) + }, + PlaceRef { + base: _, + projection: [.., _], + } => Self::in_projection(cx, per_local, place), + } + } + + fn in_operand( + cx: &ConstCx<'_, 'tcx>, + per_local: &BitSet, + operand: &Operand<'tcx>, + ) -> bool { + match *operand { + Operand::Copy(ref place) | + Operand::Move(ref place) => Self::in_place(cx, per_local, place.as_ref()), + + Operand::Constant(ref constant) => { + if let ConstValue::Unevaluated(def_id, _) = constant.literal.val { + // Don't peek inside trait associated constants. + if cx.tcx.trait_of_item(def_id).is_some() { + Self::in_any_value_of_ty(cx, constant.literal.ty) + } else { + let (bits, _) = cx.tcx.at(constant.span).mir_const_qualif(def_id); + + let qualif = QualifSet(bits).contains::(); + + // Just in case the type is more specific than + // the definition, e.g., impl associated const + // with type parameters, take it into account. + qualif && Self::in_any_value_of_ty(cx, constant.literal.ty) + } + } else { + false + } + } + } + } + + fn in_rvalue_structurally( + cx: &ConstCx<'_, 'tcx>, + per_local: &BitSet, + rvalue: &Rvalue<'tcx>, + ) -> bool { + match *rvalue { + Rvalue::NullaryOp(..) => false, + + Rvalue::Discriminant(ref place) | + Rvalue::Len(ref place) => Self::in_place(cx, per_local, place.as_ref()), + + Rvalue::Use(ref operand) | + Rvalue::Repeat(ref operand, _) | + Rvalue::UnaryOp(_, ref operand) | + Rvalue::Cast(_, ref operand, _) => Self::in_operand(cx, per_local, operand), + + Rvalue::BinaryOp(_, ref lhs, ref rhs) | + Rvalue::CheckedBinaryOp(_, ref lhs, ref rhs) => { + Self::in_operand(cx, per_local, lhs) || Self::in_operand(cx, per_local, rhs) + } + + Rvalue::Ref(_, _, ref place) => { + // Special-case reborrows to be more like a copy of the reference. + if let box [proj_base @ .., elem] = &place.projection { + if ProjectionElem::Deref == *elem { + let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty; + if let ty::Ref(..) = base_ty.kind { + return Self::in_place(cx, per_local, PlaceRef { + base: &place.base, + projection: proj_base, + }); + } + } + } + + Self::in_place(cx, per_local, place.as_ref()) + } + + Rvalue::Aggregate(_, ref operands) => { + operands.iter().any(|o| Self::in_operand(cx, per_local, o)) + } + } + } + + fn in_rvalue(cx: &ConstCx<'_, 'tcx>, per_local: &BitSet, rvalue: &Rvalue<'tcx>) -> bool { + Self::in_rvalue_structurally(cx, per_local, rvalue) + } + + fn in_call( + cx: &ConstCx<'_, 'tcx>, + _per_local: &BitSet, + _callee: &Operand<'tcx>, + _args: &[Operand<'tcx>], + return_ty: Ty<'tcx>, + ) -> bool { + // Be conservative about the returned value of a const fn. + Self::in_any_value_of_ty(cx, return_ty) + } +} + +/// Constant containing interior mutability (`UnsafeCell`). +/// This must be ruled out to make sure that evaluating the constant at compile-time +/// and at *any point* during the run-time would produce the same result. In particular, +/// promotion of temporaries must not change program behavior; if the promoted could be +/// written to, that would be a problem. +pub struct HasMutInterior; + +impl Qualif for HasMutInterior { + const IDX: usize = 0; + const ANALYSIS_NAME: &'static str = "flow_has_mut_interior"; + + fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { + !ty.is_freeze(cx.tcx, cx.param_env, DUMMY_SP) + } + + fn in_rvalue(cx: &ConstCx<'_, 'tcx>, per_local: &BitSet, rvalue: &Rvalue<'tcx>) -> bool { + match *rvalue { + // Returning `true` for `Rvalue::Ref` indicates the borrow isn't + // allowed in constants (and the `Checker` will error), and/or it + // won't be promoted, due to `&mut ...` or interior mutability. + Rvalue::Ref(_, kind, ref place) => { + let ty = place.ty(cx.body, cx.tcx).ty; + + if let BorrowKind::Mut { .. } = kind { + // In theory, any zero-sized value could be borrowed + // mutably without consequences. + match ty.kind { + // Inside a `static mut`, &mut [...] is also allowed. + ty::Array(..) | ty::Slice(_) if cx.mode == Mode::StaticMut => {}, + + // FIXME(ecstaticmorse): uncomment the following match arm to stop marking + // `&mut []` as `HasMutInterior`. + /* + ty::Array(_, len) if len.try_eval_usize(cx.tcx, cx.param_env) == Some(0) + => {}, + */ + + _ => return true, + } + } + } + + Rvalue::Aggregate(ref kind, _) => { + if let AggregateKind::Adt(def, ..) = **kind { + if Some(def.did) == cx.tcx.lang_items().unsafe_cell_type() { + let ty = rvalue.ty(cx.body, cx.tcx); + assert_eq!(Self::in_any_value_of_ty(cx, ty), true); + return true; + } + } + } + + _ => {} + } + + Self::in_rvalue_structurally(cx, per_local, rvalue) + } +} + +/// Constant containing an ADT that implements `Drop`. +/// This must be ruled out (a) because we cannot run `Drop` during compile-time +/// as that might not be a `const fn`, and (b) because implicit promotion would +/// remove side-effects that occur as part of dropping that value. +pub struct NeedsDrop; + +impl Qualif for NeedsDrop { + const IDX: usize = 1; + const ANALYSIS_NAME: &'static str = "flow_needs_drop"; + const IS_CLEARED_ON_MOVE: bool = true; + + fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { + ty.needs_drop(cx.tcx, cx.param_env) + } + + fn in_rvalue(cx: &ConstCx<'_, 'tcx>, per_local: &BitSet, rvalue: &Rvalue<'tcx>) -> bool { + if let Rvalue::Aggregate(ref kind, _) = *rvalue { + if let AggregateKind::Adt(def, ..) = **kind { + if def.has_dtor(cx.tcx) { + return true; + } + } + } + + Self::in_rvalue_structurally(cx, per_local, rvalue) + } +} diff --git a/src/librustc_mir/transform/check_consts/resolver.rs b/src/librustc_mir/transform/check_consts/resolver.rs new file mode 100644 index 0000000000000..4fa4eba4c23b6 --- /dev/null +++ b/src/librustc_mir/transform/check_consts/resolver.rs @@ -0,0 +1,350 @@ +//! Propagate `Qualif`s between locals and query the results. +//! +//! This also contains the dataflow analysis used to track `Qualif`s on complex control-flow +//! graphs. + +use rustc::mir::visit::Visitor; +use rustc::mir::{self, BasicBlock, Local, Location}; +use rustc_index::bit_set::BitSet; + +use std::cell::RefCell; +use std::marker::PhantomData; + +use crate::dataflow::{self as old_dataflow, generic as dataflow}; +use super::{Item, Qualif}; +use self::old_dataflow::IndirectlyMutableLocals; + +/// A `Visitor` that propagates qualifs between locals. This defines the transfer function of +/// `FlowSensitiveAnalysis` as well as the logic underlying `TempPromotionResolver`. +/// +/// This transfer does nothing when encountering an indirect assignment. Consumers should rely on +/// the `IndirectlyMutableLocals` dataflow pass to see if a `Local` may have become qualified via +/// an indirect assignment or function call. +struct TransferFunction<'a, 'mir, 'tcx, Q> { + item: &'a Item<'mir, 'tcx>, + qualifs_per_local: &'a mut BitSet, + + _qualif: PhantomData, +} + +impl TransferFunction<'a, 'mir, 'tcx, Q> +where + Q: Qualif, +{ + fn new( + item: &'a Item<'mir, 'tcx>, + qualifs_per_local: &'a mut BitSet, + ) -> Self { + TransferFunction { + item, + qualifs_per_local, + _qualif: PhantomData, + } + } + + fn initialize_state(&mut self) { + self.qualifs_per_local.clear(); + + for arg in self.item.body.args_iter() { + let arg_ty = self.item.body.local_decls[arg].ty; + if Q::in_any_value_of_ty(self.item, arg_ty) { + self.qualifs_per_local.insert(arg); + } + } + } + + fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) { + debug_assert!(!place.is_indirect()); + + match (value, place) { + (true, mir::Place { base: mir::PlaceBase::Local(local), .. }) => { + self.qualifs_per_local.insert(*local); + } + + // For now, we do not clear the qualif if a local is overwritten in full by + // an unqualified rvalue (e.g. `y = 5`). This is to be consistent + // with aggregates where we overwrite all fields with assignments, which would not + // get this feature. + (false, mir::Place { base: mir::PlaceBase::Local(_local), projection: box [] }) => { + // self.qualifs_per_local.remove(*local); + } + + _ => {} + } + } + + fn apply_call_return_effect( + &mut self, + _block: BasicBlock, + func: &mir::Operand<'tcx>, + args: &[mir::Operand<'tcx>], + return_place: &mir::Place<'tcx>, + ) { + let return_ty = return_place.ty(self.item.body, self.item.tcx).ty; + let qualif = Q::in_call(self.item, &mut self.qualifs_per_local, func, args, return_ty); + if !return_place.is_indirect() { + self.assign_qualif_direct(return_place, qualif); + } + } +} + +impl Visitor<'tcx> for TransferFunction<'_, '_, 'tcx, Q> +where + Q: Qualif, +{ + fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) { + self.super_operand(operand, location); + + if !Q::IS_CLEARED_ON_MOVE { + return; + } + + // If a local with no projections is moved from (e.g. `x` in `y = x`), record that + // it no longer needs to be dropped. + if let mir::Operand::Move(mir::Place { + base: mir::PlaceBase::Local(local), + projection: box [], + }) = *operand { + self.qualifs_per_local.remove(local); + } + } + + fn visit_assign( + &mut self, + place: &mir::Place<'tcx>, + rvalue: &mir::Rvalue<'tcx>, + location: Location, + ) { + let qualif = Q::in_rvalue(self.item, self.qualifs_per_local, rvalue); + if !place.is_indirect() { + self.assign_qualif_direct(place, qualif); + } + + // We need to assign qualifs to the left-hand side before visiting `rvalue` since + // qualifs can be cleared on move. + self.super_assign(place, rvalue, location); + } + + fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location: Location) { + // The effect of assignment to the return place in `TerminatorKind::Call` is not applied + // here; that occurs in `apply_call_return_effect`. + + if let mir::TerminatorKind::DropAndReplace { value, location: dest, .. } = kind { + let qualif = Q::in_operand(self.item, self.qualifs_per_local, value); + if !dest.is_indirect() { + self.assign_qualif_direct(dest, qualif); + } + } + + // We need to assign qualifs to the dropped location before visiting the operand that + // replaces it since qualifs can be cleared on move. + self.super_terminator_kind(kind, location); + } +} + +/// Types that can compute the qualifs of each local at each location in a `mir::Body`. +/// +/// Code that wishes to use a `QualifResolver` must call `visit_{statement,terminator}` for each +/// statement or terminator, processing blocks in reverse post-order beginning from the +/// `START_BLOCK`. Calling code may optionally call `get` after visiting each statement or +/// terminator to query the qualification state immediately before that statement or terminator. +/// +/// These conditions are much more restrictive than woud be required by `FlowSensitiveResolver` +/// alone. This is to allow a linear, on-demand `TempPromotionResolver` that can operate +/// efficiently on simple CFGs. +pub trait QualifResolver { + /// Get the qualifs of each local at the last location visited. + /// + /// This takes `&mut self` so qualifs can be computed lazily. + fn get(&mut self) -> &BitSet; + + /// A convenience method for `self.get().contains(local)`. + fn contains(&mut self, local: Local) -> bool { + self.get().contains(local) + } + + /// Resets the resolver to the `START_BLOCK`. This allows a resolver to be reused + /// for multiple passes over a `mir::Body`. + fn reset(&mut self); +} + +pub type IndirectlyMutableResults<'mir, 'tcx> = + old_dataflow::DataflowResultsCursor<'mir, 'tcx, IndirectlyMutableLocals<'mir, 'tcx>>; + +/// A resolver for qualifs that works on arbitrarily complex CFGs. +/// +/// As soon as a `Local` becomes writable through a reference (as determined by the +/// `IndirectlyMutableLocals` dataflow pass), we must assume that it takes on all other qualifs +/// possible for its type. This is because no effort is made to track qualifs across indirect +/// assignments (e.g. `*p = x` or calls to opaque functions). +/// +/// It is possible to be more precise here by waiting until an indirect assignment actually occurs +/// before marking a borrowed `Local` as qualified. +pub struct FlowSensitiveResolver<'a, 'mir, 'tcx, Q> +where + Q: Qualif, +{ + location: Location, + indirectly_mutable_locals: &'a RefCell>, + cursor: dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>>, + qualifs_per_local: BitSet, + + /// The value of `Q::in_any_value_of_ty` for each local. + qualifs_in_any_value_of_ty: BitSet, +} + +impl FlowSensitiveResolver<'a, 'mir, 'tcx, Q> +where + Q: Qualif, +{ + pub fn new( + _: Q, + item: &'a Item<'mir, 'tcx>, + indirectly_mutable_locals: &'a RefCell>, + dead_unwinds: &BitSet, + ) -> Self { + let analysis = FlowSensitiveAnalysis { + item, + _qualif: PhantomData, + }; + let results = + dataflow::Engine::new(item.tcx, item.body, item.def_id, dead_unwinds, analysis) + .iterate_to_fixpoint(); + let cursor = dataflow::ResultsCursor::new(item.body, results); + + let mut qualifs_in_any_value_of_ty = BitSet::new_empty(item.body.local_decls.len()); + for (local, decl) in item.body.local_decls.iter_enumerated() { + if Q::in_any_value_of_ty(item, decl.ty) { + qualifs_in_any_value_of_ty.insert(local); + } + } + + FlowSensitiveResolver { + cursor, + indirectly_mutable_locals, + qualifs_per_local: BitSet::new_empty(item.body.local_decls.len()), + qualifs_in_any_value_of_ty, + location: Location { block: mir::START_BLOCK, statement_index: 0 }, + } + } +} + +impl Visitor<'tcx> for FlowSensitiveResolver<'_, '_, 'tcx, Q> +where + Q: Qualif +{ + fn visit_statement(&mut self, _: &mir::Statement<'tcx>, location: Location) { + self.location = location; + } + + fn visit_terminator(&mut self, _: &mir::Terminator<'tcx>, location: Location) { + self.location = location; + } +} + +impl QualifResolver for FlowSensitiveResolver<'_, '_, '_, Q> +where + Q: Qualif +{ + fn get(&mut self) -> &BitSet { + let mut indirectly_mutable_locals = self.indirectly_mutable_locals.borrow_mut(); + + indirectly_mutable_locals.seek(self.location); + self.cursor.seek_before(self.location); + + self.qualifs_per_local.overwrite(indirectly_mutable_locals.get()); + self.qualifs_per_local.union(self.cursor.get()); + self.qualifs_per_local.intersect(&self.qualifs_in_any_value_of_ty); + &self.qualifs_per_local + } + + fn contains(&mut self, local: Local) -> bool { + // No need to update the cursor if we know that `Local` cannot possibly be qualified. + if !self.qualifs_in_any_value_of_ty.contains(local) { + return false; + } + + // Otherwise, return `true` if this local is qualified or was indirectly mutable at any + // point before this statement. + self.cursor.seek_before(self.location); + if self.cursor.get().contains(local) { + return true; + } + + let mut indirectly_mutable_locals = self.indirectly_mutable_locals.borrow_mut(); + indirectly_mutable_locals.seek(self.location); + indirectly_mutable_locals.get().contains(local) + } + + fn reset(&mut self) { + self.location = Location { block: mir::START_BLOCK, statement_index: 0 }; + } +} + +/// The dataflow analysis used to propagate qualifs on arbitrary CFGs. +pub(super) struct FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q> { + item: &'a Item<'mir, 'tcx>, + _qualif: PhantomData, +} + +impl<'a, 'mir, 'tcx, Q> FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q> +where + Q: Qualif, +{ + fn transfer_function( + &self, + state: &'a mut BitSet, + ) -> TransferFunction<'a, 'mir, 'tcx, Q> { + TransferFunction::::new(self.item, state) + } +} + +impl old_dataflow::BottomValue for FlowSensitiveAnalysis<'_, '_, '_, Q> { + const BOTTOM_VALUE: bool = false; +} + +impl dataflow::Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q> +where + Q: Qualif, +{ + type Idx = Local; + + const NAME: &'static str = Q::ANALYSIS_NAME; + + fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { + body.local_decls.len() + } + + fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut BitSet) { + self.transfer_function(state).initialize_state(); + } + + fn apply_statement_effect( + &self, + state: &mut BitSet, + statement: &mir::Statement<'tcx>, + location: Location, + ) { + self.transfer_function(state).visit_statement(statement, location); + } + + fn apply_terminator_effect( + &self, + state: &mut BitSet, + terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + self.transfer_function(state).visit_terminator(terminator, location); + } + + fn apply_call_return_effect( + &self, + state: &mut BitSet, + block: BasicBlock, + func: &mir::Operand<'tcx>, + args: &[mir::Operand<'tcx>], + return_place: &mir::Place<'tcx>, + ) { + self.transfer_function(state).apply_call_return_effect(block, func, args, return_place) + } +} diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs new file mode 100644 index 0000000000000..87cd39b02cd97 --- /dev/null +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -0,0 +1,593 @@ +//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations. + +use rustc::hir::{self, def_id::DefId}; +use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext}; +use rustc::mir::*; +use rustc::ty::cast::CastTy; +use rustc::ty::{self, TyCtxt}; +use rustc_index::bit_set::BitSet; +use rustc_target::spec::abi::Abi; +use syntax::symbol::sym; +use syntax_pos::Span; + +use std::cell::RefCell; +use std::fmt; +use std::ops::Deref; + +use crate::dataflow as old_dataflow; +use super::{Item, Qualif, is_lang_panic_fn}; +use super::resolver::{FlowSensitiveResolver, IndirectlyMutableResults, QualifResolver}; +use super::qualifs::{HasMutInterior, NeedsDrop}; +use super::ops::{self, NonConstOp}; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum CheckOpResult { + Forbidden, + Unleashed, + Allowed, +} + +/// What kind of item we are in. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Mode { + /// A `static` item. + Static, + /// A `static mut` item. + StaticMut, + /// A `const fn` item. + ConstFn, + /// A `const` item or an anonymous constant (e.g. in array lengths). + Const, +} + +impl Mode { + /// Returns the validation mode for the item with the given `DefId`, or `None` if this item + /// does not require validation (e.g. a non-const `fn`). + pub fn for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option { + use hir::BodyOwnerKind as HirKind; + + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + + let mode = match tcx.hir().body_owner_kind(hir_id) { + HirKind::Closure => return None, + + HirKind::Fn if tcx.is_const_fn(def_id) => Mode::ConstFn, + HirKind::Fn => return None, + + HirKind::Const => Mode::Const, + + HirKind::Static(hir::MutImmutable) => Mode::Static, + HirKind::Static(hir::MutMutable) => Mode::StaticMut, + }; + + Some(mode) + } + + pub fn is_static(self) -> bool { + match self { + Mode::Static | Mode::StaticMut => true, + Mode::ConstFn | Mode::Const => false, + } + } + + /// Returns `true` if the value returned by this item must be `Sync`. + /// + /// This returns false for `StaticMut` since all accesses to one are `unsafe` anyway. + pub fn requires_sync(self) -> bool { + match self { + Mode::Static => true, + Mode::ConstFn | Mode::Const | Mode::StaticMut => false, + } + } +} + +impl fmt::Display for Mode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Mode::Const => write!(f, "constant"), + Mode::Static | Mode::StaticMut => write!(f, "static"), + Mode::ConstFn => write!(f, "constant function"), + } + } +} + +pub struct Qualifs<'a, 'mir, 'tcx> { + has_mut_interior: FlowSensitiveResolver<'a, 'mir, 'tcx, HasMutInterior>, + needs_drop: FlowSensitiveResolver<'a, 'mir, 'tcx, NeedsDrop>, +} + +pub struct Validator<'a, 'mir, 'tcx> { + item: &'a Item<'mir, 'tcx>, + qualifs: Qualifs<'a, 'mir, 'tcx>, + + /// The span of the current statement. + span: Span, + + /// True if the local was assigned the result of an illegal borrow (`ops::MutBorrow`). + /// + /// This is used to hide errors from {re,}borrowing the newly-assigned local, instead pointing + /// the user to the place where the illegal borrow occurred. This set is only populated once an + /// error has been emitted, so it will never cause an erroneous `mir::Body` to pass validation. + /// + /// FIXME(ecstaticmorse): assert at the end of checking that if `tcx.has_errors() == false`, + /// this set is empty. Note that if we start removing locals from + /// `derived_from_illegal_borrow`, just checking at the end won't be enough. + derived_from_illegal_borrow: BitSet, + + errors: Vec<(Span, String)>, + + /// Whether to actually emit errors or just store them in `errors`. + pub(crate) suppress_errors: bool, +} + +impl Deref for Validator<'_, 'mir, 'tcx> { + type Target = Item<'mir, 'tcx>; + + fn deref(&self) -> &Self::Target { + &self.item + } +} + +pub fn compute_indirectly_mutable_locals<'mir, 'tcx>( + item: &Item<'mir, 'tcx>, +) -> RefCell> { + let dead_unwinds = BitSet::new_empty(item.body.basic_blocks().len()); + + let indirectly_mutable_locals = old_dataflow::do_dataflow( + item.tcx, + item.body, + item.def_id, + &item.tcx.get_attrs(item.def_id), + &dead_unwinds, + old_dataflow::IndirectlyMutableLocals::new(item.tcx, item.body, item.param_env), + |_, local| old_dataflow::DebugFormatted::new(&local), + ); + + let indirectly_mutable_locals = old_dataflow::DataflowResultsCursor::new( + indirectly_mutable_locals, + item.body, + ); + + RefCell::new(indirectly_mutable_locals) +} + +impl Validator<'a, 'mir, 'tcx> { + pub fn new( + item: &'a Item<'mir, 'tcx>, + indirectly_mutable_locals: &'a RefCell>, + ) -> Self { + let dead_unwinds = BitSet::new_empty(item.body.basic_blocks().len()); + + let needs_drop = FlowSensitiveResolver::new( + NeedsDrop, + item, + indirectly_mutable_locals, + &dead_unwinds, + ); + + let has_mut_interior = FlowSensitiveResolver::new( + HasMutInterior, + item, + indirectly_mutable_locals, + &dead_unwinds, + ); + + let qualifs = Qualifs { + needs_drop, + has_mut_interior, + }; + + Validator { + span: item.body.span, + item, + qualifs, + errors: vec![], + derived_from_illegal_borrow: BitSet::new_empty(item.body.local_decls.len()), + suppress_errors: false, + } + } + + /// Resets the `QualifResolver`s used by this `Validator` and returns them so they can be + /// reused. + pub fn into_qualifs(mut self) -> Qualifs<'a, 'mir, 'tcx> { + self.qualifs.needs_drop.reset(); + self.qualifs.has_mut_interior.reset(); + self.qualifs + } + + pub fn take_errors(&mut self) -> Vec<(Span, String)> { + std::mem::replace(&mut self.errors, vec![]) + } + + /// Emits an error at the given `span` if an expression cannot be evaluated in the current + /// context. Returns `Forbidden` if an error was emitted. + pub fn check_op_spanned(&mut self, op: O, span: Span) -> CheckOpResult + where + O: NonConstOp + fmt::Debug + { + trace!("check_op: op={:?}", op); + + if op.is_allowed_in_item(self) { + return CheckOpResult::Allowed; + } + + // If an operation is supported in miri (and is not already controlled by a feature gate) it + // can be turned on with `-Zunleash-the-miri-inside-of-you`. + let is_unleashable = O::IS_SUPPORTED_IN_MIRI + && O::feature_gate(self.tcx).is_none(); + + if is_unleashable && self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { + self.tcx.sess.span_warn(span, "skipping const checks"); + return CheckOpResult::Unleashed; + } + + if !self.suppress_errors { + op.emit_error(self, span); + } + + self.errors.push((span, format!("{:?}", op))); + CheckOpResult::Forbidden + } + + /// Emits an error if an expression cannot be evaluated in the current context. + pub fn check_op(&mut self, op: impl NonConstOp + fmt::Debug) -> CheckOpResult { + let span = self.span; + self.check_op_spanned(op, span) + } +} + +impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location); + + // Check nested operands and places. + if let Rvalue::Ref(_, kind, ref place) = *rvalue { + // Special-case reborrows to be more like a copy of a reference. + let mut reborrow_place = None; + if let box [proj_base @ .., elem] = &place.projection { + if *elem == ProjectionElem::Deref { + let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty; + if let ty::Ref(..) = base_ty.kind { + reborrow_place = Some(proj_base); + } + } + } + + if let Some(proj) = reborrow_place { + let ctx = match kind { + BorrowKind::Shared => PlaceContext::NonMutatingUse( + NonMutatingUseContext::SharedBorrow, + ), + BorrowKind::Shallow => PlaceContext::NonMutatingUse( + NonMutatingUseContext::ShallowBorrow, + ), + BorrowKind::Unique => PlaceContext::NonMutatingUse( + NonMutatingUseContext::UniqueBorrow, + ), + BorrowKind::Mut { .. } => PlaceContext::MutatingUse( + MutatingUseContext::Borrow, + ), + }; + self.visit_place_base(&place.base, ctx, location); + self.visit_projection(&place.base, proj, ctx, location); + } else { + self.super_rvalue(rvalue, location); + } + } else { + self.super_rvalue(rvalue, location); + } + + match *rvalue { + Rvalue::Use(_) | + Rvalue::Repeat(..) | + Rvalue::UnaryOp(UnOp::Neg, _) | + Rvalue::UnaryOp(UnOp::Not, _) | + Rvalue::NullaryOp(NullOp::SizeOf, _) | + Rvalue::CheckedBinaryOp(..) | + Rvalue::Cast(CastKind::Pointer(_), ..) | + Rvalue::Discriminant(..) | + Rvalue::Len(_) | + Rvalue::Ref(..) | + Rvalue::Aggregate(..) => {} + + Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { + let operand_ty = operand.ty(self.body, self.tcx); + let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); + let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); + + if let (CastTy::Ptr(_), CastTy::Int(_)) + | (CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { + self.check_op(ops::RawPtrToIntCast); + } + } + + Rvalue::BinaryOp(op, ref lhs, _) => { + if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind { + assert!(op == BinOp::Eq || op == BinOp::Ne || + op == BinOp::Le || op == BinOp::Lt || + op == BinOp::Ge || op == BinOp::Gt || + op == BinOp::Offset); + + + self.check_op(ops::RawPtrComparison); + } + } + + Rvalue::NullaryOp(NullOp::Box, _) => { + self.check_op(ops::HeapAllocation); + } + } + } + + fn visit_place_base( + &mut self, + place_base: &PlaceBase<'tcx>, + context: PlaceContext, + location: Location, + ) { + trace!( + "visit_place_base: place_base={:?} context={:?} location={:?}", + place_base, + context, + location, + ); + self.super_place_base(place_base, context, location); + + match place_base { + PlaceBase::Local(_) => {} + PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) => { + bug!("Promotion must be run after const validation"); + } + + PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => { + let is_thread_local = self.tcx.has_attr(*def_id, sym::thread_local); + if is_thread_local { + self.check_op(ops::ThreadLocalAccess); + } else if self.mode == Mode::Static && context.is_mutating_use() { + // this is not strictly necessary as miri will also bail out + // For interior mutability we can't really catch this statically as that + // goes through raw pointers and intermediate temporaries, so miri has + // to catch this anyway + + self.tcx.sess.span_err( + self.span, + "cannot mutate statics in the initializer of another static", + ); + } else { + self.check_op(ops::StaticAccess); + } + } + } + } + + fn visit_assign(&mut self, dest: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { + trace!("visit_assign: dest={:?} rvalue={:?} location={:?}", dest, rvalue, location); + + // Error on mutable borrows or shared borrows of values with interior mutability. + // + // This replicates the logic at the start of `assign` in the old const checker. Note that + // it depends on `HasMutInterior` being set for mutable borrows as well as values with + // interior mutability. + if let Rvalue::Ref(_, kind, ref borrowed_place) = *rvalue { + let rvalue_has_mut_interior = HasMutInterior::in_rvalue( + &self.item, + self.qualifs.has_mut_interior.get(), + rvalue, + ); + + if rvalue_has_mut_interior { + let is_derived_from_illegal_borrow = match *borrowed_place { + // If an unprojected local was borrowed and its value was the result of an + // illegal borrow, suppress this error and mark the result of this borrow as + // illegal as well. + Place { base: PlaceBase::Local(borrowed_local), projection: box [] } + if self.derived_from_illegal_borrow.contains(borrowed_local) => true, + + // Otherwise proceed normally: check the legality of a mutable borrow in this + // context. + _ => self.check_op(ops::MutBorrow(kind)) == CheckOpResult::Forbidden, + }; + + // When the target of the assignment is a local with no projections, mark it as + // derived from an illegal borrow if necessary. + // + // FIXME: should we also clear `derived_from_illegal_borrow` when a local is + // assigned a new value? + if is_derived_from_illegal_borrow { + if let Place { base: PlaceBase::Local(dest), projection: box [] } = *dest { + self.derived_from_illegal_borrow.insert(dest); + } + } + } + } + + self.super_assign(dest, rvalue, location); + } + + fn visit_projection_elem( + &mut self, + place_base: &PlaceBase<'tcx>, + proj_base: &[PlaceElem<'tcx>], + elem: &PlaceElem<'tcx>, + context: PlaceContext, + location: Location, + ) { + trace!( + "visit_projection_elem: place_base={:?} proj_base={:?} elem={:?} \ + context={:?} location={:?}", + place_base, + proj_base, + elem, + context, + location, + ); + + self.super_projection_elem(place_base, proj_base, elem, context, location); + + match elem { + ProjectionElem::Deref => { + if context.is_mutating_use() { + self.check_op(ops::MutDeref); + } + + let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty; + if let ty::RawPtr(_) = base_ty.kind { + self.check_op(ops::RawPtrDeref); + } + } + + ProjectionElem::ConstantIndex {..} | + ProjectionElem::Subslice {..} | + ProjectionElem::Field(..) | + ProjectionElem::Index(_) => { + let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty; + match base_ty.ty_adt_def() { + Some(def) if def.is_union() => { + self.check_op(ops::UnionAccess); + } + + _ => {} + } + } + + ProjectionElem::Downcast(..) => { + self.check_op(ops::Downcast); + } + } + } + + + fn visit_source_info(&mut self, source_info: &SourceInfo) { + trace!("visit_source_info: source_info={:?}", source_info); + self.span = source_info.span; + } + + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + trace!("visit_statement: statement={:?} location={:?}", statement, location); + + self.qualifs.needs_drop.visit_statement(statement, location); + self.qualifs.has_mut_interior.visit_statement(statement, location); + + match statement.kind { + StatementKind::Assign(..) => { + self.super_statement(statement, location); + } + StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) => { + self.check_op(ops::IfOrMatch); + } + // FIXME(eddyb) should these really do nothing? + StatementKind::FakeRead(..) | + StatementKind::SetDiscriminant { .. } | + StatementKind::StorageLive(_) | + StatementKind::StorageDead(_) | + StatementKind::InlineAsm {..} | + StatementKind::Retag { .. } | + StatementKind::AscribeUserType(..) | + StatementKind::Nop => {} + } + } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + trace!("visit_terminator: terminator={:?} location={:?}", terminator, location); + + self.qualifs.needs_drop.visit_terminator(terminator, location); + self.qualifs.has_mut_interior.visit_terminator(terminator, location); + + self.super_terminator(terminator, location); + } + + fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Location) { + trace!("visit_terminator_kind: kind={:?} location={:?}", kind, location); + self.super_terminator_kind(kind, location); + + match kind { + TerminatorKind::Call { func, .. } => { + let fn_ty = func.ty(self.body, self.tcx); + + let def_id = match fn_ty.kind { + ty::FnDef(def_id, _) => def_id, + + ty::FnPtr(_) => { + self.check_op(ops::FnCallIndirect); + return; + } + _ => { + self.check_op(ops::FnCallOther); + return; + } + }; + + // At this point, we are calling a function whose `DefId` is known... + + if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = self.tcx.fn_sig(def_id).abi() { + assert!(!self.tcx.is_const_fn(def_id)); + + if self.tcx.item_name(def_id) == sym::transmute { + self.check_op(ops::Transmute); + return; + } + + // To preserve the current semantics, we return early, allowing all + // intrinsics (except `transmute`) to pass unchecked to miri. + // + // FIXME: We should keep a whitelist of allowed intrinsics (or at least a + // blacklist of unimplemented ones) and fail here instead. + return; + } + + if self.tcx.is_const_fn(def_id) { + return; + } + + if is_lang_panic_fn(self.tcx, def_id) { + self.check_op(ops::Panic); + } else if let Some(feature) = self.tcx.is_unstable_const_fn(def_id) { + // Exempt unstable const fns inside of macros with + // `#[allow_internal_unstable]`. + if !self.span.allows_unstable(feature) { + self.check_op(ops::FnCallUnstable(def_id, feature)); + } + } else { + self.check_op(ops::FnCallNonConst(def_id)); + } + + } + + // Forbid all `Drop` terminators unless the place being dropped is a local with no + // projections that cannot be `NeedsDrop`. + | TerminatorKind::Drop { location: dropped_place, .. } + | TerminatorKind::DropAndReplace { location: dropped_place, .. } + => { + let mut err_span = self.span; + + // Check to see if the type of this place can ever have a drop impl. If not, this + // `Drop` terminator is frivolous. + let ty_needs_drop = dropped_place + .ty(self.body, self.tcx) + .ty + .needs_drop(self.tcx, self.param_env); + + if !ty_needs_drop { + return; + } + + let needs_drop = if let Place { + base: PlaceBase::Local(local), + projection: box [], + } = *dropped_place { + // Use the span where the local was declared as the span of the drop error. + err_span = self.body.local_decls[local].source_info.span; + self.qualifs.needs_drop.contains(local) + } else { + true + }; + + if needs_drop { + self.check_op_spanned(ops::LiveDrop, err_span); + } + } + + _ => {} + } + } +} diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index d5c5267a119d3..70855d70228b3 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -1,5 +1,5 @@ use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::vec::IndexVec; use rustc_data_structures::sync::Lrc; use rustc::ty::query::Providers; @@ -182,7 +182,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { // result of a comparison of addresses would differ between runtime and compile-time. Rvalue::BinaryOp(_, ref lhs, _) if self.const_context && self.tcx.features().const_compare_raw_pointers => { - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).sty { + if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind { self.register_violations(&[UnsafetyViolation { source_info: self.source_info, description: InternedString::intern("pointer operation"), @@ -200,127 +200,127 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { place: &Place<'tcx>, context: PlaceContext, _location: Location) { - place.iterate(|place_base, place_projections| { - match place_base { - PlaceBase::Local(..) => { - // Locals are safe. - } - PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }) => { - bug!("unsafety checking should happen before promotion") - } - PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), .. }) => { - if self.tcx.is_mutable_static(*def_id) { - self.require_unsafe("use of mutable static", - "mutable statics can be mutated by multiple threads: aliasing \ - violations or data races will cause undefined behavior", - UnsafetyViolationKind::General); - } else if self.tcx.is_foreign_item(*def_id) { - let source_info = self.source_info; - let lint_root = - self.source_scope_local_data[source_info.scope].lint_root; - self.register_violations(&[UnsafetyViolation { - source_info, - description: InternedString::intern("use of extern static"), - details: InternedString::intern( - "extern statics are not controlled by the Rust type system: \ - invalid data, aliasing violations or data races will cause \ - undefined behavior"), - kind: UnsafetyViolationKind::ExternStatic(lint_root) - }], &[]); - } + match place.base { + PlaceBase::Local(..) => { + // Locals are safe. + } + PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => { + bug!("unsafety checking should happen before promotion") + } + PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => { + if self.tcx.is_mutable_static(def_id) { + self.require_unsafe("use of mutable static", + "mutable statics can be mutated by multiple threads: aliasing \ + violations or data races will cause undefined behavior", + UnsafetyViolationKind::General); + } else if self.tcx.is_foreign_item(def_id) { + let source_info = self.source_info; + let lint_root = + self.source_scope_local_data[source_info.scope].lint_root; + self.register_violations(&[UnsafetyViolation { + source_info, + description: InternedString::intern("use of extern static"), + details: InternedString::intern( + "extern statics are not controlled by the Rust type system: \ + invalid data, aliasing violations or data races will cause \ + undefined behavior"), + kind: UnsafetyViolationKind::ExternStatic(lint_root) + }], &[]); } } + } - for proj in place_projections { - if context.is_borrow() { - if util::is_disaligned(self.tcx, self.body, self.param_env, place) { - let source_info = self.source_info; - let lint_root = - self.source_scope_local_data[source_info.scope].lint_root; - self.register_violations(&[UnsafetyViolation { - source_info, - description: InternedString::intern("borrow of packed field"), - details: InternedString::intern( - "fields of packed structs might be misaligned: dereferencing a \ - misaligned pointer or even just creating a misaligned reference \ - is undefined behavior"), - kind: UnsafetyViolationKind::BorrowPacked(lint_root) - }], &[]); - } + for (i, elem) in place.projection.iter().enumerate() { + let proj_base = &place.projection[..i]; + + if context.is_borrow() { + if util::is_disaligned(self.tcx, self.body, self.param_env, place) { + let source_info = self.source_info; + let lint_root = + self.source_scope_local_data[source_info.scope].lint_root; + self.register_violations(&[UnsafetyViolation { + source_info, + description: InternedString::intern("borrow of packed field"), + details: InternedString::intern( + "fields of packed structs might be misaligned: dereferencing a \ + misaligned pointer or even just creating a misaligned reference \ + is undefined behavior"), + kind: UnsafetyViolationKind::BorrowPacked(lint_root) + }], &[]); } - let is_borrow_of_interior_mut = context.is_borrow() && - !Place::ty_from(&place.base, &proj.base, self.body, self.tcx) - .ty - .is_freeze(self.tcx, self.param_env, self.source_info.span); - // prevent - // * `&mut x.field` - // * `x.field = y;` - // * `&x.field` if `field`'s type has interior mutability - // because either of these would allow modifying the layout constrained field and - // insert values that violate the layout constraints. - if context.is_mutating_use() || is_borrow_of_interior_mut { - self.check_mut_borrowing_layout_constrained_field( - place, context.is_mutating_use(), - ); + } + let is_borrow_of_interior_mut = context.is_borrow() && + !Place::ty_from(&place.base, proj_base, self.body, self.tcx) + .ty + .is_freeze(self.tcx, self.param_env, self.source_info.span); + // prevent + // * `&mut x.field` + // * `x.field = y;` + // * `&x.field` if `field`'s type has interior mutability + // because either of these would allow modifying the layout constrained field and + // insert values that violate the layout constraints. + if context.is_mutating_use() || is_borrow_of_interior_mut { + self.check_mut_borrowing_layout_constrained_field( + place, context.is_mutating_use(), + ); + } + let old_source_info = self.source_info; + if let (PlaceBase::Local(local), []) = (&place.base, proj_base) { + if self.body.local_decls[*local].internal { + // Internal locals are used in the `move_val_init` desugaring. + // We want to check unsafety against the source info of the + // desugaring, rather than the source info of the RHS. + self.source_info = self.body.local_decls[*local].source_info; } - let old_source_info = self.source_info; - if let (PlaceBase::Local(local), None) = (&place.base, &proj.base) { - if self.body.local_decls[*local].internal { - // Internal locals are used in the `move_val_init` desugaring. - // We want to check unsafety against the source info of the - // desugaring, rather than the source info of the RHS. - self.source_info = self.body.local_decls[*local].source_info; - } + } + let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty; + match base_ty.kind { + ty::RawPtr(..) => { + self.require_unsafe("dereference of raw pointer", + "raw pointers may be NULL, dangling or unaligned; they can violate \ + aliasing rules and cause data races: all of these are undefined \ + behavior", UnsafetyViolationKind::General) } - let base_ty = Place::ty_from(&place.base, &proj.base, self.body, self.tcx).ty; - match base_ty.sty { - ty::RawPtr(..) => { - self.require_unsafe("dereference of raw pointer", - "raw pointers may be NULL, dangling or unaligned; they can violate \ - aliasing rules and cause data races: all of these are undefined \ - behavior", UnsafetyViolationKind::General) - } - ty::Adt(adt, _) => { - if adt.is_union() { - if context == PlaceContext::MutatingUse(MutatingUseContext::Store) || - context == PlaceContext::MutatingUse(MutatingUseContext::Drop) || - context == PlaceContext::MutatingUse( - MutatingUseContext::AsmOutput - ) - { - let elem_ty = match proj.elem { - ProjectionElem::Field(_, ty) => ty, - _ => span_bug!( - self.source_info.span, - "non-field projection {:?} from union?", - place) - }; - if !elem_ty.is_copy_modulo_regions( - self.tcx, - self.param_env, + ty::Adt(adt, _) => { + if adt.is_union() { + if context == PlaceContext::MutatingUse(MutatingUseContext::Store) || + context == PlaceContext::MutatingUse(MutatingUseContext::Drop) || + context == PlaceContext::MutatingUse( + MutatingUseContext::AsmOutput + ) + { + let elem_ty = match elem { + ProjectionElem::Field(_, ty) => ty, + _ => span_bug!( self.source_info.span, - ) { - self.require_unsafe( - "assignment to non-`Copy` union field", - "the previous content of the field will be dropped, which \ - causes undefined behavior if the field was not properly \ - initialized", UnsafetyViolationKind::General) - } else { - // write to non-move union, safe - } + "non-field projection {:?} from union?", + place) + }; + if !elem_ty.is_copy_modulo_regions( + self.tcx, + self.param_env, + self.source_info.span, + ) { + self.require_unsafe( + "assignment to non-`Copy` union field", + "the previous content of the field will be dropped, which \ + causes undefined behavior if the field was not properly \ + initialized", UnsafetyViolationKind::GeneralAndConstFn) } else { - self.require_unsafe("access to union field", - "the field may not be properly initialized: using \ - uninitialized data will cause undefined behavior", - UnsafetyViolationKind::General) + // write to non-move union, safe } + } else { + self.require_unsafe("access to union field", + "the field may not be properly initialized: using \ + uninitialized data will cause undefined behavior", + UnsafetyViolationKind::GeneralAndConstFn) } } - _ => {} } - self.source_info = old_source_info; + _ => {} } - }); + self.source_info = old_source_info; + } } } @@ -407,14 +407,16 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { place: &Place<'tcx>, is_mut_use: bool, ) { - let mut projection = &place.projection; - while let Some(proj) = projection { - match proj.elem { + let mut cursor = &*place.projection; + while let [proj_base @ .., elem] = cursor { + cursor = proj_base; + + match elem { ProjectionElem::Field(..) => { let ty = - Place::ty_from(&place.base, &proj.base, &self.body.local_decls, self.tcx) + Place::ty_from(&place.base, proj_base, &self.body.local_decls, self.tcx) .ty; - match ty.sty { + match ty.kind { ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) { (Bound::Unbounded, Bound::Unbounded) => {}, _ => { @@ -447,7 +449,6 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { } _ => {} } - projection = &proj.base; } } } @@ -576,7 +577,7 @@ fn is_enclosed( if used_unsafe.contains(&parent_id) { Some(("block".to_string(), parent_id)) } else if let Some(Node::Item(&hir::Item { - node: hir::ItemKind::Fn(_, header, _, _), + kind: hir::ItemKind::Fn(_, header, _, _), .. })) = tcx.hir().find(parent_id) { match header.unsafety { diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs index 6ee14160bbd1b..ea173279aa073 100644 --- a/src/librustc_mir/transform/cleanup_post_borrowck.rs +++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs @@ -26,8 +26,8 @@ pub struct CleanupNonCodegenStatements; pub struct DeleteNonCodegenStatements; -impl MirPass for CleanupNonCodegenStatements { - fn run_pass<'tcx>(&self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements { + fn run_pass(&self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { let mut delete = DeleteNonCodegenStatements; delete.visit_body(body); } @@ -39,7 +39,7 @@ impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements { location: Location) { match statement.kind { StatementKind::AscribeUserType(..) - | StatementKind::Assign(_, box Rvalue::Ref(_, BorrowKind::Shallow, _)) + | StatementKind::Assign(box(_, Rvalue::Ref(_, BorrowKind::Shallow, _))) | StatementKind::FakeRead(..) => statement.make_nop(), _ => (), } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 38d26d0ba50a4..49ac1de8fef64 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -1,40 +1,44 @@ //! Propagates constants for early reporting of statically known //! assertion failures +use std::borrow::Cow; use std::cell::Cell; use rustc::hir::def::DefKind; +use rustc::hir::def_id::DefId; use rustc::mir::{ AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, - Local, NullOp, UnOp, StatementKind, Statement, LocalKind, Static, StaticKind, - TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem, - SourceScope, SourceScopeLocalData, LocalDecl, Promoted, + Local, NullOp, UnOp, StatementKind, Statement, LocalKind, + TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, + SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock, }; use rustc::mir::visit::{ Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext, }; -use rustc::mir::interpret::{Scalar, GlobalId, InterpResult, PanicInfo}; +use rustc::mir::interpret::{Scalar, InterpResult, PanicInfo}; use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; +use syntax::ast::Mutability; use syntax_pos::{Span, DUMMY_SP}; use rustc::ty::subst::InternalSubsts; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::fx::FxHashMap; +use rustc_index::vec::IndexVec; use rustc::ty::layout::{ - LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout, Size, + LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout, }; use crate::interpret::{ self, InterpCx, ScalarMaybeUndef, Immediate, OpTy, - ImmTy, MemoryKind, StackPopCleanup, LocalValue, LocalState, -}; -use crate::const_eval::{ - CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_eval_cx, + StackPopCleanup, LocalValue, LocalState, AllocId, Frame, + Allocation, MemoryKind, ImmTy, Pointer, Memory, PlaceTy, + Operand as InterpOperand, }; +use crate::const_eval::error_to_const_error; use crate::transform::{MirPass, MirSource}; pub struct ConstProp; -impl MirPass for ConstProp { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for ConstProp { + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { // will be evaluated by miri and produce its errors there if source.promoted.is_some() { return; @@ -57,6 +61,14 @@ impl MirPass for ConstProp { return } + let is_generator = tcx.type_of(source.def_id()).is_generator(); + // FIXME(welseywiser) const prop doesn't work on generators because of query cycles + // computing their layout. + if is_generator { + trace!("ConstProp skipped for generator {:?}", source.def_id()); + return + } + trace!("ConstProp starting for {:?}", source.def_id()); // Steal some data we need from `body`. @@ -64,17 +76,12 @@ impl MirPass for ConstProp { &mut body.source_scope_local_data, ClearCrossCrate::Clear ); - let promoted = std::mem::replace( - &mut body.promoted, - IndexVec::new() - ); let dummy_body = &Body::new( body.basic_blocks().clone(), Default::default(), ClearCrossCrate::Clear, - Default::default(), None, body.local_decls.clone(), Default::default(), @@ -92,39 +99,176 @@ impl MirPass for ConstProp { body, dummy_body, source_scope_local_data, - promoted, tcx, source ); optimization_finder.visit_body(body); // put back the data we stole from `mir` - let (source_scope_local_data, promoted) = optimization_finder.release_stolen_data(); + let source_scope_local_data = optimization_finder.release_stolen_data(); std::mem::replace( &mut body.source_scope_local_data, source_scope_local_data ); - std::mem::replace( - &mut body.promoted, - promoted - ); trace!("ConstProp done for {:?}", source.def_id()); } } +struct ConstPropMachine; + +impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { + type MemoryKinds= !; + type PointerTag = (); + type ExtraFnVal = !; + + type FrameExtra = (); + type MemoryExtra = (); + type AllocExtra = (); + + type MemoryMap = FxHashMap, Allocation)>; + + const STATIC_KIND: Option = None; + + const CHECK_ALIGN: bool = false; + + #[inline(always)] + fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + false + } + + fn find_fn( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _instance: ty::Instance<'tcx>, + _args: &[OpTy<'tcx>], + _dest: Option>, + _ret: Option, + ) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> { + Ok(None) + } + + fn call_extra_fn( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + fn_val: !, + _args: &[OpTy<'tcx>], + _dest: Option>, + _ret: Option, + ) -> InterpResult<'tcx> { + match fn_val {} + } + + fn call_intrinsic( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _instance: ty::Instance<'tcx>, + _args: &[OpTy<'tcx>], + _dest: PlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + throw_unsup_format!("calling intrinsics isn't supported in ConstProp"); + } + + fn ptr_to_int( + _mem: &Memory<'mir, 'tcx, Self>, + _ptr: Pointer, + ) -> InterpResult<'tcx, u64> { + throw_unsup_format!("ptr-to-int casts aren't supported in ConstProp"); + } + + fn binary_ptr_op( + _ecx: &InterpCx<'mir, 'tcx, Self>, + _bin_op: BinOp, + _left: ImmTy<'tcx>, + _right: ImmTy<'tcx>, + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + // We can't do this because aliasing of memory can differ between const eval and llvm + throw_unsup_format!("pointer arithmetic or comparisons aren't supported in ConstProp"); + } + + fn find_foreign_static( + _tcx: TyCtxt<'tcx>, + _def_id: DefId, + ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { + throw_unsup!(ReadForeignStatic) + } + + #[inline(always)] + fn tag_allocation<'b>( + _memory_extra: &(), + _id: AllocId, + alloc: Cow<'b, Allocation>, + _kind: Option>, + ) -> (Cow<'b, Allocation>, Self::PointerTag) { + // We do not use a tag so we can just cheaply forward the allocation + (alloc, ()) + } + + #[inline(always)] + fn tag_static_base_pointer( + _memory_extra: &(), + _id: AllocId, + ) -> Self::PointerTag { + () + } + + fn box_alloc( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _dest: PlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + throw_unsup_format!("can't const prop `box` keyword"); + } + + fn access_local( + _ecx: &InterpCx<'mir, 'tcx, Self>, + frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, + local: Local, + ) -> InterpResult<'tcx, InterpOperand> { + let l = &frame.locals[local]; + + if l.value == LocalValue::Uninitialized { + throw_unsup_format!("tried to access an uninitialized local"); + } + + l.access() + } + + fn before_access_static( + allocation: &Allocation, + ) -> InterpResult<'tcx> { + // if the static allocation is mutable or if it has relocations (it may be legal to mutate + // the memory behind that in the future), then we can't const prop it + if allocation.mutability == Mutability::Mutable || allocation.relocations().len() > 0 { + throw_unsup_format!("can't eval mutable statics in ConstProp"); + } + + Ok(()) + } + + fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + Ok(()) + } + + #[inline(always)] + fn stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + Ok(()) + } + + /// Called immediately before a stack frame gets popped. + #[inline(always)] + fn stack_pop(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _extra: ()) -> InterpResult<'tcx> { + Ok(()) + } +} + type Const<'tcx> = OpTy<'tcx>; /// Finds optimization opportunities on the MIR. struct ConstPropagator<'mir, 'tcx> { - ecx: InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, + ecx: InterpCx<'mir, 'tcx, ConstPropMachine>, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, can_const_prop: IndexVec, param_env: ParamEnv<'tcx>, source_scope_local_data: ClearCrossCrate>, local_decls: IndexVec>, - promoted: IndexVec>, } impl<'mir, 'tcx> LayoutOf for ConstPropagator<'mir, 'tcx> { @@ -155,14 +299,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { body: &Body<'tcx>, dummy_body: &'mir Body<'tcx>, source_scope_local_data: ClearCrossCrate>, - promoted: IndexVec>, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, ) -> ConstPropagator<'mir, 'tcx> { let def_id = source.def_id(); let param_env = tcx.param_env(def_id); let span = tcx.def_span(def_id); - let mut ecx = mk_eval_cx(tcx, span, param_env); + let mut ecx = InterpCx::new(tcx.at(span), param_env, ConstPropMachine, ()); let can_const_prop = CanConstProp::check(body); ecx.push_stack_frame( @@ -184,48 +327,17 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { source_scope_local_data, //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it local_decls: body.local_decls.clone(), - promoted, } } - fn release_stolen_data( - self, - ) -> ( - ClearCrossCrate>, - IndexVec>, - ) { - (self.source_scope_local_data, self.promoted) + fn release_stolen_data(self) -> ClearCrossCrate> { + self.source_scope_local_data } fn get_const(&self, local: Local) -> Option> { - let l = &self.ecx.frame().locals[local]; - - // If the local is `Unitialized` or `Dead` then we haven't propagated a value into it. - // - // `InterpCx::access_local()` mostly takes care of this for us however, for ZSTs, - // it will synthesize a value for us. In doing so, that will cause the - // `get_const(l).is_empty()` assert right before we call `set_const()` in `visit_statement` - // to fail. - if let LocalValue::Uninitialized | LocalValue::Dead = l.value { - return None; - } - self.ecx.access_local(self.ecx.frame(), local, None).ok() } - fn set_const(&mut self, local: Local, c: Const<'tcx>) { - let frame = self.ecx.frame_mut(); - - if let Some(layout) = frame.locals[local].layout.get() { - debug_assert_eq!(c.layout, layout); - } - - frame.locals[local] = LocalState { - value: LocalValue::Live(*c), - layout: Cell::new(Some(c.layout)), - }; - } - fn remove_const(&mut self, local: Local) { self.ecx.frame_mut().locals[local] = LocalState { value: LocalValue::Uninitialized, @@ -255,9 +367,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let r = match f(self) { Ok(val) => Some(val), Err(error) => { - let diagnostic = error_to_const_error(&self.ecx, error); use rustc::mir::interpret::InterpError::*; - match diagnostic.error { + match error.kind { Exit(_) => bug!("the CTFE program cannot exit"), Unsupported(_) | UndefinedBehavior(_) @@ -266,6 +377,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // Ignore these errors. } Panic(_) => { + let diagnostic = error_to_const_error(&self.ecx, error); diagnostic.report_as_lint( self.ecx.tcx, "this expression will panic at runtime", @@ -300,55 +412,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option> { trace!("eval_place(place={:?})", place); - place.iterate(|place_base, place_projection| { - let mut eval = match place_base { - PlaceBase::Local(loc) => self.get_const(*loc).clone()?, - PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted), ..}) => { - let generics = self.tcx.generics_of(self.source.def_id()); - if generics.requires_monomorphization(self.tcx) { - // FIXME: can't handle code with generics - return None; - } - let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id()); - let instance = Instance::new(self.source.def_id(), substs); - let cid = GlobalId { - instance, - promoted: Some(*promoted), - }; - // 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 res = self.use_ecx(source_info, |this| { - let body = &this.promoted[*promoted]; - eval_promoted(this.tcx, cid, body, this.param_env) - })?; - trace!("evaluated promoted {:?} to {:?}", promoted, res); - res.into() - } - _ => return None, - }; - - for proj in place_projection { - match proj.elem { - ProjectionElem::Field(field, _) => { - trace!("field proj on {:?}", proj.base); - eval = self.use_ecx(source_info, |this| { - this.ecx.operand_field(eval, field.index() as u64) - })?; - }, - ProjectionElem::Deref => { - trace!("processing deref"); - eval = self.use_ecx(source_info, |this| { - this.ecx.deref_operand(eval) - })?.into(); - } - // We could get more projections by using e.g., `operand_projection`, - // but we do not even have the stack frame set up properly so - // an `Index` projection would throw us off-track. - _ => return None, - } - } - - Some(eval) + self.use_ecx(source_info, |this| { + this.ecx.eval_place_to_op(place, None) }) } @@ -365,181 +430,124 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { rvalue: &Rvalue<'tcx>, place_layout: TyLayout<'tcx>, source_info: SourceInfo, + place: &Place<'tcx>, ) -> Option> { let span = source_info.span; - match *rvalue { - Rvalue::Use(ref op) => { - self.eval_operand(op, source_info) - }, - Rvalue::Ref(_, _, ref place) => { - let src = self.eval_place(place, source_info)?; - let mplace = src.try_as_mplace().ok()?; - Some(ImmTy::from_scalar(mplace.ptr.into(), place_layout).into()) - }, + + // if this isn't a supported operation, then return None + match rvalue { Rvalue::Repeat(..) | Rvalue::Aggregate(..) | Rvalue::NullaryOp(NullOp::Box, _) | - Rvalue::Discriminant(..) => None, - - Rvalue::Cast(kind, ref operand, _) => { - let op = self.eval_operand(operand, source_info)?; - self.use_ecx(source_info, |this| { - let dest = this.ecx.allocate(place_layout, MemoryKind::Stack); - this.ecx.cast(op, kind, dest.into())?; - Ok(dest.into()) - }) - }, - Rvalue::Len(ref place) => { - let place = self.eval_place(&place, source_info)?; - let mplace = place.try_as_mplace().ok()?; - - if let ty::Slice(_) = mplace.layout.ty.sty { - let len = mplace.meta.unwrap().to_usize(&self.ecx).unwrap(); - - Some(ImmTy { - imm: Immediate::Scalar( - Scalar::from_uint( - len, - Size::from_bits( - self.tcx.sess.target.usize_ty.bit_width().unwrap() as u64 - ) - ).into(), - ), - layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?, - }.into()) - } else { - trace!("not slice: {:?}", mplace.layout.ty.sty); - None - } - }, - Rvalue::NullaryOp(NullOp::SizeOf, ty) => { - type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some( - ImmTy { - imm: Immediate::Scalar( - Scalar::from_uint(n, self.tcx.data_layout.pointer_size).into() - ), - layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?, - }.into() - )) - } - Rvalue::UnaryOp(op, ref arg) => { - let def_id = if self.tcx.is_closure(self.source.def_id()) { - self.tcx.closure_base_def_id(self.source.def_id()) - } else { - self.source.def_id() - }; - let generics = self.tcx.generics_of(def_id); - if generics.requires_monomorphization(self.tcx) { - // FIXME: can't handle code with generics - return None; - } + Rvalue::Discriminant(..) => return None, + + Rvalue::Use(_) | + Rvalue::Len(_) | + Rvalue::Cast(..) | + Rvalue::NullaryOp(..) | + Rvalue::CheckedBinaryOp(..) | + Rvalue::Ref(..) | + Rvalue::UnaryOp(..) | + Rvalue::BinaryOp(..) => { } + } - let arg = self.eval_operand(arg, source_info)?; - let val = self.use_ecx(source_info, |this| { - let prim = this.ecx.read_immediate(arg)?; - match op { - UnOp::Neg => { - // Need to do overflow check here: For actual CTFE, MIR - // generation emits code that does this before calling the op. - if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) { - throw_panic!(OverflowNeg) - } - } - UnOp::Not => { - // Cannot overflow + // perform any special checking for specific Rvalue types + if let Rvalue::UnaryOp(op, arg) = rvalue { + trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg); + let overflow_check = self.tcx.sess.overflow_checks(); + + self.use_ecx(source_info, |this| { + // We check overflow in debug mode already + // so should only check in release mode. + if *op == UnOp::Neg && !overflow_check { + let ty = arg.ty(&this.local_decls, this.tcx); + + if ty.is_integral() { + let arg = this.ecx.eval_operand(arg, None)?; + let prim = this.ecx.read_immediate(arg)?; + // Need to do overflow check here: For actual CTFE, MIR + // generation emits code that does this before calling the op. + if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) { + throw_panic!(OverflowNeg) } } - // Now run the actual operation. - this.ecx.unary_op(op, prim) - })?; - let res = ImmTy { - imm: Immediate::Scalar(val.into()), - layout: place_layout, - }; - Some(res.into()) - } - Rvalue::CheckedBinaryOp(op, ref left, ref right) | - Rvalue::BinaryOp(op, ref left, ref right) => { - trace!("rvalue binop {:?} for {:?} and {:?}", op, left, right); - let right = self.eval_operand(right, source_info)?; - let def_id = if self.tcx.is_closure(self.source.def_id()) { - self.tcx.closure_base_def_id(self.source.def_id()) - } else { - self.source.def_id() - }; - let generics = self.tcx.generics_of(def_id); - if generics.requires_monomorphization(self.tcx) { - // FIXME: can't handle code with generics + } + + Ok(()) + })?; + } else if let Rvalue::BinaryOp(op, left, right) = rvalue { + trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right); + + let r = self.use_ecx(source_info, |this| { + this.ecx.read_immediate(this.ecx.eval_operand(right, None)?) + })?; + if *op == BinOp::Shr || *op == BinOp::Shl { + let left_bits = place_layout.size.bits(); + let right_size = r.layout.size; + let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size)); + if r_bits.ok().map_or(false, |b| b >= left_bits as u128) { + let source_scope_local_data = match self.source_scope_local_data { + ClearCrossCrate::Set(ref data) => data, + ClearCrossCrate::Clear => return None, + }; + let dir = if *op == BinOp::Shr { + "right" + } else { + "left" + }; + let hir_id = source_scope_local_data[source_info.scope].lint_root; + self.tcx.lint_hir( + ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, + hir_id, + span, + &format!("attempt to shift {} with overflow", dir)); return None; } + } + self.use_ecx(source_info, |this| { + let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?; + let (_, overflow, _ty) = this.ecx.overflowing_binary_op(*op, l, r)?; + + // We check overflow in debug mode already + // so should only check in release mode. + if !this.tcx.sess.overflow_checks() && overflow { + let err = err_panic!(Overflow(*op)).into(); + return Err(err); + } - let r = self.use_ecx(source_info, |this| { - this.ecx.read_immediate(right) - })?; - if op == BinOp::Shr || op == BinOp::Shl { - let left_ty = left.ty(&self.local_decls, self.tcx); - let left_bits = self - .tcx - .layout_of(self.param_env.and(left_ty)) - .unwrap() - .size - .bits(); - let right_size = right.layout.size; - let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size)); - if r_bits.ok().map_or(false, |b| b >= left_bits as u128) { - let source_scope_local_data = match self.source_scope_local_data { - ClearCrossCrate::Set(ref data) => data, - ClearCrossCrate::Clear => return None, - }; - let dir = if op == BinOp::Shr { - "right" - } else { - "left" - }; - let hir_id = source_scope_local_data[source_info.scope].lint_root; - self.tcx.lint_hir( - ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, - hir_id, - span, - &format!("attempt to shift {} with overflow", dir)); - return None; - } + Ok(()) + })?; + } else if let Rvalue::Ref(_, _, place) = rvalue { + trace!("checking Ref({:?})", place); + // FIXME(wesleywiser) we don't currently handle the case where we try to make a ref + // from a function argument that hasn't been assigned to in this function. + if let Place { + base: PlaceBase::Local(local), + projection: box [] + } = place { + let alive = + if let LocalValue::Live(_) = self.ecx.frame().locals[*local].value { + true + } else { false }; + + if local.as_usize() <= self.ecx.frame().body.arg_count && !alive { + trace!("skipping Ref({:?})", place); + return None; } - let left = self.eval_operand(left, source_info)?; - let l = self.use_ecx(source_info, |this| { - this.ecx.read_immediate(left) - })?; - trace!("const evaluating {:?} for {:?} and {:?}", op, left, right); - let (val, overflow) = self.use_ecx(source_info, |this| { - this.ecx.binary_op(op, l, r) - })?; - let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue { - Immediate::ScalarPair( - val.into(), - Scalar::from_bool(overflow).into(), - ) - } else { - if overflow { - let err = err_panic!(Overflow(op)).into(); - let _: Option<()> = self.use_ecx(source_info, |_| Err(err)); - return None; - } - Immediate::Scalar(val.into()) - }; - let res = ImmTy { - imm: val, - layout: place_layout, - }; - Some(res.into()) - }, + } } + + self.use_ecx(source_info, |this| { + trace!("calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})", rvalue, place); + this.ecx.eval_rvalue_into_place(rvalue, place)?; + this.ecx.eval_place_to_op(place, Some(place_layout)) + }) } fn operand_from_scalar(&self, scalar: Scalar, ty: Ty<'tcx>, span: Span) -> Operand<'tcx> { Operand::Constant(Box::new( Constant { span, - ty, user_ty: None, literal: self.tcx.mk_const(*ty::Const::from_scalar( self.tcx, @@ -582,7 +590,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ScalarMaybeUndef::Scalar(one), ScalarMaybeUndef::Scalar(two) ) => { - let ty = &value.layout.ty.sty; + let ty = &value.layout.ty.kind; if let ty::Tuple(substs) = ty { *rval = Rvalue::Aggregate( Box::new(AggregateKind::Tuple), @@ -607,14 +615,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } -fn type_size_of<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, -) -> Option { - tcx.layout_of(param_env.and(ty)).ok().map(|layout| layout.size.bytes()) -} - struct CanConstProp { can_const_prop: IndexVec, // false at the beginning, once set, there are not allowed to be any more assignments @@ -695,21 +695,23 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { location: Location, ) { trace!("visit_statement: {:?}", statement); - if let StatementKind::Assign(ref place, ref mut rval) = statement.kind { + if let StatementKind::Assign(box(ref place, ref mut rval)) = statement.kind { let place_ty: Ty<'tcx> = place .ty(&self.local_decls, self.tcx) .ty; if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) { - if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) { - if let Place { - base: PlaceBase::Local(local), - projection: None, - } = *place { + if let Place { + base: PlaceBase::Local(local), + projection: box [], + } = *place { + if let Some(value) = self.const_prop(rval, + place_layout, + statement.source_info, + place) { trace!("checking whether {:?} can be stored to {:?}", value, local); if self.can_const_prop[local] { - trace!("storing {:?} to {:?}", value, local); - assert!(self.get_const(local).is_none()); - self.set_const(local, value); + trace!("stored {:?} to {:?}", value, local); + assert_eq!(self.get_const(local), Some(value)); if self.should_const_prop() { self.replace_with_const( @@ -718,11 +720,29 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { statement.source_info, ); } + } else { + trace!("can't propagate {:?} to {:?}", value, local); + self.remove_const(local); } } } } + } else { + match statement.kind { + StatementKind::StorageLive(local) | + StatementKind::StorageDead(local) if self.can_const_prop[local] => { + let frame = self.ecx.frame_mut(); + frame.locals[local].value = + if let StatementKind::StorageLive(_) = statement.kind { + LocalValue::Uninitialized + } else { + LocalValue::Dead + }; + } + _ => {} + } } + self.super_statement(statement, location); } diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 7c9eeb5a57741..28f97f41b50cf 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -29,8 +29,8 @@ use crate::util::def_use::DefUseAnalysis; pub struct CopyPropagation; -impl MirPass for CopyPropagation { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for CopyPropagation { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { // We only run when the MIR optimization level is > 1. // This avoids a slow pass, and messing up debug info. if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { @@ -94,11 +94,13 @@ impl MirPass for CopyPropagation { // That use of the source must be an assignment. match statement.kind { StatementKind::Assign( - Place { - base: PlaceBase::Local(local), - projection: None, - }, - box Rvalue::Use(ref operand) + box( + Place { + base: PlaceBase::Local(local), + projection: box [], + }, + Rvalue::Use(ref operand) + ) ) if local == dest_local => { let maybe_action = match *operand { Operand::Copy(ref src_place) | @@ -148,24 +150,28 @@ fn eliminate_self_assignments( if let Some(stmt) = body[location.block].statements.get(location.statement_index) { match stmt.kind { StatementKind::Assign( - Place { - base: PlaceBase::Local(local), - projection: None, - }, - box Rvalue::Use(Operand::Copy(Place { - base: PlaceBase::Local(src_local), - projection: None, - })), + box( + Place { + base: PlaceBase::Local(local), + projection: box [], + }, + Rvalue::Use(Operand::Copy(Place { + base: PlaceBase::Local(src_local), + projection: box [], + })), + ) ) | StatementKind::Assign( - Place { - base: PlaceBase::Local(local), - projection: None, - }, - box Rvalue::Use(Operand::Move(Place { - base: PlaceBase::Local(src_local), - projection: None, - })), + box( + Place { + base: PlaceBase::Local(local), + projection: box [], + }, + Rvalue::Use(Operand::Move(Place { + base: PlaceBase::Local(src_local), + projection: box [], + })), + ) ) if local == dest_local && dest_local == src_local => {} _ => { continue; @@ -194,7 +200,7 @@ impl<'tcx> Action<'tcx> { // The source must be a local. let src_local = if let Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } = *src_place { local } else { @@ -351,11 +357,11 @@ impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> { match *operand { Operand::Copy(Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }) | Operand::Move(Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }) if local == self.dest_local => {} _ => return, } diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index 1b42a0dffb894..c1224be6324e2 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -5,15 +5,15 @@ use crate::util::expand_aggregate; pub struct Deaggregator; -impl MirPass for Deaggregator { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for Deaggregator { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); let local_decls = &*local_decls; for bb in basic_blocks { bb.expand_statements(|stmt| { // FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL). - if let StatementKind::Assign(_, ref rhs) = stmt.kind { - if let Rvalue::Aggregate(ref kind, _) = **rhs { + if let StatementKind::Assign(box(_, ref rhs)) = stmt.kind { + if let Rvalue::Aggregate(ref kind, _) = *rhs { // FIXME(#48193) Deaggregate arrays when it's cheaper to do so. if let AggregateKind::Array(_) = **kind { return None; @@ -28,7 +28,7 @@ impl MirPass for Deaggregator { let stmt = stmt.replace_nop(); let source_info = stmt.source_info; let (lhs, kind, operands) = match stmt.kind { - StatementKind::Assign(lhs, box rvalue) => { + StatementKind::Assign(box(lhs, rvalue)) => { match rvalue { Rvalue::Aggregate(kind, operands) => (lhs, kind, operands), _ => bug!() diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index a6fb555f20bd0..ed0eff943a165 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -13,12 +13,12 @@ use crate::util as mir_util; pub struct Marker(pub &'static str); -impl MirPass for Marker { +impl<'tcx> MirPass<'tcx> for Marker { fn name(&self) -> Cow<'_, str> { Cow::Borrowed(self.0) } - fn run_pass<'tcx>(&self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, _body: &mut Body<'tcx>) { + fn run_pass(&self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, _body: &mut Body<'tcx>) { } } diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 0a021d9b8fa06..f91a08bcd9aa6 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -14,31 +14,21 @@ use rustc::ty::layout::VariantIdx; use rustc::hir; use rustc::mir::*; use rustc::util::nodemap::FxHashMap; -use rustc_data_structures::bit_set::BitSet; +use rustc_index::bit_set::BitSet; use std::fmt; use syntax_pos::Span; pub struct ElaborateDrops; -impl MirPass for ElaborateDrops { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for ElaborateDrops { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { debug!("elaborate_drops({:?} @ {:?})", src, body.span); let def_id = src.def_id(); let param_env = tcx.param_env(src.def_id()).with_reveal_all(); let move_data = match MoveData::gather_moves(body, tcx) { Ok(move_data) => move_data, - Err((move_data, _move_errors)) => { - // The only way we should be allowing any move_errors - // in here is if we are in the migration path for the - // NLL-based MIR-borrowck. - // - // If we are in the migration path, we have already - // reported these errors as warnings to the user. So - // we will just ignore them here. - assert!(tcx.migrate_borrowck()); - move_data - } + Err(_) => bug!("No `move_errors` should be allowed in MIR borrowck"), }; let elaborate_patch = { let body = &*body; @@ -236,47 +226,34 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { } fn field_subpath(&self, path: Self::Path, field: Field) -> Option { - dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| { - match p { - &Projection { - elem: ProjectionElem::Field(idx, _), .. - } => idx == field, - _ => false - } + dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { + ProjectionElem::Field(idx, _) => *idx == field, + _ => false, }) } fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option { - dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| { - match p { - &Projection { - elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: false}, .. - } => offset == index, - &Projection { - elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true}, .. - } => size - offset == index, - _ => false + dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { + ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false } => { + *offset == index + } + ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true } => { + size - offset == index } + _ => false, }) } fn deref_subpath(&self, path: Self::Path) -> Option { - dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| { - match p { - &Projection { elem: ProjectionElem::Deref, .. } => true, - _ => false - } + dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| { + *e == ProjectionElem::Deref }) } fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option { - dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| { - match p { - &Projection { - elem: ProjectionElem::Downcast(_, idx), .. - } => idx == variant, - _ => false - } + dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { + ProjectionElem::Downcast(_, idx) => *idx == variant, + _ => false }) } @@ -465,7 +442,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported"); let assign = Statement { - kind: StatementKind::Assign(location.clone(), box Rvalue::Use(value.clone())), + kind: StatementKind::Assign(box(location.clone(), Rvalue::Use(value.clone()))), source_info: terminator.source_info }; @@ -527,7 +504,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> { Rvalue::Use(Operand::Constant(Box::new(Constant { span, - ty: self.tcx.types.bool, user_ty: None, literal: ty::Const::from_bool(self.tcx, val), }))) diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 5a29ea21a7a04..38a04ce8f3815 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -39,18 +39,12 @@ impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> { fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, _: Location) { *substs = self.tcx.erase_regions(substs); } - - fn visit_statement(&mut self, - statement: &mut Statement<'tcx>, - location: Location) { - self.super_statement(statement, location); - } } pub struct EraseRegions; -impl MirPass for EraseRegions { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for EraseRegions { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { EraseRegionsVisitor::new(tcx).visit_body(body); } } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 94bb70e10aa53..865fa012c2995 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -58,8 +58,8 @@ use rustc::ty::GeneratorSubsts; use rustc::ty::layout::VariantIdx; use rustc::ty::subst::SubstsRef; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc_data_structures::bit_set::{BitSet, BitMatrix}; +use rustc_index::vec::{Idx, IndexVec}; +use rustc_index::bit_set::{BitSet, BitMatrix}; use std::borrow::Cow; use std::iter; use std::mem; @@ -67,7 +67,7 @@ use crate::transform::{MirPass, MirSource}; use crate::transform::simplify; use crate::transform::no_landing_pads::no_landing_pads; use crate::dataflow::{DataflowResults, DataflowResultsConsumer, FlowAtLocation}; -use crate::dataflow::{do_dataflow, DebugFormatted, state_for_location}; +use crate::dataflow::{do_dataflow, DebugFormatted, DataflowResultsCursor}; use crate::dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals, RequiresStorage}; use crate::util::dump_mir; use crate::util::liveness; @@ -107,10 +107,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor { if place.base == PlaceBase::Local(self_arg()) { replace_base(place, Place { base: PlaceBase::Local(self_arg()), - projection: Some(Box::new(Projection { - base: None, - elem: ProjectionElem::Deref, - })), + projection: Box::new([ProjectionElem::Deref]), }); } else { self.super_place(place, context, location); @@ -137,10 +134,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { if place.base == PlaceBase::Local(self_arg()) { replace_base(place, Place { base: PlaceBase::Local(self_arg()), - projection: Some(Box::new(Projection { - base: None, - elem: ProjectionElem::Field(Field::new(0), self.ref_gen_ty), - })), + projection: Box::new([ProjectionElem::Field(Field::new(0), self.ref_gen_ty)]), }); } else { self.super_place(place, context, location); @@ -149,13 +143,12 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { } fn replace_base(place: &mut Place<'tcx>, new_base: Place<'tcx>) { - let mut projection = &mut place.projection; - while let Some(box proj) = projection { - projection = &mut proj.base; - } - place.base = new_base.base; - *projection = new_base.projection; + + let mut new_projection = new_base.projection.to_vec(); + new_projection.append(&mut place.projection.to_vec()); + + place.projection = new_projection.into_boxed_slice(); } fn self_arg() -> Local { @@ -210,13 +203,12 @@ impl TransformVisitor<'tcx> { fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> { let self_place = Place::from(self_arg()); let base = self_place.downcast_unnamed(variant_index); - let field = Projection { - base: base.projection, - elem: ProjectionElem::Field(Field::new(idx), ty), - }; + let mut projection = base.projection.to_vec(); + projection.push(ProjectionElem::Field(Field::new(idx), ty)); + Place { base: base.base, - projection: Some(Box::new(field)), + projection: projection.into_boxed_slice(), } } @@ -225,7 +217,10 @@ impl TransformVisitor<'tcx> { let self_place = Place::from(self_arg()); Statement { source_info, - kind: StatementKind::SetDiscriminant { place: self_place, variant_index: state_disc }, + kind: StatementKind::SetDiscriminant { + place: box self_place, + variant_index: state_disc, + }, } } @@ -238,7 +233,7 @@ impl TransformVisitor<'tcx> { let self_place = Place::from(self_arg()); let assign = Statement { source_info: source_info(body), - kind: StatementKind::Assign(temp.clone(), box Rvalue::Discriminant(self_place)), + kind: StatementKind::Assign(box(temp.clone(), Rvalue::Discriminant(self_place))), }; (assign, temp) } @@ -296,8 +291,12 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> { // We must assign the value first in case it gets declared dead below data.statements.push(Statement { source_info, - kind: StatementKind::Assign(Place::RETURN_PLACE, - box self.make_state(state_idx, v)), + kind: StatementKind::Assign( + box( + Place::return_place(), + self.make_state(state_idx, v) + ) + ), }); let state = if let Some(resume) = resume { // Yield let state = 3 + self.suspension_points.len(); @@ -437,9 +436,10 @@ fn locals_live_across_suspend_points( // Calculate when MIR locals have live storage. This gives us an upper bound of their // lifetimes. let storage_live_analysis = MaybeStorageLive::new(body); - let storage_live = + let storage_live_results = do_dataflow(tcx, body, def_id, &[], &dead_unwinds, storage_live_analysis, |bd, p| DebugFormatted::new(&bd.body().local_decls[p])); + let mut storage_live_cursor = DataflowResultsCursor::new(&storage_live_results, body); // Find the MIR locals which do not use StorageLive/StorageDead statements. // The storage of these locals are always live. @@ -449,17 +449,18 @@ fn locals_live_across_suspend_points( // Calculate the MIR locals which have been previously // borrowed (even if they are still active). let borrowed_locals_analysis = HaveBeenBorrowedLocals::new(body); - let borrowed_locals_result = + let borrowed_locals_results = do_dataflow(tcx, body, def_id, &[], &dead_unwinds, borrowed_locals_analysis, |bd, p| DebugFormatted::new(&bd.body().local_decls[p])); + let mut borrowed_locals_cursor = DataflowResultsCursor::new(&borrowed_locals_results, body); // Calculate the MIR locals that we actually need to keep storage around // for. - let requires_storage_analysis = RequiresStorage::new(body, &borrowed_locals_result); - let requires_storage = + let requires_storage_analysis = RequiresStorage::new(body, &borrowed_locals_results); + let requires_storage_results = do_dataflow(tcx, body, def_id, &[], &dead_unwinds, requires_storage_analysis, |bd, p| DebugFormatted::new(&bd.body().local_decls[p])); - let requires_storage_analysis = RequiresStorage::new(body, &borrowed_locals_result); + let mut requires_storage_cursor = DataflowResultsCursor::new(&requires_storage_results, body); // Calculate the liveness of MIR locals ignoring borrows. let mut live_locals = liveness::LiveVarSet::new_empty(body.local_decls.len()); @@ -485,10 +486,6 @@ fn locals_live_across_suspend_points( }; if !movable { - let borrowed_locals = state_for_location(loc, - &borrowed_locals_analysis, - &borrowed_locals_result, - body); // The `liveness` variable contains the liveness of MIR locals ignoring borrows. // This is correct for movable generators since borrows cannot live across // suspension points. However for immovable generators we need to account for @@ -499,25 +496,19 @@ fn locals_live_across_suspend_points( // If a borrow is converted to a raw reference, we must also assume that it lives // forever. Note that the final liveness is still bounded by the storage liveness // of the local, which happens using the `intersect` operation below. - liveness.outs[block].union(&borrowed_locals); + borrowed_locals_cursor.seek(loc); + liveness.outs[block].union(borrowed_locals_cursor.get()); } - let storage_liveness = state_for_location(loc, - &storage_live_analysis, - &storage_live, - body); + storage_live_cursor.seek(loc); + let storage_liveness = storage_live_cursor.get(); // Store the storage liveness for later use so we can restore the state // after a suspension point storage_liveness_map.insert(block, storage_liveness.clone()); - let mut storage_required = state_for_location(loc, - &requires_storage_analysis, - &requires_storage, - body); - - // Mark locals without storage statements as always requiring storage - storage_required.union(&ignored.0); + requires_storage_cursor.seek(loc); + let storage_required = requires_storage_cursor.get().clone(); // Locals live are live at this point only if they are used across // suspension points (the `liveness` variable) @@ -550,8 +541,7 @@ fn locals_live_across_suspend_points( body, &live_locals, &ignored, - requires_storage, - requires_storage_analysis); + requires_storage_results); LivenessInfo { live_locals, @@ -589,7 +579,6 @@ fn compute_storage_conflicts( stored_locals: &liveness::LiveVarSet, ignored: &StorageIgnored, requires_storage: DataflowResults<'tcx, RequiresStorage<'mir, 'tcx>>, - _requires_storage_analysis: RequiresStorage<'mir, 'tcx>, ) -> BitMatrix { assert_eq!(body.local_decls.len(), ignored.0.domain_size()); assert_eq!(body.local_decls.len(), stored_locals.domain_size()); @@ -719,7 +708,7 @@ fn compute_layout<'tcx>( // Erase regions from the types passed in from typeck so we can compare them with // MIR types let allowed_upvars = tcx.erase_regions(upvars); - let allowed = match interior.sty { + let allowed = match interior.kind { ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(&s), _ => bug!(), }; @@ -848,7 +837,7 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut kind: TerminatorKind::Drop { location: Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }, target, unwind @@ -937,7 +926,7 @@ fn create_generator_drop_shim<'tcx>( // Alias tracking must know we changed the type body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement { source_info, - kind: StatementKind::Retag(RetagKind::Raw, Place::from(self_arg())), + kind: StatementKind::Retag(RetagKind::Raw, box Place::from(self_arg())), }) } @@ -975,7 +964,6 @@ fn insert_panic_block<'tcx>( let term = TerminatorKind::Assert { cond: Operand::Constant(box Constant { span: body.span, - ty: tcx.types.bool, user_ty: None, literal: ty::Const::from_bool(tcx, false), }), @@ -1116,8 +1104,8 @@ where }).collect() } -impl MirPass for StateTransform { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for StateTransform { + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { let yield_ty = if let Some(yield_ty) = body.yield_ty { yield_ty } else { @@ -1133,8 +1121,9 @@ impl MirPass for StateTransform { let gen_ty = body.local_decls.raw[1].ty; // Get the interior types and substs which typeck computed - let (upvars, interior, discr_ty, movable) = match gen_ty.sty { + let (upvars, interior, discr_ty, movable) = match gen_ty.kind { ty::Generator(_, substs, movability) => { + let substs = substs.as_generator(); (substs.upvar_tys(def_id, tcx).collect(), substs.witness(def_id, tcx), substs.discr_ty(tcx), diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 40cb1fbdc57fa..9830ed35ffc3e 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -3,8 +3,8 @@ use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def_id::DefId; -use rustc_data_structures::bit_set::BitSet; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::{Idx, IndexVec}; use rustc::mir::*; use rustc::mir::visit::*; @@ -37,8 +37,8 @@ struct CallSite<'tcx> { location: SourceInfo, } -impl MirPass for Inline { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for Inline { + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 { Inliner { tcx, source }.run_pass(body); } @@ -177,7 +177,7 @@ impl Inliner<'tcx> { // Only consider direct calls to functions let terminator = bb_data.terminator(); if let TerminatorKind::Call { func: ref op, .. } = terminator.kind { - if let ty::FnDef(callee_def_id, substs) = op.ty(caller_body, self.tcx).sty { + if let ty::FnDef(callee_def_id, substs) = op.ty(caller_body, self.tcx).kind { let instance = Instance::resolve(self.tcx, param_env, callee_def_id, @@ -328,7 +328,7 @@ impl Inliner<'tcx> { } TerminatorKind::Call {func: Operand::Constant(ref f), .. } => { - if let ty::FnDef(def_id, _) = f.ty.sty { + if let ty::FnDef(def_id, _) = f.literal.ty.kind { // Don't give intrinsics the extra penalty for calls let f = tcx.fn_sig(def_id); if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { @@ -394,7 +394,6 @@ impl Inliner<'tcx> { let mut local_map = IndexVec::with_capacity(callee_body.local_decls.len()); let mut scope_map = IndexVec::with_capacity(callee_body.source_scopes.len()); - let mut promoted_map = IndexVec::with_capacity(callee_body.promoted.len()); for mut scope in callee_body.source_scopes.iter().cloned() { if scope.parent_scope.is_none() { @@ -420,32 +419,26 @@ impl Inliner<'tcx> { local_map.push(idx); } - promoted_map.extend( - callee_body.promoted.iter().cloned().map(|p| caller_body.promoted.push(p)) - ); - // If the call is something like `a[*i] = f(i)`, where // `i : &mut usize`, then just duplicating the `a[*i]` // Place could result in two different locations if `f` // writes to `i`. To prevent this we need to create a temporary // borrow of the place and pass the destination as `*temp` instead. fn dest_needs_borrow(place: &Place<'_>) -> bool { - place.iterate(|place_base, place_projection| { - for proj in place_projection { - match proj.elem { - ProjectionElem::Deref | - ProjectionElem::Index(_) => return true, - _ => {} - } + for elem in place.projection.iter() { + match elem { + ProjectionElem::Deref | + ProjectionElem::Index(_) => return true, + _ => {} } + } - match place_base { - // Static variables need a borrow because the callee - // might modify the same static. - PlaceBase::Static(_) => true, - _ => false - } - }) + match place.base { + // Static variables need a borrow because the callee + // might modify the same static. + PlaceBase::Static(_) => true, + _ => false + } } let dest = if dest_needs_borrow(&destination.0) { @@ -464,7 +457,7 @@ impl Inliner<'tcx> { let stmt = Statement { source_info: callsite.location, - kind: StatementKind::Assign(tmp.clone(), box dest) + kind: StatementKind::Assign(box(tmp.clone(), dest)) }; caller_body[callsite.bb] .statements.push(stmt); @@ -484,12 +477,10 @@ impl Inliner<'tcx> { args: &args, local_map, scope_map, - promoted_map, - _callsite: callsite, destination: dest, return_block, cleanup_block: cleanup, - in_cleanup_block: false + in_cleanup_block: false, }; @@ -555,7 +546,7 @@ impl Inliner<'tcx> { assert!(args.next().is_none()); let tuple = Place::from(tuple); - let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_body, tcx).ty.sty { + let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_body, tcx).ty.kind { s } else { bug!("Closure arguments are not passed as a tuple"); @@ -598,7 +589,7 @@ impl Inliner<'tcx> { if let Operand::Move(Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }) = arg { if caller_body.local_kind(local) == LocalKind::Temp { // Reuse the operand if it's a temporary already @@ -617,7 +608,7 @@ impl Inliner<'tcx> { let stmt = Statement { source_info: callsite.location, - kind: StatementKind::Assign(Place::from(arg_tmp), box arg), + kind: StatementKind::Assign(box(Place::from(arg_tmp), arg)), }; caller_body[callsite.bb].statements.push(stmt); arg_tmp @@ -644,8 +635,6 @@ struct Integrator<'a, 'tcx> { args: &'a [Local], local_map: IndexVec, scope_map: IndexVec, - promoted_map: IndexVec, - _callsite: CallSite<'tcx>, destination: Place<'tcx>, return_block: BasicBlock, cleanup_block: Option, @@ -669,7 +658,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { match self.destination { Place { base: PlaceBase::Local(l), - projection: None, + projection: box [], } => { *local = l; return; @@ -693,22 +682,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { match place { Place { base: PlaceBase::Local(RETURN_PLACE), - projection: None, + projection: box [], } => { // Return pointer; update the place itself *place = self.destination.clone(); }, - Place { - base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(promoted), - .. - }), - projection: None, - } => { - if let Some(p) = self.promoted_map.get(*promoted).cloned() { - *promoted = p; - } - }, _ => self.super_place(place, _ctxt, _location) } } diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index 5542926503693..bb98d63b1ee10 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -5,14 +5,14 @@ use rustc::mir::{Constant, Location, Place, PlaceBase, Body, Operand, Projection use rustc::mir::visit::{MutVisitor, Visitor}; use rustc::ty::{self, TyCtxt}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use std::mem; use crate::transform::{MirPass, MirSource}; pub struct InstCombine; -impl MirPass for InstCombine { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for InstCombine { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { // We only run when optimizing MIR (at any level). if tcx.sess.opts.debugging_opts.mir_opt_level == 0 { return @@ -43,12 +43,21 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { let new_place = match *rvalue { Rvalue::Ref(_, _, Place { ref mut base, - projection: Some(ref mut projection), - }) => Place { - // Replace with dummy - base: mem::replace(base, PlaceBase::Local(Local::new(0))), - projection: projection.base.take(), - }, + projection: ref mut projection @ box [.., _], + }) => { + if let box [proj_l @ .., proj_r] = projection { + let place = Place { + // Replace with dummy + base: mem::replace(base, PlaceBase::Local(Local::new(0))), + projection: proj_l.to_vec().into_boxed_slice(), + }; + *projection = vec![proj_r.clone()].into_boxed_slice(); + + place + } else { + unreachable!(); + } + } _ => bug!("Detected `&*` but didn't find `&*`!"), }; *rvalue = Rvalue::Use(Operand::Copy(new_place)) @@ -83,22 +92,19 @@ impl OptimizationFinder<'b, 'tcx> { impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Ref(_, _, Place { - ref base, - projection: Some(ref projection), - }) = *rvalue { - if let ProjectionElem::Deref = projection.elem { - if Place::ty_from(&base, &projection.base, self.body, self.tcx).ty.is_region_ptr() { - self.optimizations.and_stars.insert(location); - } + base, + projection: box [proj_base @ .., ProjectionElem::Deref], + }) = rvalue { + if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() { + self.optimizations.and_stars.insert(location); } } if let Rvalue::Len(ref place) = *rvalue { let place_ty = place.ty(&self.body.local_decls, self.tcx).ty; - if let ty::Array(_, len) = place_ty.sty { + if let ty::Array(_, len) = place_ty.kind { let span = self.body.source_info(location).span; - let ty = self.tcx.types.usize; - let constant = Constant { span, ty, literal: len, user_ty: None }; + let constant = Constant { span, literal: len, user_ty: None }; self.optimizations.arrays_lengths.insert(location, constant); } } diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 61d0b1f3485b6..7e06729c2c742 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -1,5 +1,5 @@ use crate::{build, shim}; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::vec::IndexVec; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::mir::{Body, MirPhase, Promoted}; use rustc::ty::{TyCtxt, InstanceDef}; @@ -15,6 +15,7 @@ use syntax_pos::Span; pub mod add_retag; pub mod add_moves_for_packed_drops; pub mod cleanup_post_borrowck; +pub mod check_consts; pub mod check_unsafety; pub mod simplify_branches; pub mod simplify; @@ -137,60 +138,50 @@ pub fn default_name() -> Cow<'static, str> { /// A streamlined trait that you can implement to create a pass; the /// pass will be named after the type, and it will consist of a main /// loop that goes over each available MIR and applies `run_pass`. -pub trait MirPass { +pub trait MirPass<'tcx> { fn name(&self) -> Cow<'_, str> { default_name::() } - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>); + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>); } pub fn run_passes( tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, instance: InstanceDef<'tcx>, + promoted: Option, mir_phase: MirPhase, - passes: &[&dyn MirPass], + passes: &[&dyn MirPass<'tcx>], ) { let phase_index = mir_phase.phase_index(); - let run_passes = |body: &mut Body<'tcx>, promoted| { - if body.phase >= mir_phase { - return; - } + if body.phase >= mir_phase { + return; + } - let source = MirSource { - instance, - promoted, - }; - let mut index = 0; - let mut run_pass = |pass: &dyn MirPass| { - let run_hooks = |body: &_, index, is_after| { - dump_mir::on_mir_pass(tcx, &format_args!("{:03}-{:03}", phase_index, index), - &pass.name(), source, body, is_after); - }; - run_hooks(body, index, false); - pass.run_pass(tcx, source, body); - run_hooks(body, index, true); - - index += 1; + let source = MirSource { + instance, + promoted, + }; + let mut index = 0; + let mut run_pass = |pass: &dyn MirPass<'tcx>| { + let run_hooks = |body: &_, index, is_after| { + dump_mir::on_mir_pass(tcx, &format_args!("{:03}-{:03}", phase_index, index), + &pass.name(), source, body, is_after); }; + run_hooks(body, index, false); + pass.run_pass(tcx, source, body); + run_hooks(body, index, true); - for pass in passes { - run_pass(*pass); - } - - body.phase = mir_phase; + index += 1; }; - run_passes(body, None); - - for (index, promoted_body) in body.promoted.iter_enumerated_mut() { - run_passes(promoted_body, Some(index)); - - //Let's make sure we don't miss any nested instances - assert!(promoted_body.promoted.is_empty()) + for pass in passes { + run_pass(*pass); } + + body.phase = mir_phase; } fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal> { @@ -198,7 +189,7 @@ fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal> { let _ = tcx.unsafety_check_result(def_id); let mut body = tcx.mir_built(def_id).steal(); - run_passes(tcx, &mut body, InstanceDef::Item(def_id), MirPhase::Const, &[ + run_passes(tcx, &mut body, InstanceDef::Item(def_id), None, MirPhase::Const, &[ // What we need to do constant evaluation. &simplify::SimplifyCfg::new("initial"), &rustc_peek::SanityCheck, @@ -207,7 +198,10 @@ fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal> { tcx.alloc_steal_mir(body) } -fn mir_validated(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Steal> { +fn mir_validated( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> (&'tcx Steal>, &'tcx Steal>>) { let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); if let hir::BodyOwnerKind::Const = tcx.hir().body_owner_kind(hir_id) { // Ensure that we compute the `mir_const_qualif` for constants at @@ -216,33 +210,23 @@ fn mir_validated(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Steal> { } let mut body = tcx.mir_const(def_id).steal(); - run_passes(tcx, &mut body, InstanceDef::Item(def_id), MirPhase::Validated, &[ + let qualify_and_promote_pass = qualify_consts::QualifyAndPromoteConstants::default(); + run_passes(tcx, &mut body, InstanceDef::Item(def_id), None, MirPhase::Validated, &[ // What we need to run borrowck etc. - &qualify_consts::QualifyAndPromoteConstants, + &qualify_and_promote_pass, &simplify::SimplifyCfg::new("qualify-consts"), ]); - tcx.alloc_steal_mir(body) + let promoted = qualify_and_promote_pass.promoted.into_inner(); + (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted)) } -fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> { - if tcx.is_constructor(def_id) { - // There's no reason to run all of the MIR passes on constructors when - // we can just output the MIR we want directly. This also saves const - // qualification and borrow checking the trouble of special casing - // constructors. - return shim::build_adt_ctor(tcx, def_id); - } - - // (Mir-)Borrowck uses `mir_validated`, so we have to force it to - // execute before we can steal. - tcx.ensure().mir_borrowck(def_id); - - if tcx.use_ast_borrowck() { - tcx.ensure().borrowck(def_id); - } - - let mut body = tcx.mir_validated(def_id).steal(); - run_passes(tcx, &mut body, InstanceDef::Item(def_id), MirPhase::Optimized, &[ +fn run_optimization_passes<'tcx>( + tcx: TyCtxt<'tcx>, + body: &mut Body<'tcx>, + def_id: DefId, + promoted: Option, +) { + run_passes(tcx, body, InstanceDef::Item(def_id), promoted, MirPhase::Optimized, &[ // Remove all things only needed by analysis &no_landing_pads::NoLandingPads, &simplify_branches::SimplifyBranches::new("initial"), @@ -293,10 +277,39 @@ fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> { &add_call_guards::CriticalCallEdges, &dump_mir::Marker("PreCodegen"), ]); +} + +fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> { + if tcx.is_constructor(def_id) { + // There's no reason to run all of the MIR passes on constructors when + // we can just output the MIR we want directly. This also saves const + // qualification and borrow checking the trouble of special casing + // constructors. + return shim::build_adt_ctor(tcx, def_id); + } + + // (Mir-)Borrowck uses `mir_validated`, so we have to force it to + // execute before we can steal. + tcx.ensure().mir_borrowck(def_id); + + let (body, _) = tcx.mir_validated(def_id); + let mut body = body.steal(); + run_optimization_passes(tcx, &mut body, def_id, None); tcx.arena.alloc(body) } fn promoted_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx IndexVec> { - let body = tcx.optimized_mir(def_id); - &body.promoted + if tcx.is_constructor(def_id) { + return tcx.intern_promoted(IndexVec::new()); + } + + tcx.ensure().mir_borrowck(def_id); + let (_, promoted) = tcx.mir_validated(def_id); + let mut promoted = promoted.steal(); + + for (p, mut body) in promoted.iter_enumerated_mut() { + run_optimization_passes(tcx, &mut body, def_id, Some(p)); + } + + tcx.intern_promoted(promoted) } diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 841db80fc7dbb..762bb5d44839f 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -8,8 +8,8 @@ use crate::transform::{MirPass, MirSource}; pub struct NoLandingPads; -impl MirPass for NoLandingPads { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for NoLandingPads { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { no_landing_pads(tcx, body) } } diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 3090b63a7e993..5d241ffe1c06a 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -12,13 +12,15 @@ //! initialization and can otherwise silence errors, if //! move analysis runs after promotion on broken MIR. +use rustc::hir::def_id::DefId; use rustc::mir::*; use rustc::mir::visit::{PlaceContext, MutatingUseContext, MutVisitor, Visitor}; use rustc::mir::traversal::ReversePostorder; +use rustc::ty::subst::InternalSubsts; use rustc::ty::TyCtxt; use syntax_pos::Span; -use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use rustc_index::vec::{IndexVec, Idx}; use std::{iter, mem, usize}; @@ -185,7 +187,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { span, scope: OUTERMOST_SOURCE_SCOPE }, - kind: StatementKind::Assign(Place::from(dest), box rvalue) + kind: StatementKind::Assign(box(Place::from(dest), rvalue)) }); } @@ -220,10 +222,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { // First, take the Rvalue or Call out of the source MIR, // or duplicate it, depending on keep_original. if loc.statement_index < no_stmts { - let (rvalue, source_info) = { + let (mut rvalue, source_info) = { let statement = &mut self.source[loc.block].statements[loc.statement_index]; let rhs = match statement.kind { - StatementKind::Assign(_, ref mut rhs) => rhs, + StatementKind::Assign(box(_, ref mut rhs)) => rhs, _ => { span_bug!(statement.source_info.span, "{:?} is not an assignment", statement); @@ -233,12 +235,11 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { (if self.keep_original { rhs.clone() } else { - let unit = box Rvalue::Aggregate(box AggregateKind::Tuple, vec![]); + let unit = Rvalue::Aggregate(box AggregateKind::Tuple, vec![]); mem::replace(rhs, unit) }, statement.source_info) }; - let mut rvalue = *rvalue; self.visit_rvalue(&mut rvalue, loc); self.assign(new_temp, rvalue, source_info.span); } else { @@ -293,19 +294,30 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { new_temp } - fn promote_candidate(mut self, candidate: Candidate) { + fn promote_candidate( + mut self, + def_id: DefId, + candidate: Candidate, + next_promoted_id: usize, + ) -> Option> { let mut operand = { let promoted = &mut self.promoted; - let promoted_id = Promoted::new(self.source.promoted.len()); + let promoted_id = Promoted::new(next_promoted_id); + let tcx = self.tcx; let mut promoted_place = |ty, span| { promoted.span = span; promoted.local_decls[RETURN_PLACE] = LocalDecl::new_return_place(ty, span); Place { base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(promoted_id), - ty + kind: + StaticKind::Promoted( + promoted_id, + InternalSubsts::identity_for_item(tcx, def_id), + ), + ty, + def_id, }), - projection: None, + projection: box [], } }; let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut(); @@ -313,14 +325,17 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { Candidate::Ref(loc) => { let ref mut statement = blocks[loc.block].statements[loc.statement_index]; match statement.kind { - StatementKind::Assign(_, box Rvalue::Ref(_, _, ref mut place)) => { + StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref mut place))) => { // Use the underlying local for this (necessarily interior) borrow. let ty = place.base.ty(local_decls).ty; let span = statement.source_info.span; Operand::Move(Place { - base: mem::replace(&mut place.base, promoted_place(ty, span).base), - projection: None, + base: mem::replace( + &mut place.base, + promoted_place(ty, span).base, + ), + projection: box [], }) } _ => bug!() @@ -329,10 +344,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { Candidate::Repeat(loc) => { let ref mut statement = blocks[loc.block].statements[loc.statement_index]; match statement.kind { - StatementKind::Assign(_, box Rvalue::Repeat(ref mut operand, _)) => { + StatementKind::Assign(box(_, Rvalue::Repeat(ref mut operand, _))) => { let ty = operand.ty(local_decls, self.tcx); let span = statement.source_info.span; - mem::replace(operand, Operand::Copy(promoted_place(ty, span))) + mem::replace( + operand, + Operand::Copy(promoted_place(ty, span)) + ) } _ => bug!() } @@ -353,7 +371,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { // a function requiring a constant argument and as that constant value // providing a value whose computation contains another call to a function // requiring a constant argument. - TerminatorKind::Goto { .. } => return, + TerminatorKind::Goto { .. } => return None, _ => bug!() } } @@ -368,7 +386,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let span = self.promoted.span; self.assign(RETURN_PLACE, Rvalue::Use(operand), span); - self.source.promoted.push(self.promoted); + Some(self.promoted) } } @@ -385,23 +403,26 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { } pub fn promote_candidates<'tcx>( + def_id: DefId, body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>, mut temps: IndexVec, candidates: Vec, -) { +) -> IndexVec> { // Visit candidates in reverse, in case they're nested. debug!("promote_candidates({:?})", candidates); + let mut promotions = IndexVec::new(); + for candidate in candidates.into_iter().rev() { match candidate { Candidate::Repeat(Location { block, statement_index }) | Candidate::Ref(Location { block, statement_index }) => { match body[block].statements[statement_index].kind { - StatementKind::Assign(Place { + StatementKind::Assign(box(Place { base: PlaceBase::Local(local), - projection: None, - }, _) => { + projection: box [], + }, _)) => { if temps[local] == TempState::PromotedOut { // Already promoted. continue; @@ -426,7 +447,6 @@ pub fn promote_candidates<'tcx>( // memory usage? body.source_scopes.clone(), body.source_scope_local_data.clone(), - IndexVec::new(), None, initial_locals, IndexVec::new(), @@ -440,7 +460,11 @@ pub fn promote_candidates<'tcx>( temps: &mut temps, keep_original: false }; - promoter.promote_candidate(candidate); + + //FIXME(oli-obk): having a `maybe_push()` method on `IndexVec` might be nice + if let Some(promoted) = promoter.promote_candidate(def_id, candidate, promotions.len()) { + promotions.push(promoted); + } } // Eliminate assignments to, and drops of promoted temps. @@ -448,10 +472,10 @@ pub fn promote_candidates<'tcx>( for block in body.basic_blocks_mut() { block.statements.retain(|statement| { match statement.kind { - StatementKind::Assign(Place { + StatementKind::Assign(box(Place { base: PlaceBase::Local(index), - projection: None, - }, _) | + projection: box [], + }, _)) | StatementKind::StorageLive(index) | StatementKind::StorageDead(index) => { !promoted(index) @@ -463,7 +487,7 @@ pub fn promote_candidates<'tcx>( match terminator.kind { TerminatorKind::Drop { location: Place { base: PlaceBase::Local(index), - projection: None, + projection: box [], }, target, .. } => { if promoted(index) { terminator.kind = TerminatorKind::Goto { @@ -474,4 +498,6 @@ pub fn promote_candidates<'tcx>( _ => {} } } + + promotions } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index dcfc80968f31c..fbcf9c8cb5eba 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -4,8 +4,8 @@ //! The Qualif flags below can be used to also provide better //! diagnostics as to why a constant rvalue wasn't promoted. -use rustc_data_structures::bit_set::BitSet; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; use rustc_data_structures::fx::FxHashSet; use rustc_target::spec::abi::Abi; use rustc::hir; @@ -25,12 +25,16 @@ use syntax::feature_gate::{emit_feature_err, GateIssue}; use syntax::symbol::sym; use syntax_pos::{Span, DUMMY_SP}; +use std::borrow::Cow; +use std::cell::Cell; use std::fmt; use std::ops::{Deref, Index, IndexMut}; use std::usize; +use rustc::hir::HirId; use crate::transform::{MirPass, MirSource}; use super::promote_consts::{self, Candidate, TempState}; +use crate::transform::check_consts::ops::{self, NonConstOp}; /// What kind of item we are in. #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -184,26 +188,28 @@ trait Qualif { cx: &ConstCx<'_, 'tcx>, place: PlaceRef<'_, 'tcx>, ) -> bool { - let proj = place.projection.as_ref().unwrap(); - - let base_qualif = Self::in_place(cx, PlaceRef { - base: place.base, - projection: &proj.base, - }); - let qualif = base_qualif && Self::mask_for_ty( - cx, - Place::ty_from(place.base, &proj.base, cx.body, cx.tcx) - .projection_ty(cx.tcx, &proj.elem) - .ty, - ); - match proj.elem { - ProjectionElem::Deref | - ProjectionElem::Subslice { .. } | - ProjectionElem::Field(..) | - ProjectionElem::ConstantIndex { .. } | - ProjectionElem::Downcast(..) => qualif, - - ProjectionElem::Index(local) => qualif || Self::in_local(cx, local), + if let [proj_base @ .., elem] = place.projection { + let base_qualif = Self::in_place(cx, PlaceRef { + base: place.base, + projection: proj_base, + }); + let qualif = base_qualif && Self::mask_for_ty( + cx, + Place::ty_from(place.base, proj_base, cx.body, cx.tcx) + .projection_ty(cx.tcx, elem) + .ty, + ); + match elem { + ProjectionElem::Deref | + ProjectionElem::Subslice { .. } | + ProjectionElem::Field(..) | + ProjectionElem::ConstantIndex { .. } | + ProjectionElem::Downcast(..) => qualif, + + ProjectionElem::Index(local) => qualif || Self::in_local(cx, *local), + } + } else { + bug!("This should be called if projection is not empty"); } } @@ -218,24 +224,24 @@ trait Qualif { match place { PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } => Self::in_local(cx, *local), PlaceRef { base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(_), + kind: StaticKind::Promoted(..), .. }), - projection: None, + projection: [], } => bug!("qualifying already promoted MIR"), PlaceRef { base: PlaceBase::Static(static_), - projection: None, + projection: [], } => { Self::in_static(cx, static_) }, PlaceRef { base: _, - projection: Some(_), + projection: [.., _], } => Self::in_projection(cx, place), } } @@ -249,7 +255,7 @@ trait Qualif { if let ConstValue::Unevaluated(def_id, _) = constant.literal.val { // Don't peek inside trait associated constants. if cx.tcx.trait_of_item(def_id).is_some() { - Self::in_any_value_of_ty(cx, constant.ty).unwrap_or(false) + Self::in_any_value_of_ty(cx, constant.literal.ty).unwrap_or(false) } else { let (bits, _) = cx.tcx.at(constant.span).mir_const_qualif(def_id); @@ -258,7 +264,7 @@ trait Qualif { // Just in case the type is more specific than // the definition, e.g., impl associated const // with type parameters, take it into account. - qualif && Self::mask_for_ty(cx, constant.ty) + qualif && Self::mask_for_ty(cx, constant.literal.ty) } } else { false @@ -286,13 +292,13 @@ trait Qualif { Rvalue::Ref(_, _, ref place) => { // Special-case reborrows to be more like a copy of the reference. - if let Some(ref proj) = place.projection { - if let ProjectionElem::Deref = proj.elem { - let base_ty = Place::ty_from(&place.base, &proj.base, cx.body, cx.tcx).ty; - if let ty::Ref(..) = base_ty.sty { + if let box [proj_base @ .., elem] = &place.projection { + if ProjectionElem::Deref == *elem { + let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty; + if let ty::Ref(..) = base_ty.kind { return Self::in_place(cx, PlaceRef { base: &place.base, - projection: &proj.base, + projection: proj_base, }); } } @@ -360,11 +366,11 @@ impl Qualif for HasMutInterior { // is allowed right now, and only in functions. if cx.mode == Mode::StaticMut { // Inside a `static mut`, &mut [...] is also allowed. - match ty.sty { + match ty.kind { ty::Array(..) | ty::Slice(_) => {} _ => return true, } - } else if let ty::Array(_, len) = ty.sty { + } else if let ty::Array(_, len) = ty.kind { // FIXME(eddyb) the `cx.mode == Mode::NonConstFn` condition // seems unnecessary, given that this is merely a ZST. match len.try_eval_usize(cx.tcx, cx.param_env) { @@ -433,13 +439,13 @@ impl Qualif for IsNotPromotable { fn in_static(cx: &ConstCx<'_, 'tcx>, static_: &Static<'tcx>) -> bool { match static_.kind { - StaticKind::Promoted(_) => unreachable!(), - StaticKind::Static(def_id) => { + StaticKind::Promoted(_, _) => unreachable!(), + StaticKind::Static => { // Only allow statics (not consts) to refer to other statics. let allowed = cx.mode == Mode::Static || cx.mode == Mode::StaticMut; !allowed || - cx.tcx.get_attrs(def_id).iter().any( + cx.tcx.get_attrs(static_.def_id).iter().any( |attr| attr.check_name(sym::thread_local) ) } @@ -450,30 +456,32 @@ impl Qualif for IsNotPromotable { cx: &ConstCx<'_, 'tcx>, place: PlaceRef<'_, 'tcx>, ) -> bool { - let proj = place.projection.as_ref().unwrap(); - - match proj.elem { - ProjectionElem::Deref | - ProjectionElem::Downcast(..) => return true, - - ProjectionElem::ConstantIndex {..} | - ProjectionElem::Subslice {..} | - ProjectionElem::Index(_) => {} - - ProjectionElem::Field(..) => { - if cx.mode == Mode::NonConstFn { - let base_ty = Place::ty_from(place.base, &proj.base, cx.body, cx.tcx).ty; - if let Some(def) = base_ty.ty_adt_def() { - // No promotion of union field accesses. - if def.is_union() { - return true; + if let [proj_base @ .., elem] = place.projection { + match elem { + ProjectionElem::Deref | + ProjectionElem::Downcast(..) => return true, + + ProjectionElem::ConstantIndex {..} | + ProjectionElem::Subslice {..} | + ProjectionElem::Index(_) => {} + + ProjectionElem::Field(..) => { + if cx.mode == Mode::NonConstFn { + let base_ty = Place::ty_from(place.base, proj_base, cx.body, cx.tcx).ty; + if let Some(def) = base_ty.ty_adt_def() { + // No promotion of union field accesses. + if def.is_union() { + return true; + } } } } } - } - Self::in_projection_structurally(cx, place) + Self::in_projection_structurally(cx, place) + } else { + bug!("This should be called if projection is not empty"); + } } fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool { @@ -493,7 +501,7 @@ impl Qualif for IsNotPromotable { } Rvalue::BinaryOp(op, ref lhs, _) if cx.mode == Mode::NonConstFn => { - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(cx.body, cx.tcx).sty { + if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(cx.body, cx.tcx).kind { assert!(op == BinOp::Eq || op == BinOp::Ne || op == BinOp::Le || op == BinOp::Lt || op == BinOp::Ge || op == BinOp::Gt || @@ -519,7 +527,7 @@ impl Qualif for IsNotPromotable { _return_ty: Ty<'tcx>, ) -> bool { let fn_ty = callee.ty(cx.body, cx.tcx); - match fn_ty.sty { + match fn_ty.kind { ty::FnDef(def_id, _) => { match cx.tcx.fn_sig(def_id).abi() { Abi::RustIntrinsic | @@ -537,9 +545,9 @@ impl Qualif for IsNotPromotable { | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" - | "overflowing_add" - | "overflowing_sub" - | "overflowing_mul" + | "wrapping_add" + | "wrapping_sub" + | "wrapping_mul" | "unchecked_shl" | "unchecked_shr" | "rotate_left" @@ -550,6 +558,8 @@ impl Qualif for IsNotPromotable { | "saturating_add" | "saturating_sub" | "transmute" + | "simd_insert" + | "simd_extract" => return true, _ => {} @@ -590,7 +600,7 @@ impl Qualif for IsNotImplicitlyPromotable { _return_ty: Ty<'tcx>, ) -> bool { if cx.mode == Mode::NonConstFn { - if let ty::FnDef(def_id, _) = callee.ty(cx.body, cx.tcx).sty { + if let ty::FnDef(def_id, _) = callee.ty(cx.body, cx.tcx).kind { // Never promote runtime `const fn` calls of // functions without `#[rustc_promotable]`. if !cx.tcx.is_promotable_const_fn(def_id) { @@ -664,12 +674,18 @@ struct Checker<'a, 'tcx> { temp_promotion_state: IndexVec, promotion_candidates: Vec, + + /// If `true`, do not emit errors to the user, merely collect them in `errors`. + suppress_errors: bool, + errors: Vec<(Span, String)>, } macro_rules! unleash_miri { ($this:expr) => {{ if $this.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { - $this.tcx.sess.span_warn($this.span, "skipping const checks"); + if $this.mode.requires_const_checking() && !$this.suppress_errors { + $this.tcx.sess.span_warn($this.span, "skipping const checks"); + } return; } }} @@ -725,16 +741,19 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { def_id, rpo, temp_promotion_state: temps, - promotion_candidates: vec![] + promotion_candidates: vec![], + errors: vec![], + suppress_errors: false, } } // FIXME(eddyb) we could split the errors into meaningful // categories, but enabling full miri would make that // slightly pointless (even with feature-gating). - fn not_const(&mut self) { + fn not_const(&mut self, op: impl NonConstOp) { unleash_miri!(self); - if self.mode.requires_const_checking() { + if self.mode.requires_const_checking() && !self.suppress_errors { + self.record_error(op); let mut err = struct_span_err!( self.tcx.sess, self.span, @@ -752,6 +771,14 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { } } + fn record_error(&mut self, op: impl NonConstOp) { + self.record_error_spanned(op, self.span); + } + + fn record_error_spanned(&mut self, op: impl NonConstOp, span: Span) { + self.errors.push((span, format!("{:?}", op))); + } + /// Assigns an rvalue/call qualification to the given destination. fn assign(&mut self, dest: &Place<'tcx>, source: ValueSource<'_, 'tcx>, location: Location) { trace!("assign: {:?} <- {:?}", dest, source); @@ -770,8 +797,10 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { qualifs[HasMutInterior] = false; qualifs[IsNotPromotable] = true; - if self.mode.requires_const_checking() { + debug!("suppress_errors: {}", self.suppress_errors); + if self.mode.requires_const_checking() && !self.suppress_errors { if !self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { + self.record_error(ops::MutBorrow(kind)); if let BorrowKind::Mut { .. } = kind { let mut err = struct_span_err!(self.tcx.sess, self.span, E0017, "references in {}s may only refer \ @@ -803,23 +832,18 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { // We might have a candidate for promotion. let candidate = Candidate::Ref(location); // Start by traversing to the "base", with non-deref projections removed. - let mut place_projection = &place.projection; - while let Some(proj) = place_projection { - if proj.elem == ProjectionElem::Deref { - break; - } - place_projection = &proj.base; - } + let deref_proj = + place.projection.iter().rev().find(|&elem| *elem == ProjectionElem::Deref); debug!( "qualify_consts: promotion candidate: place={:?} {:?}", - place.base, place_projection + place.base, deref_proj ); // We can only promote interior borrows of promotable temps (non-temps // don't get promoted anyway). // (If we bailed out of the loop due to a `Deref` above, we will definitely // not enter the conditional here.) - if let (PlaceBase::Local(local), None) = (&place.base, place_projection) { + if let (PlaceBase::Local(local), None) = (&place.base, deref_proj) { if self.body.local_kind(*local) == LocalKind::Temp { debug!("qualify_consts: promotion candidate: local={:?}", local); // The borrowed place doesn't have `HasMutInterior` @@ -855,27 +879,27 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { _ => {}, } - let mut dest_projection = &dest.projection; + let mut dest_projection = &dest.projection[..]; let index = loop { match (&dest.base, dest_projection) { // We treat all locals equal in constants - (&PlaceBase::Local(index), None) => break index, + (&PlaceBase::Local(index), []) => break index, // projections are transparent for assignments // we qualify the entire destination at once, even if just a field would have // stricter qualification - (base, Some(proj)) => { + (base, [proj_base @ .., _]) => { // Catch more errors in the destination. `visit_place` also checks various // projection rules like union field access and raw pointer deref let context = PlaceContext::MutatingUse(MutatingUseContext::Store); self.visit_place_base(base, context, location); - self.visit_projection(base, proj, context, location); - dest_projection = &proj.base; + self.visit_projection(base, dest_projection, context, location); + dest_projection = proj_base; }, (&PlaceBase::Static(box Static { - kind: StaticKind::Promoted(_), + kind: StaticKind::Promoted(..), .. - }), None) => bug!("promoteds don't exist yet during promotion"), - (&PlaceBase::Static(box Static{ kind: _, .. }), None) => { + }), []) => bug!("promoteds don't exist yet during promotion"), + (&PlaceBase::Static(box Static{ kind: _, .. }), []) => { // Catch more errors in the destination. `visit_place` also checks that we // do not try to access statics from constants or try to mutate statics let context = PlaceContext::MutatingUse(MutatingUseContext::Store); @@ -921,8 +945,24 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { /// Check a whole const, static initializer or const fn. fn check_const(&mut self) -> (u8, &'tcx BitSet) { + use crate::transform::check_consts as new_checker; + debug!("const-checking {} {:?}", self.mode, self.def_id); + // FIXME: Also use the new validator when features that require it (e.g. `const_if`) are + // enabled. + let use_new_validator = self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you; + if use_new_validator { + debug!("Using dataflow-based const validator"); + } + + let item = new_checker::Item::new(self.tcx, self.def_id, self.body); + let mut_borrowed_locals = new_checker::validation::compute_indirectly_mutable_locals(&item); + let mut validator = new_checker::validation::Validator::new(&item, &mut_borrowed_locals); + + validator.suppress_errors = !use_new_validator; + self.suppress_errors = use_new_validator; + let body = self.body; let mut seen_blocks = BitSet::new_empty(body.basic_blocks().len()); @@ -931,6 +971,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { seen_blocks.insert(bb.index()); self.visit_basic_block_data(bb, &body[bb]); + validator.visit_basic_block_data(bb, &body[bb]); let target = match body[bb].terminator().kind { TerminatorKind::Goto { target } | @@ -966,12 +1007,42 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { bb = target; } _ => { - self.not_const(); + self.not_const(ops::Loop); + validator.check_op(ops::Loop); break; } } } + // The new validation pass should agree with the old when running on simple const bodies + // (e.g. no `if` or `loop`). + if !use_new_validator { + let mut new_errors = validator.take_errors(); + + // FIXME: each checker sometimes emits the same error with the same span twice in a row. + self.errors.dedup(); + new_errors.dedup(); + + if self.errors != new_errors { + error!("old validator: {:?}", self.errors); + error!("new validator: {:?}", new_errors); + + // ICE on nightly if the validators do not emit exactly the same errors. + // Users can supress this panic with an unstable compiler flag (hopefully after + // filing an issue). + let opts = &self.tcx.sess.opts; + let trigger_ice = opts.unstable_features.is_nightly_build() + && !opts.debugging_opts.suppress_const_validation_back_compat_ice; + + if trigger_ice { + span_bug!( + body.span, + "{}", + VALIDATOR_MISMATCH_ERR, + ); + } + } + } // Collect all the temps we need to promote. let mut promoted_temps = BitSet::new_empty(self.temp_promotion_state.len()); @@ -980,23 +1051,25 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { for candidate in &self.promotion_candidates { match *candidate { Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => { - if let StatementKind::Assign(_, box Rvalue::Repeat( + if let StatementKind::Assign(box(_, Rvalue::Repeat( Operand::Move(Place { base: PlaceBase::Local(index), - projection: None, + projection: box [], }), _ - )) = self.body[bb].statements[stmt_idx].kind { + ))) = self.body[bb].statements[stmt_idx].kind { promoted_temps.insert(index); } } Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => { if let StatementKind::Assign( - _, - box Rvalue::Ref(_, _, Place { - base: PlaceBase::Local(index), - projection: None, - }) + box( + _, + Rvalue::Ref(_, _, Place { + base: PlaceBase::Local(index), + projection: box [], + }) + ) ) = self.body[bb].statements[stmt_idx].kind { promoted_temps.insert(index); } @@ -1027,15 +1100,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { self.super_place_base(place_base, context, location); match place_base { PlaceBase::Local(_) => {} - PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) => { + PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) => { unreachable!() } - PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => { + PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => { if self.tcx .get_attrs(*def_id) .iter() .any(|attr| attr.check_name(sym::thread_local)) { - if self.mode.requires_const_checking() { + if self.mode.requires_const_checking() && !self.suppress_errors { + self.record_error(ops::ThreadLocalAccess); span_err!(self.tcx.sess, self.span, E0625, "thread-local statics cannot be \ accessed at compile-time"); @@ -1045,7 +1119,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // Only allow statics (not consts) to refer to other statics. if self.mode == Mode::Static || self.mode == Mode::StaticMut { - if self.mode == Mode::Static && context.is_mutating_use() { + if self.mode == Mode::Static + && context.is_mutating_use() + && !self.suppress_errors + { // this is not strictly necessary as miri will also bail out // For interior mutability we can't really catch this statically as that // goes through raw pointers and intermediate temporaries, so miri has @@ -1059,7 +1136,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } unleash_miri!(self); - if self.mode.requires_const_checking() { + if self.mode.requires_const_checking() && !self.suppress_errors { + self.record_error(ops::StaticAccess); let mut err = struct_span_err!(self.tcx.sess, self.span, E0013, "{}s cannot refer to statics, use \ a constant instead", self.mode); @@ -1078,30 +1156,40 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } } - fn visit_projection( + fn visit_projection_elem( &mut self, place_base: &PlaceBase<'tcx>, - proj: &Projection<'tcx>, + proj_base: &[PlaceElem<'tcx>], + elem: &PlaceElem<'tcx>, context: PlaceContext, location: Location, ) { debug!( - "visit_place_projection: proj={:?} context={:?} location={:?}", - proj, context, location, + "visit_projection_elem: place_base={:?} proj_base={:?} elem={:?} \ + context={:?} location={:?}", + place_base, + proj_base, + elem, + context, + location, ); - self.super_projection(place_base, proj, context, location); - match proj.elem { + + self.super_projection_elem(place_base, proj_base, elem, context, location); + + match elem { ProjectionElem::Deref => { if context.is_mutating_use() { // `not_const` errors out in const contexts - self.not_const() + self.not_const(ops::MutDeref) } - let base_ty = Place::ty_from(place_base, &proj.base, self.body, self.tcx).ty; + let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty; match self.mode { - Mode::NonConstFn => {}, + Mode::NonConstFn => {} + _ if self.suppress_errors => {} _ => { - if let ty::RawPtr(_) = base_ty.sty { + if let ty::RawPtr(_) = base_ty.kind { if !self.tcx.features().const_raw_ptr_deref { + self.record_error(ops::RawPtrDeref); emit_feature_err( &self.tcx.sess.parse_sess, sym::const_raw_ptr_deref, self.span, GateIssue::Language, @@ -1120,12 +1208,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { ProjectionElem::Subslice {..} | ProjectionElem::Field(..) | ProjectionElem::Index(_) => { - let base_ty = Place::ty_from(place_base, &proj.base, self.body, self.tcx).ty; + let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty; if let Some(def) = base_ty.ty_adt_def() { if def.is_union() { match self.mode { Mode::ConstFn => { - if !self.tcx.features().const_fn_union { + if !self.tcx.features().const_fn_union + && !self.suppress_errors + { + self.record_error(ops::UnionAccess); emit_feature_err( &self.tcx.sess.parse_sess, sym::const_fn_union, self.span, GateIssue::Language, @@ -1145,7 +1236,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } ProjectionElem::Downcast(..) => { - self.not_const() + self.not_const(ops::Downcast) } } } @@ -1159,7 +1250,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // Mark the consumed locals to indicate later drops are noops. if let Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } = *place { self.cx.per_local[NeedsDrop].remove(local); } @@ -1176,11 +1267,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { if let Rvalue::Ref(_, kind, ref place) = *rvalue { // Special-case reborrows. let mut reborrow_place = None; - if let Some(ref proj) = place.projection { - if let ProjectionElem::Deref = proj.elem { - let base_ty = Place::ty_from(&place.base, &proj.base, self.body, self.tcx).ty; - if let ty::Ref(..) = base_ty.sty { - reborrow_place = Some(&proj.base); + if let box [proj_base @ .., elem] = &place.projection { + if *elem == ProjectionElem::Deref { + let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty; + if let ty::Ref(..) = base_ty.kind { + reborrow_place = Some(proj_base); } } } @@ -1201,9 +1292,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { ), }; self.visit_place_base(&place.base, ctx, location); - if let Some(proj) = proj { - self.visit_projection(&place.base, proj, ctx, location); - } + self.visit_projection(&place.base, proj, ctx, location); } else { self.super_rvalue(rvalue, location); } @@ -1232,9 +1321,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) if self.mode != Mode::NonConstFn => { unleash_miri!(self); - if !self.tcx.features().const_raw_ptr_to_usize_cast { + if !self.tcx.features().const_raw_ptr_to_usize_cast + && !self.suppress_errors + { // in const fn and constants require the feature gate // FIXME: make it unsafe inside const fn and constants + self.record_error(ops::RawPtrToIntCast); emit_feature_err( &self.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast, self.span, GateIssue::Language, @@ -1250,7 +1342,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } Rvalue::BinaryOp(op, ref lhs, _) => { - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).sty { + if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind { assert!(op == BinOp::Eq || op == BinOp::Ne || op == BinOp::Le || op == BinOp::Lt || op == BinOp::Ge || op == BinOp::Gt || @@ -1258,8 +1350,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { unleash_miri!(self); if self.mode.requires_const_checking() && - !self.tcx.features().const_compare_raw_pointers + !self.tcx.features().const_compare_raw_pointers && + !self.suppress_errors { + self.record_error(ops::RawPtrComparison); // require the feature gate inside constants and const fn // FIXME: make it unsafe to use these operations emit_feature_err( @@ -1275,7 +1369,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { Rvalue::NullaryOp(NullOp::Box, _) => { unleash_miri!(self); - if self.mode.requires_const_checking() { + if self.mode.requires_const_checking() && !self.suppress_errors { + self.record_error(ops::HeapAllocation); let mut err = struct_span_err!(self.tcx.sess, self.span, E0010, "allocations are not allowed in {}s", self.mode); err.span_label(self.span, format!("allocation not allowed in {}s", self.mode)); @@ -1309,7 +1404,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { let fn_ty = func.ty(self.body, self.tcx); let mut callee_def_id = None; let mut is_shuffle = false; - match fn_ty.sty { + match fn_ty.kind { ty::FnDef(def_id, _) => { callee_def_id = Some(def_id); match self.tcx.fn_sig(def_id).abi() { @@ -1320,9 +1415,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // special intrinsic that can be called diretly without an intrinsic // feature gate needs a language feature gate "transmute" => { - if self.mode.requires_const_checking() { + if self.mode.requires_const_checking() + && !self.suppress_errors + { // const eval transmute calls only with the feature gate if !self.tcx.features().const_transmute { + self.record_error(ops::Transmute); emit_feature_err( &self.tcx.sess.parse_sess, sym::const_transmute, self.span, GateIssue::Language, @@ -1350,7 +1448,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { .opts .debugging_opts .unleash_the_miri_inside_of_you; - if self.tcx.is_const_fn(def_id) || unleash_miri { + if self.tcx.is_const_fn(def_id) + || unleash_miri + || self.suppress_errors + { // stable const fns or unstable const fns // with their feature gate active // FIXME(eddyb) move stability checks from `is_const_fn` here. @@ -1361,6 +1462,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // since the macro is marked with the attribute. if !self.tcx.features().const_panic { // Don't allow panics in constants without the feature gate. + self.record_error(ops::Panic); emit_feature_err( &self.tcx.sess.parse_sess, sym::const_panic, @@ -1375,6 +1477,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // functions without the feature gate active in this crate in // order to report a better error message than the one below. if !self.span.allows_unstable(feature) { + self.record_error(ops::FnCallUnstable(def_id, feature)); let mut err = self.tcx.sess.struct_span_err(self.span, &format!("`{}` is not yet stable as a const fn", self.tcx.def_path_str(def_id))); @@ -1387,6 +1490,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { err.emit(); } } else { + self.record_error(ops::FnCallNonConst(def_id)); let mut err = struct_span_err!( self.tcx.sess, self.span, @@ -1402,15 +1506,18 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } } ty::FnPtr(_) => { - if self.mode.requires_const_checking() { + unleash_miri!(self); + if self.mode.requires_const_checking() && !self.suppress_errors { + self.record_error(ops::FnCallIndirect); let mut err = self.tcx.sess.struct_span_err( self.span, - &format!("function pointers are not allowed in const fn")); + "function pointers are not allowed in const fn" + ); err.emit(); } } _ => { - self.not_const(); + self.not_const(ops::FnCallOther); } } @@ -1468,13 +1575,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } // Deny *any* live drops anywhere other than functions. - if self.mode.requires_const_checking() { + if self.mode.requires_const_checking() && !self.suppress_errors { unleash_miri!(self); // HACK(eddyb): emulate a bit of dataflow analysis, // conservatively, that drop elaboration will do. let needs_drop = if let Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } = *place { if NeedsDrop::in_local(self, local) { Some(self.body.local_decls[local].source_info.span) @@ -1489,6 +1596,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // Double-check the type being dropped, to minimize false positives. let ty = place.ty(self.body, self.tcx).ty; if ty.needs_drop(self.tcx, self.param_env) { + self.record_error_spanned(ops::LiveDrop, span); struct_span_err!(self.tcx.sess, span, E0493, "destructors cannot be evaluated at compile-time") .span_label(span, format!("{}s cannot evaluate destructors", @@ -1533,7 +1641,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { self.super_statement(statement, location); } StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) => { - self.not_const(); + self.not_const(ops::IfOrMatch); } // FIXME(eddyb) should these really do nothing? StatementKind::FakeRead(..) | @@ -1570,10 +1678,20 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> (u8, &BitSet) { Checker::new(tcx, def_id, body, Mode::Const).check_const() } -pub struct QualifyAndPromoteConstants; +pub struct QualifyAndPromoteConstants<'tcx> { + pub promoted: Cell>>, +} -impl MirPass for QualifyAndPromoteConstants { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> Default for QualifyAndPromoteConstants<'tcx> { + fn default() -> Self { + QualifyAndPromoteConstants { + promoted: Cell::new(IndexVec::new()), + } + } +} + +impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants<'tcx> { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { // There's not really any point in promoting errorful MIR. if body.return_ty().references_error() { tcx.sess.delay_span_bug(body.span, "QualifyAndPromoteConstants: MIR had errors"); @@ -1585,51 +1703,24 @@ impl MirPass for QualifyAndPromoteConstants { } let def_id = src.def_id(); - let id = tcx.hir().as_local_hir_id(def_id).unwrap(); - let mut const_promoted_temps = None; - let mode = match tcx.hir().body_owner_kind(id) { - hir::BodyOwnerKind::Closure => Mode::NonConstFn, - hir::BodyOwnerKind::Fn => { - if tcx.is_const_fn(def_id) { - Mode::ConstFn - } else { - Mode::NonConstFn - } - } - hir::BodyOwnerKind::Const => { - const_promoted_temps = Some(tcx.mir_const_qualif(def_id).1); - Mode::Const - } - hir::BodyOwnerKind::Static(hir::MutImmutable) => Mode::Static, - hir::BodyOwnerKind::Static(hir::MutMutable) => Mode::StaticMut, - }; + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + + let mode = determine_mode(tcx, hir_id, def_id); debug!("run_pass: mode={:?}", mode); - if mode == Mode::NonConstFn || mode == Mode::ConstFn { + if let Mode::NonConstFn | Mode::ConstFn = mode { // This is ugly because Checker holds onto mir, // which can't be mutated until its scope ends. let (temps, candidates) = { let mut checker = Checker::new(tcx, def_id, body, mode); - if mode == Mode::ConstFn { + if let Mode::ConstFn = mode { if tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { checker.check_const(); } else if tcx.is_min_const_fn(def_id) { - // enforce `min_const_fn` for stable const fns + // Enforce `min_const_fn` for stable `const fn`s. use super::qualify_min_const_fn::is_min_const_fn; if let Err((span, err)) = is_min_const_fn(tcx, def_id, body) { - let mut diag = struct_span_err!( - tcx.sess, - span, - E0723, - "{}", - err, - ); - diag.note("for more information, see issue \ - https://github.com/rust-lang/rust/issues/57563"); - diag.help( - "add `#![feature(const_fn)]` to the crate attributes to enable", - ); - diag.emit(); + error_min_const_fn_violation(tcx, span, err); } else { // this should not produce any errors, but better safe than sorry // FIXME(#53819) @@ -1649,115 +1740,136 @@ impl MirPass for QualifyAndPromoteConstants { }; // Do the actual promotion, now that we know what's viable. - promote_consts::promote_candidates(body, tcx, temps, candidates); + self.promoted.set( + promote_consts::promote_candidates(def_id, body, tcx, temps, candidates) + ); } else { - if !body.control_flow_destroyed.is_empty() { - let mut locals = body.vars_iter(); - if let Some(local) = locals.next() { - let span = body.local_decls[local].source_info.span; - let mut error = tcx.sess.struct_span_err( - span, - &format!( - "new features like let bindings are not permitted in {}s \ - which also use short circuiting operators", - mode, - ), - ); - for (span, kind) in body.control_flow_destroyed.iter() { - error.span_note( - *span, - &format!("use of {} here does not actually short circuit due to \ - the const evaluator presently not being able to do control flow. \ - See https://github.com/rust-lang/rust/issues/49146 for more \ - information.", kind), - ); - } - for local in locals { - let span = body.local_decls[local].source_info.span; - error.span_note( - span, - "more locals defined here", - ); - } - error.emit(); - } - } - let promoted_temps = if mode == Mode::Const { - // Already computed by `mir_const_qualif`. - const_promoted_temps.unwrap() - } else { - Checker::new(tcx, def_id, body, mode).check_const().1 + check_short_circuiting_in_const_local(tcx, body, mode); + + let promoted_temps = match mode { + Mode::Const => tcx.mir_const_qualif(def_id).1, + _ => Checker::new(tcx, def_id, body, mode).check_const().1, }; + remove_drop_and_storage_dead_on_promoted_locals(body, promoted_temps); + } - // In `const` and `static` everything without `StorageDead` - // is `'static`, we don't have to create promoted MIR fragments, - // just remove `Drop` and `StorageDead` on "promoted" locals. - debug!("run_pass: promoted_temps={:?}", promoted_temps); - for block in body.basic_blocks_mut() { - block.statements.retain(|statement| { - match statement.kind { - StatementKind::StorageDead(index) => { - !promoted_temps.contains(index) - } - _ => true - } - }); - let terminator = block.terminator_mut(); - match terminator.kind { - TerminatorKind::Drop { - location: Place { - base: PlaceBase::Local(index), - projection: None, - }, - target, - .. - } => { - if promoted_temps.contains(index) { - terminator.kind = TerminatorKind::Goto { - target, - }; - } - } - _ => {} - } - } + if mode == Mode::Static && !tcx.has_attr(def_id, sym::thread_local) { + // `static`s (not `static mut`s) which are not `#[thread_local]` must be `Sync`. + check_static_is_sync(tcx, body, hir_id); + } + } +} + +fn determine_mode(tcx: TyCtxt<'_>, hir_id: HirId, def_id: DefId) -> Mode { + match tcx.hir().body_owner_kind(hir_id) { + hir::BodyOwnerKind::Closure => Mode::NonConstFn, + hir::BodyOwnerKind::Fn if tcx.is_const_fn(def_id) => Mode::ConstFn, + hir::BodyOwnerKind::Fn => Mode::NonConstFn, + hir::BodyOwnerKind::Const => Mode::Const, + hir::BodyOwnerKind::Static(hir::MutImmutable) => Mode::Static, + hir::BodyOwnerKind::Static(hir::MutMutable) => Mode::StaticMut, + } +} + +fn error_min_const_fn_violation(tcx: TyCtxt<'_>, span: Span, msg: Cow<'_, str>) { + struct_span_err!(tcx.sess, span, E0723, "{}", msg) + .note("for more information, see issue https://github.com/rust-lang/rust/issues/57563") + .help("add `#![feature(const_fn)]` to the crate attributes to enable") + .emit(); +} + +fn check_short_circuiting_in_const_local(tcx: TyCtxt<'_>, body: &mut Body<'tcx>, mode: Mode) { + if body.control_flow_destroyed.is_empty() { + return; + } + + let mut locals = body.vars_iter(); + if let Some(local) = locals.next() { + let span = body.local_decls[local].source_info.span; + let mut error = tcx.sess.struct_span_err( + span, + &format!( + "new features like let bindings are not permitted in {}s \ + which also use short circuiting operators", + mode, + ), + ); + for (span, kind) in body.control_flow_destroyed.iter() { + error.span_note( + *span, + &format!("use of {} here does not actually short circuit due to \ + the const evaluator presently not being able to do control flow. \ + See https://github.com/rust-lang/rust/issues/49146 for more \ + information.", kind), + ); + } + for local in locals { + let span = body.local_decls[local].source_info.span; + error.span_note(span, "more locals defined here"); } + error.emit(); + } +} - // Statics must be Sync. - if mode == Mode::Static { - // `#[thread_local]` statics don't have to be `Sync`. - for attr in &tcx.get_attrs(def_id)[..] { - if attr.check_name(sym::thread_local) { - return; - } +/// In `const` and `static` everything without `StorageDead` +/// is `'static`, we don't have to create promoted MIR fragments, +/// just remove `Drop` and `StorageDead` on "promoted" locals. +fn remove_drop_and_storage_dead_on_promoted_locals( + body: &mut Body<'tcx>, + promoted_temps: &BitSet, +) { + debug!("run_pass: promoted_temps={:?}", promoted_temps); + + for block in body.basic_blocks_mut() { + block.statements.retain(|statement| { + match statement.kind { + StatementKind::StorageDead(index) => !promoted_temps.contains(index), + _ => true } - let ty = body.return_ty(); - tcx.infer_ctxt().enter(|infcx| { - let param_env = ty::ParamEnv::empty(); - let cause = traits::ObligationCause::new(body.span, id, traits::SharedStatic); - let mut fulfillment_cx = traits::FulfillmentContext::new(); - fulfillment_cx.register_bound(&infcx, - param_env, - ty, - tcx.require_lang_item(lang_items::SyncTraitLangItem), - cause); - if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { - infcx.report_fulfillment_errors(&err, None, false); - } - }); + }); + let terminator = block.terminator_mut(); + match terminator.kind { + TerminatorKind::Drop { + location: Place { + base: PlaceBase::Local(index), + projection: box [], + }, + target, + .. + } if promoted_temps.contains(index) => { + terminator.kind = TerminatorKind::Goto { target }; + } + _ => {} } } } +fn check_static_is_sync(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, hir_id: HirId) { + let ty = body.return_ty(); + tcx.infer_ctxt().enter(|infcx| { + let cause = traits::ObligationCause::new(body.span, hir_id, traits::SharedStatic); + let mut fulfillment_cx = traits::FulfillmentContext::new(); + let sync_def_id = tcx.require_lang_item(lang_items::SyncTraitLangItem, Some(body.span)); + fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), ty, sync_def_id, cause); + if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { + infcx.report_fulfillment_errors(&err, None, false); + } + }); +} + fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { let attrs = tcx.get_attrs(def_id); let attr = attrs.iter().find(|a| a.check_name(sym::rustc_args_required_const))?; let mut ret = FxHashSet::default(); for meta in attr.meta_item_list()? { - match meta.literal()?.node { + match meta.literal()?.kind { LitKind::Int(a, _) => { ret.insert(a as usize); } _ => return None, } } Some(ret) } + +const VALIDATOR_MISMATCH_ERR: &str = + r"Disagreement between legacy and dataflow-based const validators. + After filing an issue, use `-Zsuppress-const-validation-back-compat-ice` to compile your code."; diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index b84bc31ec2ae2..cf0ee1bf09222 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -5,6 +5,8 @@ use rustc::ty::{self, Predicate, Ty, TyCtxt, adjustment::{PointerCast}}; use rustc_target::spec::abi; use std::borrow::Cow; use syntax_pos::Span; +use syntax::symbol::{sym, Symbol}; +use syntax::attr; type McfResult = Result<(), (Span, Cow<'static, str>)>; @@ -30,7 +32,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - if Some(pred.def_id()) == tcx.lang_items().sized_trait() { continue; } - match pred.skip_binder().self_ty().sty { + match pred.skip_binder().self_ty().kind { ty::Param(ref p) => { let generics = tcx.generics_of(current); let def = generics.type_param(p, tcx); @@ -67,9 +69,9 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - )?; for bb in body.basic_blocks() { - check_terminator(tcx, body, bb.terminator())?; + check_terminator(tcx, body, def_id, bb.terminator())?; for stmt in &bb.statements { - check_statement(tcx, body, stmt)?; + check_statement(tcx, body, def_id, stmt)?; } } Ok(()) @@ -77,7 +79,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> McfResult { for ty in ty.walk() { - match ty.sty { + match ty.kind { ty::Ref(_, _, hir::Mutability::MutMutable) => return Err(( span, "mutable references in const fn are unstable".into(), @@ -121,16 +123,17 @@ fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> Mc fn check_rvalue( tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, + body: &Body<'tcx>, + def_id: DefId, rvalue: &Rvalue<'tcx>, span: Span, ) -> McfResult { match rvalue { Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => { - check_operand(operand, span) + check_operand(tcx, operand, span, def_id, body) } Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) => { - check_place(place, span) + check_place(tcx, place, span, def_id, body) } Rvalue::Cast(CastKind::Misc, operand, cast_ty) => { use rustc::ty::cast::CastTy; @@ -144,11 +147,11 @@ fn check_rvalue( (CastTy::RPtr(_), CastTy::Float) => bug!(), (CastTy::RPtr(_), CastTy::Int(_)) => bug!(), (CastTy::Ptr(_), CastTy::RPtr(_)) => bug!(), - _ => check_operand(operand, span), + _ => check_operand(tcx, operand, span, def_id, body), } } Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, _) => { - check_operand(operand, span) + check_operand(tcx, operand, span, def_id, body) } Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), _, _) | Rvalue::Cast(CastKind::Pointer(PointerCast::ClosureFnPointer(_)), _, _) | @@ -162,8 +165,8 @@ fn check_rvalue( )), // binops are fine on integers Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { - check_operand(lhs, span)?; - check_operand(rhs, span)?; + check_operand(tcx, lhs, span, def_id, body)?; + check_operand(tcx, rhs, span, def_id, body)?; let ty = lhs.ty(body, tcx); if ty.is_integral() || ty.is_bool() || ty.is_char() { Ok(()) @@ -182,7 +185,7 @@ fn check_rvalue( Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, tcx); if ty.is_integral() || ty.is_bool() { - check_operand(operand, span) + check_operand(tcx, operand, span, def_id, body) } else { Err(( span, @@ -192,7 +195,7 @@ fn check_rvalue( } Rvalue::Aggregate(_, operands) => { for operand in operands { - check_operand(operand, span)?; + check_operand(tcx, operand, span, def_id, body)?; } Ok(()) } @@ -201,21 +204,22 @@ fn check_rvalue( fn check_statement( tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, + body: &Body<'tcx>, + def_id: DefId, statement: &Statement<'tcx>, ) -> McfResult { let span = statement.source_info.span; match &statement.kind { - StatementKind::Assign(place, rval) => { - check_place(place, span)?; - check_rvalue(tcx, body, rval, span) + StatementKind::Assign(box(place, rval)) => { + check_place(tcx, place, span, def_id, body)?; + check_rvalue(tcx, body, def_id, rval, span) } StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) => { Err((span, "loops and conditional expressions are not stable in const fn".into())) } - StatementKind::FakeRead(_, place) => check_place(place, span), + StatementKind::FakeRead(_, place) => check_place(tcx, place, span, def_id, body), // just an assignment StatementKind::SetDiscriminant { .. } => Ok(()), @@ -234,48 +238,75 @@ fn check_statement( } fn check_operand( + tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, + def_id: DefId, + body: &Body<'tcx> ) -> McfResult { match operand { Operand::Move(place) | Operand::Copy(place) => { - check_place(place, span) + check_place(tcx, place, span, def_id, body) } Operand::Constant(_) => Ok(()), } } fn check_place( + tcx: TyCtxt<'tcx>, place: &Place<'tcx>, span: Span, + def_id: DefId, + body: &Body<'tcx> ) -> McfResult { - place.iterate(|place_base, place_projection| { - for proj in place_projection { - match proj.elem { - ProjectionElem::Downcast(..) => { - return Err((span, "`match` or `if let` in `const fn` is unstable".into())); + let mut cursor = &*place.projection; + while let [proj_base @ .., elem] = cursor { + cursor = proj_base; + match elem { + ProjectionElem::Downcast(..) => { + return Err((span, "`match` or `if let` in `const fn` is unstable".into())); + } + ProjectionElem::Field(..) => { + let base_ty = Place::ty_from(&place.base, &proj_base, body, tcx).ty; + if let Some(def) = base_ty.ty_adt_def() { + // No union field accesses in `const fn` + if def.is_union() { + if !feature_allowed(tcx, def_id, sym::const_fn_union) { + return Err((span, "accessing union fields is unstable".into())); + } + } } - ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Deref - | ProjectionElem::Field(..) - | ProjectionElem::Index(_) => {} } + ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Deref + | ProjectionElem::Index(_) => {} } + } - match place_base { - PlaceBase::Static(box Static { kind: StaticKind::Static(_), .. }) => { - Err((span, "cannot access `static` items in const fn".into())) - } - PlaceBase::Local(_) - | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }) => Ok(()), + match place.base { + PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => { + Err((span, "cannot access `static` items in const fn".into())) } - }) + PlaceBase::Local(_) + | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => Ok(()), + } +} + +/// Returns whether `allow_internal_unstable(..., , ...)` is present. +fn feature_allowed( + tcx: TyCtxt<'tcx>, + def_id: DefId, + feature_gate: Symbol, +) -> bool { + attr::allow_internal_unstable(&tcx.get_attrs(def_id), &tcx.sess.diagnostic()) + .map_or(false, |mut features| features.any(|name| name == feature_gate)) } fn check_terminator( tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, + def_id: DefId, terminator: &Terminator<'tcx>, ) -> McfResult { let span = terminator.source_info.span; @@ -285,11 +316,11 @@ fn check_terminator( | TerminatorKind::Resume => Ok(()), TerminatorKind::Drop { location, .. } => { - check_place(location, span) + check_place(tcx, location, span, def_id, body) } TerminatorKind::DropAndReplace { location, value, .. } => { - check_place(location, span)?; - check_operand(value, span) + check_place(tcx, location, span, def_id, body)?; + check_operand(tcx, value, span, def_id, body) }, TerminatorKind::FalseEdges { .. } | TerminatorKind::SwitchInt { .. } => Err(( @@ -311,7 +342,7 @@ fn check_terminator( cleanup: _, } => { let fn_ty = func.ty(body, tcx); - if let ty::FnDef(def_id, _) = fn_ty.sty { + if let ty::FnDef(def_id, _) = fn_ty.kind { // some intrinsics are waved through if called inside the // standard library. Users never need to call them directly @@ -341,10 +372,10 @@ fn check_terminator( )), } - check_operand(func, span)?; + check_operand(tcx, func, span, def_id, body)?; for arg in args { - check_operand(arg, span)?; + check_operand(tcx, arg, span, def_id, body)?; } Ok(()) } else { @@ -358,7 +389,7 @@ fn check_terminator( msg: _, target: _, cleanup: _, - } => check_operand(cond, span), + } => check_operand(tcx, cond, span, def_id, body), TerminatorKind::FalseUnwind { .. } => { Err((span, "loops are not allowed in const fn".into())) @@ -379,9 +410,9 @@ fn is_intrinsic_whitelisted(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { | "add_with_overflow" // ~> .overflowing_add | "sub_with_overflow" // ~> .overflowing_sub | "mul_with_overflow" // ~> .overflowing_mul - | "overflowing_add" // ~> .wrapping_add - | "overflowing_sub" // ~> .wrapping_sub - | "overflowing_mul" // ~> .wrapping_mul + | "wrapping_add" // ~> .wrapping_add + | "wrapping_sub" // ~> .wrapping_sub + | "wrapping_mul" // ~> .wrapping_mul | "saturating_add" // ~> .saturating_add | "saturating_sub" // ~> .saturating_sub | "unchecked_shl" // ~> .wrapping_shl diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index adba9097d12df..e1994c5f639b0 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -1,6 +1,6 @@ use rustc::ty::TyCtxt; use rustc::mir::*; -use rustc_data_structures::bit_set::BitSet; +use rustc_index::bit_set::BitSet; use crate::transform::{MirPass, MirSource}; use crate::util::patch::MirPatch; @@ -18,8 +18,8 @@ pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) RemoveNoopLandingPads.remove_nop_landing_pads(body) } -impl MirPass for RemoveNoopLandingPads { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { remove_noop_landing_pads(tcx, body); } } @@ -41,10 +41,10 @@ impl RemoveNoopLandingPads { // These are all nops in a landing pad } - StatementKind::Assign(Place { + StatementKind::Assign(box(Place { base: PlaceBase::Local(_), - projection: None, - }, box Rvalue::Use(_)) => { + projection: box [], + }, Rvalue::Use(_))) => { // Writing to a local (e.g., a drop flag) does not // turn a landing pad to a non-nop } diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 7fe8480c819e6..6edd28a4259a5 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -3,19 +3,21 @@ use syntax::ast; use syntax::symbol::sym; use syntax_pos::Span; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, TyCtxt, Ty}; use rustc::hir::def_id::DefId; -use rustc::mir::{self, Body, Location}; -use rustc_data_structures::bit_set::BitSet; +use rustc::mir::{self, Body, Location, Local}; +use rustc_index::bit_set::BitSet; use crate::transform::{MirPass, MirSource}; use crate::dataflow::{do_dataflow, DebugFormatted}; use crate::dataflow::MoveDataParamEnv; use crate::dataflow::BitDenotation; use crate::dataflow::DataflowResults; +use crate::dataflow::DataflowResultsCursor; use crate::dataflow::{ DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces }; +use crate::dataflow::IndirectlyMutableLocals; use crate::dataflow::move_paths::{MovePathIndex, LookupResult}; use crate::dataflow::move_paths::{HasMoveData, MoveData}; @@ -23,8 +25,8 @@ use crate::dataflow::has_rustc_mir_with; pub struct SanityCheck; -impl MirPass for SanityCheck { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for SanityCheck { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { let def_id = src.def_id(); if !tcx.has_attr(def_id, sym::rustc_mir) { debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); @@ -50,6 +52,10 @@ impl MirPass for SanityCheck { do_dataflow(tcx, body, def_id, &attributes, &dead_unwinds, DefinitelyInitializedPlaces::new(tcx, body, &mdpe), |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i])); + let flow_indirectly_mut = + do_dataflow(tcx, body, def_id, &attributes, &dead_unwinds, + IndirectlyMutableLocals::new(tcx, body, param_env), + |_, i| DebugFormatted::new(&i)); if has_rustc_mir_with(&attributes, sym::rustc_peek_maybe_init).is_some() { sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_inits); @@ -60,6 +66,9 @@ impl MirPass for SanityCheck { if has_rustc_mir_with(&attributes, sym::rustc_peek_definite_init).is_some() { sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_def_inits); } + if has_rustc_mir_with(&attributes, sym::rustc_peek_indirectly_mutable).is_some() { + sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_indirectly_mut); + } if has_rustc_mir_with(&attributes, sym::stop_after_dataflow).is_some() { tcx.sess.fatal("stop_after_dataflow ended compilation"); } @@ -88,151 +97,196 @@ pub fn sanity_check_via_rustc_peek<'tcx, O>( def_id: DefId, _attributes: &[ast::Attribute], results: &DataflowResults<'tcx, O>, -) where - O: BitDenotation<'tcx, Idx = MovePathIndex> + HasMoveData<'tcx>, -{ +) where O: RustcPeekAt<'tcx> { debug!("sanity_check_via_rustc_peek def_id: {:?}", def_id); - // FIXME: this is not DRY. Figure out way to abstract this and - // `dataflow::build_sets`. (But note it is doing non-standard - // stuff, so such generalization may not be realistic.) - for bb in body.basic_blocks().indices() { - each_block(tcx, body, results, bb); - } -} + let mut cursor = DataflowResultsCursor::new(results, body); -fn each_block<'tcx, O>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - results: &DataflowResults<'tcx, O>, - bb: mir::BasicBlock, -) where - O: BitDenotation<'tcx, Idx = MovePathIndex> + HasMoveData<'tcx>, -{ - let move_data = results.0.operator.move_data(); - let mir::BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = body[bb]; - - let (args, span) = match is_rustc_peek(tcx, terminator) { - Some(args_and_span) => args_and_span, - None => return, - }; - assert!(args.len() == 1); - let peek_arg_place = match args[0] { - mir::Operand::Copy(ref place @ mir::Place { - base: mir::PlaceBase::Local(_), - projection: None, - }) | - mir::Operand::Move(ref place @ mir::Place { - base: mir::PlaceBase::Local(_), - projection: None, - }) => Some(place), - _ => None, - }; - - let peek_arg_place = match peek_arg_place { - Some(arg) => arg, - None => { - tcx.sess.diagnostic().span_err( - span, "dataflow::sanity_check cannot feed a non-temp to rustc_peek."); - return; - } - }; - - let mut on_entry = results.0.sets.entry_set_for(bb.index()).to_owned(); - let mut trans = results.0.sets.trans_for(bb.index()).clone(); - - // Emulate effect of all statements in the block up to (but not - // including) the borrow within `peek_arg_place`. Do *not* include - // call to `peek_arg_place` itself (since we are peeking the state - // of the argument at time immediate preceding Call to - // `rustc_peek`). - - for (j, stmt) in statements.iter().enumerate() { - debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt); - let (place, rvalue) = match stmt.kind { - mir::StatementKind::Assign(ref place, ref rvalue) => { - (place, rvalue) + let peek_calls = body + .basic_blocks() + .iter_enumerated() + .filter_map(|(bb, block_data)| { + PeekCall::from_terminator(tcx, block_data.terminator()) + .map(|call| (bb, block_data, call)) + }); + + for (bb, block_data, call) in peek_calls { + // Look for a sequence like the following to indicate that we should be peeking at `_1`: + // _2 = &_1; + // rustc_peek(_2); + // + // /* or */ + // + // _2 = _1; + // rustc_peek(_2); + let (statement_index, peek_rval) = block_data + .statements + .iter() + .enumerate() + .filter_map(|(i, stmt)| value_assigned_to_local(stmt, call.arg).map(|rval| (i, rval))) + .next() + .expect("call to rustc_peek should be preceded by \ + assignment to temporary holding its argument"); + + match (call.kind, peek_rval) { + | (PeekCallKind::ByRef, mir::Rvalue::Ref(_, _, place)) + | (PeekCallKind::ByVal, mir::Rvalue::Use(mir::Operand::Move(place))) + | (PeekCallKind::ByVal, mir::Rvalue::Use(mir::Operand::Copy(place))) + => { + let loc = Location { block: bb, statement_index }; + cursor.seek(loc); + let state = cursor.get(); + results.operator().peek_at(tcx, place, state, call); } - mir::StatementKind::FakeRead(..) | - mir::StatementKind::StorageLive(_) | - mir::StatementKind::StorageDead(_) | - mir::StatementKind::InlineAsm { .. } | - mir::StatementKind::Retag { .. } | - mir::StatementKind::AscribeUserType(..) | - mir::StatementKind::Nop => continue, - mir::StatementKind::SetDiscriminant{ .. } => - span_bug!(stmt.source_info.span, - "sanity_check should run before Deaggregator inserts SetDiscriminant"), - }; - if place == peek_arg_place { - if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = **rvalue { - // Okay, our search is over. - match move_data.rev_lookup.find(peeking_at_place.as_ref()) { - LookupResult::Exact(peek_mpi) => { - let bit_state = on_entry.contains(peek_mpi); - debug!("rustc_peek({:?} = &{:?}) bit_state: {}", - place, peeking_at_place, bit_state); - if !bit_state { - tcx.sess.span_err(span, "rustc_peek: bit not set"); - } - } - LookupResult::Parent(..) => { - tcx.sess.span_err(span, "rustc_peek: argument untracked"); - } - } - return; - } else { - // Our search should have been over, but the input - // does not match expectations of `rustc_peek` for - // this sanity_check. + _ => { let msg = "rustc_peek: argument expression \ - must be immediate borrow of form `&expr`"; - tcx.sess.span_err(span, msg); + must be either `place` or `&place`"; + tcx.sess.span_err(call.span, msg); } } + } +} - let lhs_mpi = move_data.rev_lookup.find(place.as_ref()); - - debug!("rustc_peek: computing effect on place: {:?} ({:?}) in stmt: {:?}", - place, lhs_mpi, stmt); - // reset GEN and KILL sets before emulating their effect. - trans.clear(); - results.0.operator.before_statement_effect( - &mut trans, - Location { block: bb, statement_index: j }); - results.0.operator.statement_effect( - &mut trans, - Location { block: bb, statement_index: j }); - trans.apply(&mut on_entry); +/// If `stmt` is an assignment where the LHS is the given local (with no projections), returns the +/// RHS of the assignment. +fn value_assigned_to_local<'a, 'tcx>( + stmt: &'a mir::Statement<'tcx>, + local: Local, +) -> Option<&'a mir::Rvalue<'tcx>> { + if let mir::StatementKind::Assign(box (place, rvalue)) = &stmt.kind { + if let mir::Place { base: mir::PlaceBase::Local(l), projection: box [] } = place { + if local == *l { + return Some(&*rvalue); + } + } } - results.0.operator.before_terminator_effect( - &mut trans, - Location { block: bb, statement_index: statements.len() }); + None +} - tcx.sess.span_err(span, &format!("rustc_peek: MIR did not match \ - anticipated pattern; note that \ - rustc_peek expects input of \ - form `&expr`")); +#[derive(Clone, Copy, Debug)] +enum PeekCallKind { + ByVal, + ByRef, } -fn is_rustc_peek<'a, 'tcx>( - tcx: TyCtxt<'tcx>, - terminator: &'a Option>, -) -> Option<(&'a [mir::Operand<'tcx>], Span)> { - if let Some(mir::Terminator { ref kind, source_info, .. }) = *terminator { - if let mir::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind { - if let mir::Operand::Constant(ref func) = *oper { - if let ty::FnDef(def_id, _) = func.ty.sty { - let abi = tcx.fn_sig(def_id).abi(); - let name = tcx.item_name(def_id); - if abi == Abi::RustIntrinsic && name == sym::rustc_peek { - return Some((args, source_info.span)); +impl PeekCallKind { + fn from_arg_ty(arg: Ty<'_>) -> Self { + match arg.kind { + ty::Ref(_, _, _) => PeekCallKind::ByRef, + _ => PeekCallKind::ByVal, + } + } +} + +#[derive(Clone, Copy, Debug)] +pub struct PeekCall { + arg: Local, + kind: PeekCallKind, + span: Span, +} + +impl PeekCall { + fn from_terminator<'tcx>( + tcx: TyCtxt<'tcx>, + terminator: &mir::Terminator<'tcx>, + ) -> Option { + use mir::{Operand, Place, PlaceBase}; + + let span = terminator.source_info.span; + if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } = + &terminator.kind + { + if let ty::FnDef(def_id, substs) = func.literal.ty.kind { + let sig = tcx.fn_sig(def_id); + let name = tcx.item_name(def_id); + if sig.abi() != Abi::RustIntrinsic || name != sym::rustc_peek { + return None; + } + + assert_eq!(args.len(), 1); + let kind = PeekCallKind::from_arg_ty(substs.type_at(0)); + let arg = match args[0] { + | Operand::Copy(Place { base: PlaceBase::Local(local), projection: box [] }) + | Operand::Move(Place { base: PlaceBase::Local(local), projection: box [] }) + => local, + + _ => { + tcx.sess.diagnostic().span_err( + span, "dataflow::sanity_check cannot feed a non-temp to rustc_peek."); + return None; } + }; + + return Some(PeekCall { + arg, + kind, + span, + }); + } + } + + None + } +} + +pub trait RustcPeekAt<'tcx>: BitDenotation<'tcx> { + fn peek_at( + &self, + tcx: TyCtxt<'tcx>, + place: &mir::Place<'tcx>, + flow_state: &BitSet, + call: PeekCall, + ); +} + +impl<'tcx, O> RustcPeekAt<'tcx> for O + where O: BitDenotation<'tcx, Idx = MovePathIndex> + HasMoveData<'tcx>, +{ + fn peek_at( + &self, + tcx: TyCtxt<'tcx>, + place: &mir::Place<'tcx>, + flow_state: &BitSet, + call: PeekCall, + ) { + match self.move_data().rev_lookup.find(place.as_ref()) { + LookupResult::Exact(peek_mpi) => { + let bit_state = flow_state.contains(peek_mpi); + debug!("rustc_peek({:?} = &{:?}) bit_state: {}", + call.arg, place, bit_state); + if !bit_state { + tcx.sess.span_err(call.span, "rustc_peek: bit not set"); } } + + LookupResult::Parent(..) => { + tcx.sess.span_err(call.span, "rustc_peek: argument untracked"); + } + } + } +} + +impl<'tcx> RustcPeekAt<'tcx> for IndirectlyMutableLocals<'_, 'tcx> { + fn peek_at( + &self, + tcx: TyCtxt<'tcx>, + place: &mir::Place<'tcx>, + flow_state: &BitSet, + call: PeekCall, + ) { + warn!("peek_at: place={:?}", place); + let local = match place { + mir::Place { base: mir::PlaceBase::Local(l), projection: box [] } => *l, + _ => { + tcx.sess.span_err(call.span, "rustc_peek: argument was not a local"); + return; + } + }; + + if !flow_state.contains(local) { + tcx.sess.span_err(call.span, "rustc_peek: bit not set"); } } - return None; } diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 2eed9d453f233..9ffff9a92fa53 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -27,8 +27,8 @@ //! naively generate still contains the `_a = ()` write in the unreachable block "after" the //! return. -use rustc_data_structures::bit_set::BitSet; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::{Idx, IndexVec}; use rustc::ty::TyCtxt; use rustc::mir::*; use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext}; @@ -52,12 +52,12 @@ pub fn simplify_cfg(body: &mut Body<'_>) { body.basic_blocks_mut().raw.shrink_to_fit(); } -impl MirPass for SimplifyCfg { +impl<'tcx> MirPass<'tcx> for SimplifyCfg { fn name(&self) -> Cow<'_, str> { Cow::Borrowed(&self.label) } - fn run_pass<'tcx>(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body); simplify_cfg(body); } @@ -292,8 +292,8 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { pub struct SimplifyLocals; -impl MirPass for SimplifyLocals { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for SimplifyLocals { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { let mut marker = DeclMarker { locals: BitSet::new_empty(body.local_decls.len()) }; marker.visit_body(body); // Return pointer and arguments are always live diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 9ffa3db4c2eb0..0a509666d34ae 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -14,12 +14,12 @@ impl SimplifyBranches { } } -impl MirPass for SimplifyBranches { +impl<'tcx> MirPass<'tcx> for SimplifyBranches { fn name(&self) -> Cow<'_, str> { Cow::Borrowed(&self.label) } - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { let param_env = tcx.param_env(src.def_id()); for block in body.basic_blocks_mut() { let terminator = block.terminator_mut(); diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs index 60489e7fa3668..efa39d91205b4 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -30,14 +30,14 @@ use rustc::ty; use rustc::ty::TyCtxt; use rustc::mir::*; use rustc::mir::visit::{Visitor, PlaceContext, NonUseContext}; -use rustc_data_structures::indexed_vec::{IndexVec}; +use rustc_index::vec::{IndexVec}; use crate::transform::{MirPass, MirSource}; use crate::util::patch::MirPatch; pub struct UniformArrayMoveOut; -impl MirPass for UniformArrayMoveOut { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for UniformArrayMoveOut { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { let mut patch = MirPatch::new(body); let param_env = tcx.param_env(src.def_id()); { @@ -61,15 +61,15 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue { - if let Some(ref proj) = src_place.projection { + if let box [proj_base @ .., elem] = &src_place.projection { if let ProjectionElem::ConstantIndex{offset: _, min_length: _, - from_end: false} = proj.elem { + from_end: false} = elem { // no need to transformation } else { let place_ty = - Place::ty_from(&src_place.base, &proj.base, self.body, self.tcx).ty; - if let ty::Array(item_ty, const_size) = place_ty.sty { + Place::ty_from(&src_place.base, proj_base, self.body, self.tcx).ty; + if let ty::Array(item_ty, const_size) = place_ty.kind { if let Some(size) = const_size.try_eval_usize(self.tcx, self.param_env) { assert!(size <= u32::max_value() as u64, "uniform array move out doesn't supported @@ -78,7 +78,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { location, dst_place, &src_place.base, - proj, + &src_place.projection, item_ty, size as u32, ); @@ -97,73 +97,76 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { location: Location, dst_place: &Place<'tcx>, base: &PlaceBase<'tcx>, - proj: &Projection<'tcx>, + proj: &[PlaceElem<'tcx>], item_ty: &'tcx ty::TyS<'tcx>, size: u32) { - match proj.elem { - // uniforms statements like_10 = move _2[:-1]; - ProjectionElem::Subslice{from, to} => { - self.patch.make_nop(location); - let temps : Vec<_> = (from..(size-to)).map(|i| { - let temp = self.patch.new_temp(item_ty, self.body.source_info(location).span); - self.patch.add_statement(location, StatementKind::StorageLive(temp)); + if let [proj_base @ .., elem] = proj { + match elem { + // uniforms statements like_10 = move _2[:-1]; + ProjectionElem::Subslice{from, to} => { + self.patch.make_nop(location); + let temps : Vec<_> = (*from..(size-*to)).map(|i| { + let temp = + self.patch.new_temp(item_ty, self.body.source_info(location).span); + self.patch.add_statement(location, StatementKind::StorageLive(temp)); + + let mut projection = proj_base.to_vec(); + projection.push(ProjectionElem::ConstantIndex { + offset: i, + min_length: size, + from_end: false, + }); + self.patch.add_assign(location, + Place::from(temp), + Rvalue::Use( + Operand::Move( + Place { + base: base.clone(), + projection: projection.into_boxed_slice(), + } + ) + ) + ); + temp + }).collect(); + self.patch.add_assign( + location, + dst_place.clone(), + Rvalue::Aggregate( + box AggregateKind::Array(item_ty), + temps.iter().map( + |x| Operand::Move(Place::from(*x)) + ).collect() + ) + ); + for temp in temps { + self.patch.add_statement(location, StatementKind::StorageDead(temp)); + } + } + // uniforms statements like _11 = move _2[-1 of 1]; + ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => { + self.patch.make_nop(location); + + let mut projection = proj_base.to_vec(); + projection.push(ProjectionElem::ConstantIndex { + offset: size - offset, + min_length: size, + from_end: false, + }); self.patch.add_assign(location, - Place::from(temp), + dst_place.clone(), Rvalue::Use( Operand::Move( Place { base: base.clone(), - projection: Some(box Projection { - base: proj.base.clone(), - elem: ProjectionElem::ConstantIndex { - offset: i, - min_length: size, - from_end: false, - } - }), + projection: projection.into_boxed_slice(), } ) ) ); - temp - }).collect(); - self.patch.add_assign( - location, - dst_place.clone(), - Rvalue::Aggregate( - box AggregateKind::Array(item_ty), - temps.iter().map( - |x| Operand::Move(Place::from(*x)) - ).collect() - ) - ); - for temp in temps { - self.patch.add_statement(location, StatementKind::StorageDead(temp)); } + _ => {} } - // uniforms statements like _11 = move _2[-1 of 1]; - ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => { - self.patch.make_nop(location); - self.patch.add_assign(location, - dst_place.clone(), - Rvalue::Use( - Operand::Move( - Place { - base: base.clone(), - projection: Some(box Projection { - base: proj.base.clone(), - elem: ProjectionElem::ConstantIndex { - offset: size - offset, - min_length: size, - from_end: false, - }, - }), - } - ) - ) - ); - } - _ => {} } } } @@ -184,8 +187,8 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { pub struct RestoreSubsliceArrayMoveOut; -impl MirPass for RestoreSubsliceArrayMoveOut { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { let mut patch = MirPatch::new(body); let param_env = tcx.param_env(src.def_id()); { @@ -197,12 +200,12 @@ impl MirPass for RestoreSubsliceArrayMoveOut { for candidate in &visitor.candidates { let statement = &body[candidate.block].statements[candidate.statement_index]; - if let StatementKind::Assign(ref dst_place, ref rval) = statement.kind { - if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = **rval { + if let StatementKind::Assign(box(ref dst_place, ref rval)) = statement.kind { + if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval { let items : Vec<_> = items.iter().map(|item| { if let Operand::Move(Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }) = item { let local_use = &visitor.locals_use[*local]; let opt_index_and_place = @@ -221,7 +224,7 @@ impl MirPass for RestoreSubsliceArrayMoveOut { let opt_size = opt_src_place.and_then(|src_place| { let src_ty = Place::ty_from(src_place.base, src_place.projection, body, tcx).ty; - if let ty::Array(_, ref size_o) = src_ty.sty { + if let ty::Array(_, ref size_o) = src_ty.kind { size_o.try_eval_usize(tcx, param_env) } else { None @@ -269,16 +272,17 @@ impl RestoreSubsliceArrayMoveOut { } patch.make_nop(candidate); let size = opt_size.unwrap() as u32; - patch.add_assign(candidate, - dst_place.clone(), - Rvalue::Use( - Operand::Move( - Place { - base: src_place.base.clone(), - projection: Some(box Projection { - base: src_place.projection.clone(), - elem: ProjectionElem::Subslice{ - from: min, to: size - max - 1}})}))); + + let mut projection = src_place.projection.to_vec(); + projection.push(ProjectionElem::Subslice { from: min, to: size - max - 1 }); + patch.add_assign( + candidate, + dst_place.clone(), + Rvalue::Use(Operand::Move(Place { + base: src_place.base.clone(), + projection: projection.into_boxed_slice(), + })), + ); } } @@ -289,23 +293,34 @@ impl RestoreSubsliceArrayMoveOut { if block.statements.len() > location.statement_index { let statement = &block.statements[location.statement_index]; if let StatementKind::Assign( - Place { - base: PlaceBase::Local(_), - projection: None, - }, - box Rvalue::Use(Operand::Move(Place { - base, - projection: Some(box Projection { - base: proj_base, - elem: ProjectionElem::ConstantIndex { + box( + Place { + base: PlaceBase::Local(_), + projection: box [], + }, + Rvalue::Use(Operand::Move(Place { + base: _, + projection: box [.., ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false - } - }), - }))) = &statement.kind { - return Some((*offset, PlaceRef { - base, - projection: proj_base, - })) + }], + })), + ) + ) = &statement.kind { + // FIXME remove once we can use slices patterns + if let StatementKind::Assign( + box( + _, + Rvalue::Use(Operand::Move(Place { + base, + projection: box [proj_base @ .., _], + })), + ) + ) = &statement.kind { + return Some((*offset, PlaceRef { + base, + projection: proj_base, + })) + } } } } diff --git a/src/librustc_mir/util/aggregate.rs b/src/librustc_mir/util/aggregate.rs index 98e70671ab715..c0f9218574556 100644 --- a/src/librustc_mir/util/aggregate.rs +++ b/src/librustc_mir/util/aggregate.rs @@ -1,7 +1,7 @@ use rustc::mir::*; use rustc::ty::Ty; use rustc::ty::layout::VariantIdx; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use std::iter::TrustedLen; @@ -24,7 +24,7 @@ pub fn expand_aggregate<'tcx>( if adt_def.is_enum() { set_discriminant = Some(Statement { kind: StatementKind::SetDiscriminant { - place: lhs.clone(), + place: box(lhs.clone()), variant_index, }, source_info, @@ -39,7 +39,7 @@ pub fn expand_aggregate<'tcx>( let variant_index = VariantIdx::new(0); set_discriminant = Some(Statement { kind: StatementKind::SetDiscriminant { - place: lhs.clone(), + place: box(lhs.clone()), variant_index, }, source_info, @@ -70,7 +70,7 @@ pub fn expand_aggregate<'tcx>( }; Statement { source_info, - kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)), + kind: StatementKind::Assign(box(lhs_field, Rvalue::Use(op))), } }).chain(set_discriminant) } diff --git a/src/librustc_mir/util/alignment.rs b/src/librustc_mir/util/alignment.rs index b8ef77da02e60..1bad85ec42d08 100644 --- a/src/librustc_mir/util/alignment.rs +++ b/src/librustc_mir/util/alignment.rs @@ -38,15 +38,16 @@ fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<' where L: HasLocalDecls<'tcx>, { - let mut place_projection = &place.projection; + let mut cursor = &*place.projection; + while let [proj_base @ .., elem] = cursor { + cursor = proj_base; - while let Some(proj) = place_projection { - match proj.elem { + match elem { // encountered a Deref, which is ABI-aligned ProjectionElem::Deref => break, ProjectionElem::Field(..) => { - let ty = Place::ty_from(&place.base, &proj.base, local_decls, tcx).ty; - match ty.sty { + let ty = Place::ty_from(&place.base, proj_base, local_decls, tcx).ty; + match ty.kind { ty::Adt(def, _) if def.repr.packed() => { return true } @@ -55,7 +56,6 @@ where } _ => {} } - place_projection = &proj.base; } false diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index 3359d1b3bbfe1..96ba829358280 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -50,7 +50,7 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { self, span, E0381, - "{} of possibly uninitialized variable: `{}`", + "{} of possibly-uninitialized variable: `{}`", verb, desc, ) @@ -324,7 +324,7 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { ty: Ty<'_>, is_index: Option, ) -> DiagnosticBuilder<'cx> { - let type_name = match (&ty.sty, is_index) { + let type_name = match (&ty.kind, is_index) { (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array", (&ty::Slice(_), _) => "slice", _ => span_bug!(move_from_span, "this path should not cause illegal move"), diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs index 59821440c6619..3aea25fa8769f 100644 --- a/src/librustc_mir/util/def_use.rs +++ b/src/librustc_mir/util/def_use.rs @@ -2,7 +2,7 @@ use rustc::mir::{Local, Location, Body}; use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor}; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_index::vec::IndexVec; use std::mem; pub struct DefUseAnalysis { diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index d17dcaafc04f5..f7ba6f1ec6993 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -7,7 +7,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::VariantIdx; use rustc::ty::subst::SubstsRef; use rustc::ty::util::IntTypeExt; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use crate::util::patch::MirPatch; use std::convert::TryInto; @@ -586,10 +586,7 @@ where BorrowKind::Mut { allow_two_phase_borrow: false }, Place { base: PlaceBase::Local(cur), - projection: Some(Box::new(Projection { - base: None, - elem: ProjectionElem::Deref, - })), + projection: Box::new([ProjectionElem::Deref]), } ), Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one)) @@ -789,9 +786,9 @@ where /// ADT, both in the success case or if one of the destructors fail. fn open_drop(&mut self) -> BasicBlock { let ty = self.place_ty(self.place); - match ty.sty { + match ty.kind { ty::Closure(def_id, substs) => { - let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx()).collect(); + let tys : Vec<_> = substs.as_closure().upvar_tys(def_id, self.tcx()).collect(); self.open_drop_for_tuple(&tys) } // Note that `elaborate_drops` only drops the upvars of a generator, @@ -801,11 +798,11 @@ where // It effetively only contains upvars until the generator transformation runs. // See librustc_body/transform/generator.rs for more details. ty::Generator(def_id, substs, _) => { - let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx()).collect(); + let tys : Vec<_> = substs.as_generator().upvar_tys(def_id, self.tcx()).collect(); self.open_drop_for_tuple(&tys) } - ty::Tuple(tys) => { - let tys: Vec<_> = tys.iter().map(|k| k.expect_ty()).collect(); + ty::Tuple(..) => { + let tys: Vec<_> = ty.tuple_fields().collect(); self.open_drop_for_tuple(&tys) } ty::Adt(def, substs) => { @@ -897,7 +894,10 @@ where ) -> BasicBlock { let tcx = self.tcx(); let unit_temp = Place::from(self.new_temp(tcx.mk_unit())); - let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem); + let free_func = tcx.require_lang_item( + lang_items::BoxFreeFnLangItem, + Some(self.source_info.span) + ); let args = adt.variants[VariantIdx::new(0)].fields.iter().enumerate().map(|(i, f)| { let field = Field::new(i); let field_ty = f.ty(self.tcx(), substs); @@ -970,7 +970,6 @@ where fn constant_usize(&self, val: u16) -> Operand<'tcx> { Operand::Constant(box Constant { span: self.source_info.span, - ty: self.tcx().types.usize, user_ty: None, literal: ty::Const::from_usize(self.tcx(), val.into()), }) @@ -979,7 +978,7 @@ where fn assign(&self, lhs: &Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> { Statement { source_info: self.source_info, - kind: StatementKind::Assign(lhs.clone(), box rhs) + kind: StatementKind::Assign(box(lhs.clone(), rhs)) } } } diff --git a/src/librustc_mir/util/graphviz.rs b/src/librustc_mir/util/graphviz.rs index 9d142d9b700b6..7fcb7a40a3c08 100644 --- a/src/librustc_mir/util/graphviz.rs +++ b/src/librustc_mir/util/graphviz.rs @@ -1,7 +1,7 @@ use rustc::hir::def_id::DefId; use rustc::mir::*; use rustc::ty::TyCtxt; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use std::fmt::Debug; use std::io::{self, Write}; diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index b42eebc7ee3be..9757f4ac392ec 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -30,8 +30,8 @@ use rustc::mir::visit::{ use rustc::mir::Local; use rustc::mir::*; use rustc::ty::{self, TyCtxt}; -use rustc_data_structures::bit_set::BitSet; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::{Idx, IndexVec}; use rustc_data_structures::work_queue::WorkQueue; use std::fs; use std::io::{self, Write}; diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs index eb457dacf8467..a5f7e5401573b 100644 --- a/src/librustc_mir/util/patch.rs +++ b/src/librustc_mir/util/patch.rs @@ -1,6 +1,6 @@ use rustc::ty::Ty; use rustc::mir::*; -use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use rustc_index::vec::{IndexVec, Idx}; use syntax_pos::Span; /// This struct represents a patch to MIR, which can add @@ -120,7 +120,7 @@ impl<'tcx> MirPatch<'tcx> { } pub fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) { - self.add_statement(loc, StatementKind::Assign(place, box rv)); + self.add_statement(loc, StatementKind::Assign(box(place, rv))); } pub fn make_nop(&mut self, loc: Location) { diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 68880fc345ae2..7f6b60b1b116b 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -3,7 +3,7 @@ use rustc::mir::*; use rustc::mir::visit::Visitor; use rustc::ty::{self, TyCtxt}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use std::fmt::Display; use std::fmt::Write as _; use std::fs; @@ -227,12 +227,12 @@ pub(crate) fn create_dump_file( pass_name: &str, disambiguator: &dyn Display, source: MirSource<'tcx>, -) -> io::Result { +) -> io::Result> { let file_path = dump_path(tcx, extension, pass_num, pass_name, disambiguator, source); if let Some(parent) = file_path.parent() { fs::create_dir_all(parent)?; } - fs::File::create(&file_path) + Ok(io::BufWriter::new(fs::File::create(&file_path)?)) } /// Write out a human-readable textual representation for the given MIR. @@ -397,10 +397,9 @@ impl ExtraComments<'tcx> { impl Visitor<'tcx> for ExtraComments<'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); - let Constant { span, ty, user_ty, literal } = constant; + let Constant { span, user_ty, literal } = constant; self.push("mir::Constant"); self.push(&format!("+ span: {:?}", span)); - self.push(&format!("+ ty: {:?}", ty)); if let Some(user_ty) = user_ty { self.push(&format!("+ user_ty: {:?}", user_ty)); } diff --git a/src/librustc_msan/build.rs b/src/librustc_msan/build.rs index 1c66b0a9cd3cf..a81786ee36d04 100644 --- a/src/librustc_msan/build.rs +++ b/src/librustc_msan/build.rs @@ -4,6 +4,10 @@ use build_helper::sanitizer_lib_boilerplate; use cmake::Config; fn main() { + println!("cargo:rerun-if-env-changed=RUSTC_BUILD_SANITIZERS"); + if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) { + return; + } if let Some(llvm_config) = env::var_os("LLVM_CONFIG") { build_helper::restore_library_path(); diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml index 596ec6c19bcbf..9d29a23031443 100644 --- a/src/librustc_passes/Cargo.toml +++ b/src/librustc_passes/Cargo.toml @@ -15,3 +15,5 @@ rustc_data_structures = { path = "../librustc_data_structures" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } errors = { path = "../librustc_errors", package = "rustc_errors" } +rustc_target = { path = "../librustc_target" } +rustc_index = { path = "../librustc_index" } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 3c31bcef32b7a..0339b85ca55e3 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -107,7 +107,7 @@ impl<'a> AstValidator<'a> { // rust-lang/rust#57979: bug in old `visit_generic_args` called // `walk_ty` rather than `visit_ty`, skipping outer `impl Trait` // if it happened to occur at `ty`. - if let TyKind::ImplTrait(..) = ty.node { + if let TyKind::ImplTrait(..) = ty.kind { self.warning_period_57979_didnt_record_next_impl_trait = true; } } @@ -126,7 +126,7 @@ impl<'a> AstValidator<'a> { // rust-lang/rust#57979: bug in old `visit_generic_args` called // `walk_ty` rather than `visit_ty`, skippping outer `impl Trait` // if it happened to occur at `ty`. - if let TyKind::ImplTrait(..) = ty.node { + if let TyKind::ImplTrait(..) = ty.kind { self.warning_period_57979_didnt_record_next_impl_trait = true; } self.visit_ty(ty); @@ -149,7 +149,7 @@ impl<'a> AstValidator<'a> { // Mirrors `visit::walk_ty`, but tracks relevant state. fn walk_ty(&mut self, t: &'a Ty) { - match t.node { + match t.kind { TyKind::ImplTrait(..) => { let outer_impl_trait = self.outer_impl_trait(t.span); self.with_impl_trait(Some(outer_impl_trait), |this| visit::walk_ty(this, t)) @@ -231,7 +231,7 @@ impl<'a> AstValidator<'a> { fn check_decl_no_pat(&self, decl: &FnDecl, report_err: ReportFn) { for arg in &decl.inputs { - match arg.pat.node { + match arg.pat.kind { PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), _, None) | PatKind::Wild => {} PatKind::Ident(BindingMode::ByValue(Mutability::Mutable), _, None) => @@ -286,11 +286,11 @@ impl<'a> AstValidator<'a> { // m!(S); // ``` fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) { - match expr.node { + match expr.kind { ExprKind::Lit(..) | ExprKind::Err => {} ExprKind::Path(..) if allow_paths => {} ExprKind::Unary(UnOp::Neg, ref inner) - if match inner.node { ExprKind::Lit(_) => true, _ => false } => {} + if match inner.kind { ExprKind::Lit(_) => true, _ => false } => {} _ => self.err_handler().span_err(expr.span, "arbitrary expressions aren't allowed \ in patterns") } @@ -442,7 +442,7 @@ fn validate_generics_order<'a>( impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_expr(&mut self, expr: &'a Expr) { - match &expr.node { + match &expr.kind { ExprKind::Closure(_, _, _, fn_decl, _, _) => { self.check_fn_decl(fn_decl); } @@ -456,7 +456,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_ty(&mut self, ty: &'a Ty) { - match ty.node { + match ty.kind { TyKind::BareFn(ref bfty) => { self.check_fn_decl(&bfty.decl); self.check_decl_no_pat(&bfty.decl, |span, _| { @@ -538,10 +538,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.has_proc_macro_decls = true; } - match item.node { + match item.kind { ItemKind::Impl(unsafety, polarity, _, _, Some(..), ref ty, ref impl_items) => { self.invalid_visibility(&item.vis, None); - if let TyKind::Err = ty.node { + if let TyKind::Err = ty.kind { self.err_handler() .struct_span_err(item.span, "`impl Trait for .. {}` is an obsolete syntax") .help("use `auto trait Trait {}` instead").emit(); @@ -551,7 +551,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } for impl_item in impl_items { self.invalid_visibility(&impl_item.vis, None); - if let ImplItemKind::Method(ref sig, _) = impl_item.node { + if let ImplItemKind::Method(ref sig, _) = impl_item.kind { self.check_trait_fn_not_const(sig.header.constness); self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness.node); } @@ -602,7 +602,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ItemKind::Enum(ref def, _) => { for variant in &def.variants { - for field in variant.node.data.fields() { + for field in variant.data.fields() { self.invalid_visibility(&field.vis, None); } } @@ -628,7 +628,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } self.no_questions_in_bounds(bounds, "supertraits", true); for trait_item in trait_items { - if let TraitItemKind::Method(ref sig, ref block) = trait_item.node { + if let TraitItemKind::Method(ref sig, ref block) = trait_item.kind { self.check_fn_decl(&sig.decl); self.check_trait_fn_not_async(trait_item.span, sig.header.asyncness.node); self.check_trait_fn_not_const(sig.header.constness); @@ -682,7 +682,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { - match fi.node { + match fi.kind { ForeignItemKind::Fn(ref decl, _) => { self.check_fn_decl(decl); self.check_decl_no_pat(decl, |span, _| { @@ -786,7 +786,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_pat(&mut self, pat: &'a Pat) { - match pat.node { + match pat.kind { PatKind::Lit(ref expr) => { self.check_expr_within_pat(expr, false); } @@ -813,8 +813,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_poly_trait_ref(self, t, m); } - fn visit_variant_data(&mut self, s: &'a VariantData, _: Ident, - _: &'a Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, s: &'a VariantData) { self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s)) } @@ -824,7 +823,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { |this| visit::walk_enum_def(this, enum_definition, generics, item_id)) } - fn visit_mac(&mut self, mac: &Spanned) { + fn visit_mac(&mut self, mac: &Mac) { // when a new macro kind is added but the author forgets to set it up for expansion // because that's the only part that won't cause a compiler error self.session.diagnostic() @@ -833,11 +832,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_impl_item(&mut self, ii: &'a ImplItem) { - match ii.node { - ImplItemKind::Method(ref sig, _) => { - self.check_fn_decl(&sig.decl); - } - _ => {} + if let ImplItemKind::Method(ref sig, _) = ii.kind { + self.check_fn_decl(&sig.decl); } visit::walk_impl_item(self, ii); } diff --git a/src/librustc/middle/dead.rs b/src/librustc_passes/dead.rs similarity index 89% rename from src/librustc/middle/dead.rs rename to src/librustc_passes/dead.rs index 55fa261f1ed57..f2aef2c12c7df 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc_passes/dead.rs @@ -2,23 +2,22 @@ // closely. The idea is that all reachable symbols are live, codes called // from live codes are live, and everything else is dead. -use crate::hir::Node; -use crate::hir::{self, PatKind, TyKind}; -use crate::hir::intravisit::{self, Visitor, NestedVisitorMap}; -use crate::hir::itemlikevisit::ItemLikeVisitor; - -use crate::hir::def::{CtorOf, Res, DefKind}; -use crate::hir::CodegenFnAttrFlags; -use crate::hir::def_id::{DefId, LOCAL_CRATE}; -use crate::lint; -use crate::middle::privacy; -use crate::ty::{self, DefIdTree, TyCtxt}; -use crate::util::nodemap::FxHashSet; +use rustc::hir::Node; +use rustc::hir::{self, PatKind, TyKind}; +use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; + +use rustc::hir::def::{CtorOf, Res, DefKind}; +use rustc::hir::CodegenFnAttrFlags; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::lint; +use rustc::middle::privacy; +use rustc::ty::{self, DefIdTree, TyCtxt}; +use rustc::util::nodemap::FxHashSet; use rustc_data_structures::fx::FxHashMap; -use syntax::{ast, source_map}; -use syntax::attr; +use syntax::{ast, attr}; use syntax::symbol::sym; use syntax_pos; @@ -31,10 +30,11 @@ fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { Some(Node::Item(..)) | Some(Node::ImplItem(..)) | Some(Node::ForeignItem(..)) | - Some(Node::TraitItem(..)) => - true, - _ => - false + Some(Node::TraitItem(..)) | + Some(Node::Variant(..)) | + Some(Node::AnonConst(..)) | + Some(Node::Pat(..)) => true, + _ => false } } @@ -76,7 +76,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { self.check_def_id(res.def_id()); } _ if self.in_pat => {}, - Res::PrimTy(..) | Res::SelfTy(..) | Res::SelfCtor(..) | + Res::PrimTy(..) | Res::SelfCtor(..) | Res::Local(..) => {} Res::Def(DefKind::Ctor(CtorOf::Variant, ..), ctor_def_id) => { let variant_id = self.tcx.parent(ctor_def_id).unwrap(); @@ -93,6 +93,14 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { self.check_def_id(variant_id); } } + Res::SelfTy(t, i) => { + if let Some(t) = t { + self.check_def_id(t); + } + if let Some(i) = i { + self.check_def_id(i); + } + } Res::ToolMod | Res::NonMacroAttr(..) | Res::Err => {} _ => { self.check_def_id(res.def_id()); @@ -109,7 +117,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn handle_field_access(&mut self, lhs: &hir::Expr, hir_id: hir::HirId) { - match self.tables.expr_ty_adjusted(lhs).sty { + match self.tables.expr_ty_adjusted(lhs).kind { ty::Adt(def, _) => { let index = self.tcx.field_index(hir_id, self.tables); self.insert_def_id(def.non_enum_variant().fields[index].did); @@ -119,17 +127,16 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } } - fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, res: Res, - pats: &[source_map::Spanned]) { - let variant = match self.tables.node_type(lhs.hir_id).sty { + fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, res: Res, pats: &[hir::FieldPat]) { + let variant = match self.tables.node_type(lhs.hir_id).kind { ty::Adt(adt, _) => adt.variant_of_res(res), _ => span_bug!(lhs.span, "non-ADT in struct pattern") }; for pat in pats { - if let PatKind::Wild = pat.node.pat.node { + if let PatKind::Wild = pat.pat.kind { continue; } - let index = self.tcx.field_index(pat.node.hir_id, self.tables); + let index = self.tcx.field_index(pat.hir_id, self.tables); self.insert_def_id(variant.fields[index].did); } } @@ -159,7 +166,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { self.inherited_pub_visibility = false; match node { Node::Item(item) => { - match item.node { + match item.kind { hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => { let def_id = self.tcx.hir().local_def_id(item.hir_id); let def = self.tcx.adt_def(def_id); @@ -229,7 +236,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { } fn visit_expr(&mut self, expr: &'tcx hir::Expr) { - match expr.node { + match expr.kind { hir::ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => { let res = self.tables.qpath_res(qpath, expr.hir_id); self.handle_res(res); @@ -241,7 +248,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { self.handle_field_access(&lhs, expr.hir_id); } hir::ExprKind::Struct(_, ref fields, _) => { - if let ty::Adt(ref adt, _) = self.tables.expr_ty(expr).sty { + if let ty::Adt(ref adt, _) = self.tables.expr_ty(expr).kind { self.mark_as_used_if_union(adt, fields); } } @@ -252,28 +259,22 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { } fn visit_arm(&mut self, arm: &'tcx hir::Arm) { - if arm.pats.len() == 1 { - let variants = arm.pats[0].necessary_variants(); - - // Inside the body, ignore constructions of variants - // necessary for the pattern to match. Those construction sites - // can't be reached unless the variant is constructed elsewhere. - let len = self.ignore_variant_stack.len(); - self.ignore_variant_stack.extend_from_slice(&variants); - intravisit::walk_arm(self, arm); - self.ignore_variant_stack.truncate(len); - } else { - intravisit::walk_arm(self, arm); - } + // Inside the body, ignore constructions of variants + // necessary for the pattern to match. Those construction sites + // can't be reached unless the variant is constructed elsewhere. + let len = self.ignore_variant_stack.len(); + self.ignore_variant_stack.extend(arm.pat.necessary_variants()); + intravisit::walk_arm(self, arm); + self.ignore_variant_stack.truncate(len); } fn visit_pat(&mut self, pat: &'tcx hir::Pat) { - match pat.node { + match pat.kind { PatKind::Struct(ref path, ref fields, _) => { let res = self.tables.qpath_res(path, pat.hir_id); self.handle_field_pattern_match(pat, res, fields); } - PatKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => { + PatKind::Path(ref qpath) => { let res = self.tables.qpath_res(qpath, pat.hir_id); self.handle_res(res); } @@ -291,7 +292,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { } fn visit_ty(&mut self, ty: &'tcx hir::Ty) { - match ty.node { + match ty.kind { TyKind::Def(item_id, _) => { let item = self.tcx.hir().expect_item(item_id.id); intravisit::walk_item(self, item); @@ -300,6 +301,11 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { } intravisit::walk_ty(self, ty); } + + fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { + self.live_symbols.insert(c.hir_id); + intravisit::walk_anon_const(self, c); + } } fn has_allow_dead_code_or_lang_attr( @@ -363,22 +369,22 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { if allow_dead_code { self.worklist.push(item.hir_id); } - match item.node { + match item.kind { hir::ItemKind::Enum(ref enum_def, _) => { if allow_dead_code { - self.worklist.extend(enum_def.variants.iter().map(|variant| variant.node.id)); + self.worklist.extend(enum_def.variants.iter().map(|variant| variant.id)); } for variant in &enum_def.variants { - if let Some(ctor_hir_id) = variant.node.data.ctor_hir_id() { - self.struct_constructors.insert(ctor_hir_id, variant.node.id); + if let Some(ctor_hir_id) = variant.data.ctor_hir_id() { + self.struct_constructors.insert(ctor_hir_id, variant.id); } } } hir::ItemKind::Trait(.., ref trait_item_refs) => { for trait_item_ref in trait_item_refs { let trait_item = self.krate.trait_item(trait_item_ref.id); - match trait_item.node { + match trait_item.kind { hir::TraitItemKind::Const(_, Some(_)) | hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => { if has_allow_dead_code_or_lang_attr(self.tcx, @@ -476,7 +482,7 @@ struct DeadVisitor<'tcx> { impl DeadVisitor<'tcx> { fn should_warn_about_item(&mut self, item: &hir::Item) -> bool { - let should_warn = match item.node { + let should_warn = match item.kind { hir::ItemKind::Static(..) | hir::ItemKind::Const(..) | hir::ItemKind::Fn(..) @@ -497,7 +503,7 @@ impl DeadVisitor<'tcx> { && !has_allow_dead_code_or_lang_attr(self.tcx, field.hir_id, &field.attrs) } - fn should_warn_about_variant(&mut self, variant: &hir::VariantKind) -> bool { + fn should_warn_about_variant(&mut self, variant: &hir::Variant) -> bool { !self.symbol_is_live(variant.id) && !has_allow_dead_code_or_lang_attr(self.tcx, variant.id, @@ -565,7 +571,7 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> { if self.should_warn_about_item(item) { // For items that have a definition with a signature followed by a // block, point only at the signature. - let span = match item.node { + let span = match item.kind { hir::ItemKind::Fn(..) | hir::ItemKind::Mod(..) | hir::ItemKind::Enum(..) | @@ -575,7 +581,7 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> { hir::ItemKind::Impl(..) => self.tcx.sess.source_map().def_span(item.span), _ => item.span, }; - let participle = match item.node { + let participle = match item.kind { hir::ItemKind::Struct(..) => "constructed", // Issue #52325 _ => "used" }; @@ -583,7 +589,7 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> { item.hir_id, span, item.ident.name, - item.node.descriptive_variant(), + item.kind.descriptive_variant(), participle, ); } else { @@ -596,8 +602,8 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> { variant: &'tcx hir::Variant, g: &'tcx hir::Generics, id: hir::HirId) { - if self.should_warn_about_variant(&variant.node) { - self.warn_dead_code(variant.node.id, variant.span, variant.node.ident.name, + if self.should_warn_about_variant(&variant) { + self.warn_dead_code(variant.id, variant.span, variant.ident.name, "variant", "constructed"); } else { intravisit::walk_variant(self, variant, g, id); @@ -607,7 +613,7 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> { fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) { if self.should_warn_about_foreign_item(fi) { self.warn_dead_code(fi.hir_id, fi.span, fi.ident.name, - fi.node.descriptive_variant(), "used"); + fi.kind.descriptive_variant(), "used"); } intravisit::walk_foreign_item(self, fi); } @@ -620,7 +626,7 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> { } fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { - match impl_item.node { + match impl_item.kind { hir::ImplItemKind::Const(_, body_id) => { if !self.symbol_is_live(impl_item.hir_id) { self.warn_dead_code(impl_item.hir_id, @@ -646,7 +652,7 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> { // Overwrite so that we don't warn the trait item itself. fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { - match trait_item.node { + match trait_item.kind { hir::TraitItemKind::Const(_, Some(body_id)) | hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)) => { self.visit_nested_body(body_id) diff --git a/src/librustc/middle/entry.rs b/src/librustc_passes/entry.rs similarity index 62% rename from src/librustc/middle/entry.rs rename to src/librustc_passes/entry.rs index 53c099c0b4339..bf68807a0c29b 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc_passes/entry.rs @@ -1,32 +1,32 @@ -use crate::hir::map as hir_map; -use crate::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE}; -use crate::session::{config, Session}; -use crate::session::config::EntryFnType; +use rustc::hir::map as hir_map; +use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE}; +use rustc::session::{config, Session}; +use rustc::session::config::EntryFnType; use syntax::attr; use syntax::entry::EntryPointType; use syntax::symbol::sym; use syntax_pos::Span; -use crate::hir::{HirId, Item, ItemKind, ImplItem, TraitItem}; -use crate::hir::itemlikevisit::ItemLikeVisitor; -use crate::ty::TyCtxt; -use crate::ty::query::Providers; +use rustc::hir::{HirId, Item, ItemKind, ImplItem, TraitItem}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::ty::TyCtxt; +use rustc::ty::query::Providers; struct EntryContext<'a, 'tcx> { session: &'a Session, map: &'a hir_map::Map<'tcx>, - // The top-level function called 'main' + /// The top-level function called `main`. main_fn: Option<(HirId, Span)>, - // The function that has attribute named 'main' + /// The function that has attribute named `main`. attr_main_fn: Option<(HirId, Span)>, - // The function that has the attribute 'start' on it + /// The function that has the attribute 'start' on it. start_fn: Option<(HirId, Span)>, - // The functions that one might think are 'main' but aren't, e.g. - // main functions not defined at the top level. For diagnostics. + /// The functions that one might think are `main` but aren't, e.g. + /// main functions not defined at the top level. For diagnostics. non_main_fns: Vec<(HirId, Span)> , } @@ -39,11 +39,11 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> { } fn visit_trait_item(&mut self, _trait_item: &'tcx TraitItem) { - // entry fn is never a trait item + // Entry fn is never a trait item. } fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem) { - // entry fn is never an impl item + // Entry fn is never a trait item. } } @@ -54,7 +54,7 @@ fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(DefId, EntryFnType)> { *ty == config::CrateType::Executable }); if !any_exe { - // No need to find a main function + // No need to find a main function. return None; } @@ -80,7 +80,7 @@ fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(DefId, EntryFnType)> { // Beware, this is duplicated in `libsyntax/entry.rs`, so make sure to keep // them in sync. fn entry_point_type(item: &Item, at_root: bool) -> EntryPointType { - match item.node { + match item.kind { ItemKind::Fn(..) => { if attr::contains_name(&item.attrs, sym::start) { EntryPointType::Start @@ -88,7 +88,7 @@ fn entry_point_type(item: &Item, at_root: bool) -> EntryPointType { EntryPointType::MainAttr } else if item.ident.name == sym::main { if at_root { - // This is a top-level function so can be 'main'. + // This is a top-level function so can be `main`. EntryPointType::MainNamed } else { EntryPointType::OtherMain @@ -109,7 +109,7 @@ fn find_item(item: &Item, ctxt: &mut EntryContext<'_, '_>, at_root: bool) { ctxt.main_fn = Some((item.hir_id, item.span)); } else { span_err!(ctxt.session, item.span, E0136, - "multiple 'main' functions"); + "multiple `main` functions"); } }, EntryPointType::OtherMain => { @@ -130,7 +130,7 @@ fn find_item(item: &Item, ctxt: &mut EntryContext<'_, '_>, at_root: bool) { if ctxt.start_fn.is_none() { ctxt.start_fn = Some((item.hir_id, item.span)); } else { - struct_span_err!(ctxt.session, item.span, E0138, "multiple 'start' functions") + struct_span_err!(ctxt.session, item.span, E0138, "multiple `start` functions") .span_label(ctxt.start_fn.unwrap().1, "previous `start` function here") .span_label(item.span, "multiple `start` functions") .emit(); @@ -148,34 +148,48 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(De } else if let Some((hir_id, _)) = visitor.main_fn { Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main)) } else { - // No main function - let mut err = struct_err!(tcx.sess, E0601, - "`main` function not found in crate `{}`", tcx.crate_name(LOCAL_CRATE)); - if !visitor.non_main_fns.is_empty() { - // There were some functions named 'main' though. Try to give the user a hint. - err.note("the main function must be defined at the crate level \ - but you have one or more functions named 'main' that are not \ - defined at the crate level. Either move the definition or \ - attach the `#[main]` attribute to override this behavior."); - for &(_, span) in &visitor.non_main_fns { - err.span_note(span, "here is a function named 'main'"); - } - err.emit(); - } else { - if let Some(ref filename) = tcx.sess.local_crate_source_file { - err.note(&format!("consider adding a `main` function to `{}`", filename.display())); - } - if tcx.sess.teach(&err.get_code().unwrap()) { - err.note("If you don't know the basics of Rust, you can go look to the Rust Book \ - to get started: https://doc.rust-lang.org/book/"); - } - err.emit(); - } - + no_main_err(tcx, visitor); None } } +fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) { + // There is no main function. + let mut err = struct_err!(tcx.sess, E0601, + "`main` function not found in crate `{}`", tcx.crate_name(LOCAL_CRATE)); + let filename = &tcx.sess.local_crate_source_file; + let note = if !visitor.non_main_fns.is_empty() { + for &(_, span) in &visitor.non_main_fns { + err.span_note(span, "here is a function named `main`"); + } + err.note("you have one or more functions named `main` not defined at the crate level"); + err.help("either move the `main` function definitions or attach the `#[main]` attribute \ + to one of them"); + // There were some functions named `main` though. Try to give the user a hint. + format!("the main function must be defined at the crate level{}", + filename.as_ref().map(|f| format!(" (in `{}`)", f.display())).unwrap_or_default()) + } else if let Some(filename) = filename { + format!("consider adding a `main` function to `{}`", filename.display()) + } else { + String::from("consider adding a `main` function at the crate level") + }; + let sp = tcx.hir().krate().span; + // The file may be empty, which leads to the diagnostic machinery not emitting this + // note. This is a relatively simple way to detect that case and emit a span-less + // note instead. + if let Ok(_) = tcx.sess.source_map().lookup_line(sp.lo()) { + err.set_span(sp); + err.span_label(sp, ¬e); + } else { + err.note(¬e); + } + if tcx.sess.teach(&err.get_code().unwrap()) { + err.note("If you don't know the basics of Rust, you can go look to the Rust Book \ + to get started: https://doc.rust-lang.org/book/"); + } + err.emit(); +} + pub fn find_entry_point(tcx: TyCtxt<'_>) -> Option<(DefId, EntryFnType)> { tcx.entry_fn(LOCAL_CRATE) } diff --git a/src/librustc_passes/error_codes.rs b/src/librustc_passes/error_codes.rs index cd33943e77e20..a2626617afec3 100644 --- a/src/librustc_passes/error_codes.rs +++ b/src/librustc_passes/error_codes.rs @@ -1,14 +1,15 @@ -use syntax::{register_diagnostics, register_long_diagnostics}; - -register_long_diagnostics! { -/* +syntax::register_diagnostics! { E0014: r##" +#### Note: this error code is no longer emitted by the compiler. + Constants can only be initialized by a constant value or, in a future version of Rust, a call to a const function. This error indicates the use of a path (like a::b, or x) denoting something other than one of these -allowed items. Erroneous code xample: +allowed items. -```compile_fail +Erroneous code example: + +``` const FOO: i32 = { let x = 0; x }; // 'x' isn't a constant nor a function! ``` @@ -20,10 +21,10 @@ const FOO: i32 = { const X : i32 = 0; X }; const FOO2: i32 = { 0 }; // but brackets are useless here ``` "##, -*/ E0130: r##" You declared a pattern as an argument in a foreign function declaration. + Erroneous code example: ```compile_fail @@ -55,6 +56,81 @@ extern { ``` "##, +// This shouldn't really ever trigger since the repeated value error comes first +E0136: r##" +A binary can only have one entry point, and by default that entry point is the +function `main()`. If there are multiple such functions, please rename one. + +Erroneous code example: + +```compile_fail,E0136 +fn main() { + // ... +} + +// ... + +fn main() { // error! + // ... +} +``` +"##, + +E0137: r##" +More than one function was declared with the `#[main]` attribute. + +Erroneous code example: + +```compile_fail,E0137 +#![feature(main)] + +#[main] +fn foo() {} + +#[main] +fn f() {} // error: multiple functions with a `#[main]` attribute +``` + +This error indicates that the compiler found multiple functions with the +`#[main]` attribute. This is an error because there must be a unique entry +point into a Rust program. Example: + +``` +#![feature(main)] + +#[main] +fn f() {} // ok! +``` +"##, + +E0138: r##" +More than one function was declared with the `#[start]` attribute. + +Erroneous code example: + +```compile_fail,E0138 +#![feature(start)] + +#[start] +fn foo(argc: isize, argv: *const *const u8) -> isize {} + +#[start] +fn f(argc: isize, argv: *const *const u8) -> isize {} +// error: multiple 'start' functions +``` + +This error indicates that the compiler found multiple functions with the +`#[start]` attribute. This is an error because there must be a unique entry +point into a Rust program. Example: + +``` +#![feature(start)] + +#[start] +fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } // ok! +``` +"##, + E0197: r##" Inherent implementations (one that do not implement a trait but provide methods associated with a type) are always safe because they are not @@ -131,7 +207,7 @@ be taken. Erroneous code example: ```compile_fail,E0268 fn some_func() { - break; // error: `break` outside of loop + break; // error: `break` outside of a loop } ``` @@ -200,20 +276,115 @@ impl Foo for Bar { ``` "##, +E0512: r##" +Transmute with two differently sized types was attempted. Erroneous code +example: -E0590: r##" -`break` or `continue` must include a label when used in the condition of a -`while` loop. +```compile_fail,E0512 +fn takes_u8(_: u8) {} -Example of erroneous code: +fn main() { + unsafe { takes_u8(::std::mem::transmute(0u16)); } + // error: cannot transmute between types of different sizes, + // or dependently-sized types +} +``` + +Please use types with same size or use the expected type directly. Example: -```compile_fail -while break {} ``` +fn takes_u8(_: u8) {} -To fix this, add a label specifying which loop is being broken out of: +fn main() { + unsafe { takes_u8(::std::mem::transmute(0i8)); } // ok! + // or: + unsafe { takes_u8(0u8); } // ok! +} ``` -'foo: while break 'foo {} +"##, + +E0561: r##" +A non-ident or non-wildcard pattern has been used as a parameter of a function +pointer type. + +Erroneous code example: + +```compile_fail,E0561 +type A1 = fn(mut param: u8); // error! +type A2 = fn(¶m: u32); // error! +``` + +When using an alias over a function type, you cannot e.g. denote a parameter as +being mutable. + +To fix the issue, remove patterns (`_` is allowed though). Example: + +``` +type A1 = fn(param: u8); // ok! +type A2 = fn(_: u32); // ok! +``` + +You can also omit the parameter name: + +``` +type A3 = fn(i16); // ok! +``` +"##, + +E0567: r##" +Generics have been used on an auto trait. + +Erroneous code example: + +```compile_fail,E0567 +#![feature(optin_builtin_traits)] + +auto trait Generic {} // error! + +fn main() {} +``` + +Since an auto trait is implemented on all existing types, the +compiler would not be able to infer the types of the trait's generic +parameters. + +To fix this issue, just remove the generics: + +``` +#![feature(optin_builtin_traits)] + +auto trait Generic {} // ok! + +fn main() {} +``` +"##, + +E0568: r##" +A super trait has been added to an auto trait. + +Erroneous code example: + +```compile_fail,E0568 +#![feature(optin_builtin_traits)] + +auto trait Bound : Copy {} // error! + +fn main() {} +``` + +Since an auto trait is implemented on all existing types, adding a super trait +would filter out a lot of those types. In the current example, almost none of +all the existing types could implement `Bound` because very few of them have the +`Copy` trait. + +To fix this issue, just remove the super trait: + +``` +#![feature(optin_builtin_traits)] + +auto trait Bound {} // ok! + +fn main() {} ``` "##, @@ -251,6 +422,115 @@ let result = loop { // ok! ``` "##, +E0590: r##" +`break` or `continue` must include a label when used in the condition of a +`while` loop. + +Example of erroneous code: + +```compile_fail +while break {} +``` + +To fix this, add a label specifying which loop is being broken out of: +``` +'foo: while break 'foo {} +``` +"##, + +E0591: r##" +Per [RFC 401][rfc401], if you have a function declaration `foo`: + +``` +// For the purposes of this explanation, all of these +// different kinds of `fn` declarations are equivalent: +struct S; +fn foo(x: S) { /* ... */ } +# #[cfg(for_demonstration_only)] +extern "C" { fn foo(x: S); } +# #[cfg(for_demonstration_only)] +impl S { fn foo(self) { /* ... */ } } +``` + +the type of `foo` is **not** `fn(S)`, as one might expect. +Rather, it is a unique, zero-sized marker type written here as `typeof(foo)`. +However, `typeof(foo)` can be _coerced_ to a function pointer `fn(S)`, +so you rarely notice this: + +``` +# struct S; +# fn foo(_: S) {} +let x: fn(S) = foo; // OK, coerces +``` + +The reason that this matter is that the type `fn(S)` is not specific to +any particular function: it's a function _pointer_. So calling `x()` results +in a virtual call, whereas `foo()` is statically dispatched, because the type +of `foo` tells us precisely what function is being called. + +As noted above, coercions mean that most code doesn't have to be +concerned with this distinction. However, you can tell the difference +when using **transmute** to convert a fn item into a fn pointer. + +This is sometimes done as part of an FFI: + +```compile_fail,E0591 +extern "C" fn foo(userdata: Box) { + /* ... */ +} + +# fn callback(_: extern "C" fn(*mut i32)) {} +# use std::mem::transmute; +# unsafe { +let f: extern "C" fn(*mut i32) = transmute(foo); +callback(f); +# } +``` + +Here, transmute is being used to convert the types of the fn arguments. +This pattern is incorrect because, because the type of `foo` is a function +**item** (`typeof(foo)`), which is zero-sized, and the target type (`fn()`) +is a function pointer, which is not zero-sized. +This pattern should be rewritten. There are a few possible ways to do this: + +- change the original fn declaration to match the expected signature, + and do the cast in the fn body (the preferred option) +- cast the fn item fo a fn pointer before calling transmute, as shown here: + + ``` + # extern "C" fn foo(_: Box) {} + # use std::mem::transmute; + # unsafe { + let f: extern "C" fn(*mut i32) = transmute(foo as extern "C" fn(_)); + let f: extern "C" fn(*mut i32) = transmute(foo as usize); // works too + # } + ``` + +The same applies to transmutes to `*mut fn()`, which were observed in practice. +Note though that use of this type is generally incorrect. +The intention is typically to describe a function pointer, but just `fn()` +alone suffices for that. `*mut fn()` is a pointer to a fn pointer. +(Since these values are typically just passed to C code, however, this rarely +makes a difference in practice.) + +[rfc401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md +"##, + +E0601: r##" +No `main` function was found in a binary crate. To fix this error, add a +`main` function. For example: + +``` +fn main() { + // Your program will start here. + println!("Hello world!"); +} +``` + +If you don't know the basics of Rust, you can go look to the Rust Book to get +started: https://doc.rust-lang.org/book/ +"##, + E0642: r##" Trait methods currently cannot take patterns as arguments. @@ -320,15 +600,11 @@ async fn foo() {} ``` Switch to the Rust 2018 edition to use `async fn`. -"## -} +"##, -register_diagnostics! { +; E0226, // only a single explicit lifetime bound is permitted E0472, // asm! is unsupported on this target - E0561, // patterns aren't allowed in function pointer types - E0567, // auto traits can not have generic parameters - E0568, // auto traits can not have super traits E0666, // nested `impl Trait` is illegal E0667, // `impl Trait` in projections E0696, // `continue` pointing to a labeled block diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 8fba3256ec429..a5924efefc2af 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -94,9 +94,9 @@ impl<'k> StatCollector<'k> { } impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { - fn visit_arg(&mut self, arg: &'v hir::Arg) { - self.record("Arg", Id::Node(arg.hir_id), arg); - hir_visit::walk_arg(self, arg) + fn visit_param(&mut self, param: &'v hir::Param) { + self.record("Param", Id::Node(param.hir_id), param); + hir_visit::walk_param(self, param) } fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'v> { @@ -334,12 +334,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { ast_visit::walk_struct_field(self, s) } - fn visit_variant(&mut self, - v: &'v ast::Variant, - g: &'v ast::Generics, - item_id: NodeId) { + fn visit_variant(&mut self, v: &'v ast::Variant) { self.record("Variant", Id::None, v); - ast_visit::walk_variant(self, v, g, item_id) + ast_visit::walk_variant(self, v) } fn visit_lifetime(&mut self, lifetime: &'v ast::Lifetime) { diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc_passes/intrinsicck.rs similarity index 91% rename from src/librustc/middle/intrinsicck.rs rename to src/librustc_passes/intrinsicck.rs index 1cc96c549e724..91a7e9f5d7fca 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc_passes/intrinsicck.rs @@ -1,14 +1,14 @@ -use crate::hir::def::{Res, DefKind}; -use crate::hir::def_id::DefId; -use crate::ty::{self, Ty, TyCtxt}; -use crate::ty::layout::{LayoutError, Pointer, SizeSkeleton, VariantIdx}; -use crate::ty::query::Providers; +use rustc::hir::def::{Res, DefKind}; +use rustc::hir::def_id::DefId; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::layout::{LayoutError, Pointer, SizeSkeleton, VariantIdx}; +use rustc::ty::query::Providers; use rustc_target::spec::abi::Abi::RustIntrinsic; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; use syntax_pos::{Span, sym}; -use crate::hir::intravisit::{self, Visitor, NestedVisitorMap}; -use crate::hir; +use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; +use rustc::hir; fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: DefId) { tcx.hir().visit_item_likes_in_module( @@ -37,7 +37,7 @@ struct ExprVisitor<'tcx> { /// If the type is `Option`, it will return `T`, otherwise /// the type itself. Works on most `Option`-like types. fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - let (def, substs) = match ty.sty { + let (def, substs) = match ty.kind { ty::Adt(def, substs) => (def, substs), _ => return ty }; @@ -82,8 +82,8 @@ impl ExprVisitor<'tcx> { // Special-case transmutting from `typeof(function)` and // `Option` to present a clearer error. - let from = unpack_option_like(self.tcx.global_tcx(), from); - if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (&from.sty, sk_to) { + let from = unpack_option_like(self.tcx, from); + if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (&from.kind, sk_to) { if size_to == Pointer.size(&self.tcx) { struct_span_err!(self.tcx.sess, span, E0591, "can't transmute zero-sized type") @@ -150,7 +150,7 @@ impl Visitor<'tcx> for ExprVisitor<'tcx> { } fn visit_expr(&mut self, expr: &'tcx hir::Expr) { - let res = if let hir::ExprKind::Path(ref qpath) = expr.node { + let res = if let hir::ExprKind::Path(ref qpath) = expr.kind { self.tables.qpath_res(qpath, expr.hir_id) } else { Res::Err diff --git a/src/librustc_passes/layout_test.rs b/src/librustc_passes/layout_test.rs index 45a185dccf29c..06683c16e4a9b 100644 --- a/src/librustc_passes/layout_test.rs +++ b/src/librustc_passes/layout_test.rs @@ -31,7 +31,7 @@ impl ItemLikeVisitor<'tcx> for VarianceTest<'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { let item_def_id = self.tcx.hir().local_def_id(item.hir_id); - if let ItemKind::TyAlias(..) = item.node { + if let ItemKind::TyAlias(..) = item.kind { for attr in self.tcx.get_attrs(item_def_id).iter() { if attr.check_name(sym::rustc_layout) { self.dump_layout_of(item_def_id, item, attr); diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 5614b570b927a..db59d8e101f77 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -8,27 +8,32 @@ #![feature(in_band_lifetimes)] #![feature(nll)] -#![feature(bind_by_move_pattern_guards)] -#![feature(rustc_diagnostic_macros)] #![recursion_limit="256"] #[macro_use] extern crate rustc; +#[macro_use] +extern crate log; +#[macro_use] +extern crate syntax; use rustc::ty::query::Providers; -mod error_codes; +pub mod error_codes; pub mod ast_validation; -pub mod rvalue_promotion; pub mod hir_stats; pub mod layout_test; pub mod loops; - -__build_diagnostic_array! { librustc_passes, DIAGNOSTICS } +pub mod dead; +pub mod entry; +mod liveness; +mod intrinsicck; pub fn provide(providers: &mut Providers<'_>) { - rvalue_promotion::provide(providers); + entry::provide(providers); loops::provide(providers); + liveness::provide(providers); + intrinsicck::provide(providers); } diff --git a/src/librustc/middle/liveness.rs b/src/librustc_passes/liveness.rs similarity index 84% rename from src/librustc/middle/liveness.rs rename to src/librustc_passes/liveness.rs index daf0d8103a2c0..fb06808619f66 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -96,29 +96,29 @@ use self::LiveNodeKind::*; use self::VarKind::*; -use crate::hir::def::*; -use crate::hir::Node; -use crate::hir::ptr::P; -use crate::ty::{self, TyCtxt}; -use crate::ty::query::Providers; -use crate::lint; -use crate::util::nodemap::{HirIdMap, HirIdSet}; +use rustc::hir; +use rustc::hir::{Expr, HirId}; +use rustc::hir::def::*; +use rustc::hir::def_id::DefId; +use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap}; +use rustc::hir::Node; +use rustc::hir::ptr::P; +use rustc::ty::{self, TyCtxt}; +use rustc::ty::query::Providers; +use rustc::lint; +use rustc::util::nodemap::{HirIdMap, HirIdSet}; use errors::Applicability; -use std::collections::{BTreeMap, VecDeque}; +use rustc_data_structures::fx::FxIndexMap; +use std::collections::VecDeque; use std::{fmt, u32}; use std::io::prelude::*; use std::io; use std::rc::Rc; use syntax::ast; -use syntax::symbol::{kw, sym}; +use syntax::symbol::sym; use syntax_pos::Span; -use crate::hir; -use crate::hir::{Expr, HirId}; -use crate::hir::def_id::DefId; -use crate::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap}; - #[derive(Copy, Clone, PartialEq)] struct Variable(u32); @@ -242,7 +242,7 @@ struct LocalInfo { #[derive(Copy, Clone, Debug)] enum VarKind { - Arg(HirId, ast::Name), + Param(HirId, ast::Name), Local(LocalInfo), CleanExit } @@ -298,7 +298,7 @@ impl IrMaps<'tcx> { self.num_vars += 1; match vk { - Local(LocalInfo { id: node_id, .. }) | Arg(node_id, _) => { + Local(LocalInfo { id: node_id, .. }) | Param(node_id, _) => { self.variable_map.insert(node_id, v); }, CleanExit => {} @@ -320,7 +320,7 @@ impl IrMaps<'tcx> { fn variable_name(&self, var: Variable) -> String { match self.var_kinds[var.get()] { - Local(LocalInfo { name, .. }) | Arg(_, name) => { + Local(LocalInfo { name, .. }) | Param(_, name) => { name.to_string() }, CleanExit => "".to_owned() @@ -330,7 +330,7 @@ impl IrMaps<'tcx> { fn variable_is_shorthand(&self, var: Variable) -> bool { match self.var_kinds[var.get()] { Local(LocalInfo { is_shorthand, .. }) => is_shorthand, - Arg(..) | CleanExit => false + Param(..) | CleanExit => false } } @@ -371,13 +371,13 @@ fn visit_fn<'tcx>( let body = ir.tcx.hir().body(body_id); - for arg in &body.arguments { - let is_shorthand = match arg.pat.node { - crate::hir::PatKind::Struct(..) => true, + for param in &body.params { + let is_shorthand = match param.pat.kind { + rustc::hir::PatKind::Struct(..) => true, _ => false, }; - arg.pat.each_binding(|_bm, hir_id, _x, ident| { - debug!("adding argument {:?}", hir_id); + param.pat.each_binding(|_bm, hir_id, _x, ident| { + debug!("adding parameters {:?}", hir_id); let var = if is_shorthand { Local(LocalInfo { id: hir_id, @@ -385,7 +385,7 @@ fn visit_fn<'tcx>( is_shorthand: true, }) } else { - Arg(hir_id, ident.name) + Param(hir_id, ident.name) }; fn_maps.add_variable(var); }) @@ -404,34 +404,29 @@ fn visit_fn<'tcx>( lsets.warn_about_unused_args(body, entry_ln); } -fn add_from_pat<'tcx>(ir: &mut IrMaps<'tcx>, pat: &P) { +fn add_from_pat(ir: &mut IrMaps<'_>, pat: &P) { // For struct patterns, take note of which fields used shorthand // (`x` rather than `x: x`). let mut shorthand_field_ids = HirIdSet::default(); let mut pats = VecDeque::new(); pats.push_back(pat); while let Some(pat) = pats.pop_front() { - use crate::hir::PatKind::*; - match pat.node { - Binding(_, _, _, ref inner_pat) => { + use rustc::hir::PatKind::*; + match &pat.kind { + Binding(.., inner_pat) => { pats.extend(inner_pat.iter()); } - Struct(_, ref fields, _) => { - for field in fields { - if field.node.is_shorthand { - shorthand_field_ids.insert(field.node.pat.hir_id); - } - } + Struct(_, fields, _) => { + let ids = fields.iter().filter(|f| f.is_shorthand).map(|f| f.pat.hir_id); + shorthand_field_ids.extend(ids); } - Ref(ref inner_pat, _) | - Box(ref inner_pat) => { + Ref(inner_pat, _) | Box(inner_pat) => { pats.push_back(inner_pat); } - TupleStruct(_, ref inner_pats, _) | - Tuple(ref inner_pats, _) => { + TupleStruct(_, inner_pats, _) | Tuple(inner_pats, _) | Or(inner_pats) => { pats.extend(inner_pats.iter()); } - Slice(ref pre_pats, ref inner_pat, ref post_pats) => { + Slice(pre_pats, inner_pat, post_pats) => { pats.extend(pre_pats.iter()); pats.extend(inner_pat.iter()); pats.extend(post_pats.iter()); @@ -440,7 +435,7 @@ fn add_from_pat<'tcx>(ir: &mut IrMaps<'tcx>, pat: &P) { } } - pat.each_binding(|_bm, hir_id, _sp, ident| { + pat.each_binding(|_, hir_id, _, ident| { ir.add_live_node_for_node(hir_id, VarDefNode(ident.span)); ir.add_variable(Local(LocalInfo { id: hir_id, @@ -456,14 +451,12 @@ fn visit_local<'tcx>(ir: &mut IrMaps<'tcx>, local: &'tcx hir::Local) { } fn visit_arm<'tcx>(ir: &mut IrMaps<'tcx>, arm: &'tcx hir::Arm) { - for pat in &arm.pats { - add_from_pat(ir, pat); - } + add_from_pat(ir, &arm.pat); intravisit::walk_arm(ir, arm); } fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr) { - match expr.node { + match expr.kind { // live nodes required for uses or definitions of variables: hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res); @@ -734,35 +727,15 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.ir.variable(hir_id, span) } - fn pat_bindings(&mut self, pat: &hir::Pat, mut f: F) where - F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, HirId), - { - pat.each_binding(|_bm, hir_id, sp, n| { - let ln = self.live_node(hir_id, sp); - let var = self.variable(hir_id, n.span); - f(self, ln, var, n.span, hir_id); - }) - } - - fn arm_pats_bindings(&mut self, pat: Option<&hir::Pat>, f: F) where - F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, HirId), - { - if let Some(pat) = pat { - self.pat_bindings(pat, f); - } - } - - fn define_bindings_in_pat(&mut self, pat: &hir::Pat, succ: LiveNode) - -> LiveNode { - self.define_bindings_in_arm_pats(Some(pat), succ) - } - - fn define_bindings_in_arm_pats(&mut self, pat: Option<&hir::Pat>, succ: LiveNode) - -> LiveNode { - let mut succ = succ; - self.arm_pats_bindings(pat, |this, ln, var, _sp, _id| { - this.init_from_succ(ln, succ); - this.define(ln, var); + fn define_bindings_in_pat(&mut self, pat: &hir::Pat, mut succ: LiveNode) -> LiveNode { + // In an or-pattern, only consider the first pattern; any later patterns + // must have the same bindings, and we also consider the first pattern + // to be the "authoritative" set of ids. + pat.each_binding_or_first(&mut |_, hir_id, pat_sp, ident| { + let ln = self.live_node(hir_id, pat_sp); + let var = self.variable(hir_id, ident.span); + self.init_from_succ(ln, succ); + self.define(ln, var); succ = ln; }); succ @@ -974,7 +947,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn propagate_through_stmt(&mut self, stmt: &hir::Stmt, succ: LiveNode) -> LiveNode { - match stmt.node { + match stmt.kind { hir::StmtKind::Local(ref local) => { // Note: we mark the variable as defined regardless of whether // there is an initializer. Initially I had thought to only mark @@ -1018,7 +991,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { -> LiveNode { debug!("propagate_through_expr: {}", self.ir.tcx.hir().hir_to_pretty_string(expr.hir_id)); - match expr.node { + match expr.kind { // Interesting cases with control flow or which gen/kill hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { self.access_path(expr.hir_id, path, succ, ACC_READ | ACC_USE) @@ -1076,12 +1049,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { arm.guard.as_ref().map(|hir::Guard::If(e)| &**e), body_succ ); - // only consider the first pattern; any later patterns must have - // the same bindings, and we also consider the first pattern to be - // the "authoritative" set of ids - let arm_succ = - self.define_bindings_in_arm_pats(arm.pats.first().map(|p| &**p), - guard_succ); + let arm_succ = self.define_bindings_in_pat(&arm.pat, guard_succ); self.merge_from_succ(ln, arm_succ, first_merge); first_merge = false; }; @@ -1291,7 +1259,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // these errors are detected in the later pass borrowck. We // just ignore such cases and treat them as reads. - match expr.node { + match expr.kind { hir::ExprKind::Path(_) => succ, hir::ExprKind::Field(ref e, _) => self.propagate_through_expr(&e, succ), _ => self.propagate_through_expr(expr, succ) @@ -1300,7 +1268,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // see comment on propagate_through_place() fn write_place(&mut self, expr: &Expr, succ: LiveNode, acc: u32) -> LiveNode { - match expr.node { + match expr.kind { hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { self.access_path(expr.hir_id, path, succ, acc) } @@ -1388,74 +1356,36 @@ impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> { NestedVisitorMap::None } - fn visit_local(&mut self, l: &'tcx hir::Local) { - check_local(self, l); - } - fn visit_expr(&mut self, ex: &'tcx Expr) { - check_expr(self, ex); - } - fn visit_arm(&mut self, a: &'tcx hir::Arm) { - check_arm(self, a); - } -} + fn visit_local(&mut self, local: &'tcx hir::Local) { + self.check_unused_vars_in_pat(&local.pat, None, |spans, hir_id, ln, var| { + if local.init.is_some() { + self.warn_about_dead_assign(spans, hir_id, ln, var); + } + }); -fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local) { - match local.init { - Some(_) => { - this.warn_about_unused_or_dead_vars_in_pat(&local.pat); - }, - None => { - this.pat_bindings(&local.pat, |this, ln, var, sp, id| { - let span = local.pat.simple_ident().map_or(sp, |ident| ident.span); - this.warn_about_unused(vec![span], id, ln, var); - }) - } + intravisit::walk_local(self, local); } - intravisit::walk_local(this, local); -} - -fn check_arm<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, arm: &'tcx hir::Arm) { - // Only consider the variable from the first pattern; any later patterns must have - // the same bindings, and we also consider the first pattern to be the "authoritative" set of - // ids. However, we should take the spans of variables with the same name from the later - // patterns so the suggestions to prefix with underscores will apply to those too. - let mut vars: BTreeMap)> = Default::default(); - - for pat in &arm.pats { - this.arm_pats_bindings(Some(&*pat), |this, ln, var, sp, id| { - let name = this.ir.variable_name(var); - vars.entry(name) - .and_modify(|(.., spans)| { - spans.push(sp); - }) - .or_insert_with(|| { - (ln, var, id, vec![sp]) - }); - }); + fn visit_expr(&mut self, ex: &'tcx Expr) { + check_expr(self, ex); } - for (_, (ln, var, id, spans)) in vars { - this.warn_about_unused(spans, id, ln, var); + fn visit_arm(&mut self, arm: &'tcx hir::Arm) { + self.check_unused_vars_in_pat(&arm.pat, None, |_, _, _, _| {}); + intravisit::walk_arm(self, arm); } - - intravisit::walk_arm(this, arm); } -fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { - match expr.node { +fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr) { + match expr.kind { hir::ExprKind::Assign(ref l, _) => { this.check_place(&l); - - intravisit::walk_expr(this, expr); } hir::ExprKind::AssignOp(_, ref l, _) => { if !this.tables.is_method_call(expr) { this.check_place(&l); } - - intravisit::walk_expr(this, expr); } hir::ExprKind::InlineAsm(ref ia, ref outputs, ref inputs) => { @@ -1470,8 +1400,6 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { } this.visit_expr(output); } - - intravisit::walk_expr(this, expr); } // no correctness conditions related to liveness @@ -1484,15 +1412,15 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { hir::ExprKind::Lit(_) | hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) | hir::ExprKind::Closure(..) | hir::ExprKind::Path(_) | hir::ExprKind::Yield(..) | - hir::ExprKind::Box(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err => { - intravisit::walk_expr(this, expr); - } + hir::ExprKind::Box(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err => {} } + + intravisit::walk_expr(this, expr); } -impl<'a, 'tcx> Liveness<'a, 'tcx> { +impl<'tcx> Liveness<'_, 'tcx> { fn check_place(&mut self, expr: &'tcx Expr) { - match expr.node { + match expr.kind { hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { if let Res::Local(var_hid) = path.res { let upvars = self.ir.tcx.upvars(self.ir.body_owner); @@ -1503,7 +1431,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // as being used. let ln = self.live_node(expr.hir_id, expr.span); let var = self.variable(var_hid, expr.span); - self.warn_about_dead_assign(expr.span, expr.hir_id, ln, var); + self.warn_about_dead_assign(vec![expr.span], expr.hir_id, ln, var); } } } @@ -1525,109 +1453,112 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } fn warn_about_unused_args(&self, body: &hir::Body, entry_ln: LiveNode) { - for arg in &body.arguments { - arg.pat.each_binding(|_bm, hir_id, _, ident| { - let sp = ident.span; - let var = self.variable(hir_id, sp); - // Ignore unused self. - if ident.name != kw::SelfLower { - if !self.warn_about_unused(vec![sp], hir_id, entry_ln, var) { - if self.live_on_entry(entry_ln, var).is_none() { - self.report_dead_assign(hir_id, sp, var, true); - } - } + for p in &body.params { + self.check_unused_vars_in_pat(&p.pat, Some(entry_ln), |spans, hir_id, ln, var| { + if self.live_on_entry(ln, var).is_none() { + self.report_dead_assign(hir_id, spans, var, true); } - }) + }); } } - fn warn_about_unused_or_dead_vars_in_pat(&mut self, pat: &hir::Pat) { - self.pat_bindings(pat, |this, ln, var, sp, id| { - if !this.warn_about_unused(vec![sp], id, ln, var) { - this.warn_about_dead_assign(sp, id, ln, var); + fn check_unused_vars_in_pat( + &self, + pat: &hir::Pat, + entry_ln: Option, + on_used_on_entry: impl Fn(Vec, HirId, LiveNode, Variable), + ) { + // In an or-pattern, only consider the variable; any later patterns must have the same + // bindings, and we also consider the first pattern to be the "authoritative" set of ids. + // However, we should take the spans of variables with the same name from the later + // patterns so the suggestions to prefix with underscores will apply to those too. + let mut vars: FxIndexMap)> = <_>::default(); + + pat.each_binding(|_, hir_id, pat_sp, ident| { + let ln = entry_ln.unwrap_or_else(|| self.live_node(hir_id, pat_sp)); + let var = self.variable(hir_id, ident.span); + vars.entry(self.ir.variable_name(var)) + .and_modify(|(.., spans)| spans.push(ident.span)) + .or_insert_with(|| (ln, var, hir_id, vec![ident.span])); + }); + + for (_, (ln, var, id, spans)) in vars { + if self.used_on_entry(ln, var) { + on_used_on_entry(spans, id, ln, var); + } else { + self.report_unused(spans, id, ln, var); } - }) + } } - fn warn_about_unused(&self, - spans: Vec, - hir_id: HirId, - ln: LiveNode, - var: Variable) - -> bool { - if !self.used_on_entry(ln, var) { - let r = self.should_warn(var); - if let Some(name) = r { - // annoying: for parameters in funcs like `fn(x: i32) - // {ret}`, there is only one node, so asking about - // assigned_on_exit() is not meaningful. - let is_assigned = if ln == self.s.exit_ln { - false - } else { - self.assigned_on_exit(ln, var).is_some() - }; + fn report_unused(&self, spans: Vec, hir_id: HirId, ln: LiveNode, var: Variable) { + if let Some(name) = self.should_warn(var).filter(|name| name != "self") { + // annoying: for parameters in funcs like `fn(x: i32) + // {ret}`, there is only one node, so asking about + // assigned_on_exit() is not meaningful. + let is_assigned = if ln == self.s.exit_ln { + false + } else { + self.assigned_on_exit(ln, var).is_some() + }; - if is_assigned { - self.ir.tcx.lint_hir_note( - lint::builtin::UNUSED_VARIABLES, - hir_id, - spans, - &format!("variable `{}` is assigned to, but never used", name), - &format!("consider using `_{}` instead", name), - ); - } else if name != "self" { - let mut err = self.ir.tcx.struct_span_lint_hir( - lint::builtin::UNUSED_VARIABLES, - hir_id, - spans.clone(), - &format!("unused variable: `{}`", name), - ); + if is_assigned { + self.ir.tcx.lint_hir_note( + lint::builtin::UNUSED_VARIABLES, + hir_id, + spans, + &format!("variable `{}` is assigned to, but never used", name), + &format!("consider using `_{}` instead", name), + ); + } else { + let mut err = self.ir.tcx.struct_span_lint_hir( + lint::builtin::UNUSED_VARIABLES, + hir_id, + spans.clone(), + &format!("unused variable: `{}`", name), + ); + + if self.ir.variable_is_shorthand(var) { + if let Node::Binding(pat) = self.ir.tcx.hir().get(hir_id) { + // Handle `ref` and `ref mut`. + let spans = spans.iter() + .map(|_span| (pat.span, format!("{}: _", name))) + .collect(); - if self.ir.variable_is_shorthand(var) { - if let Node::Binding(pat) = self.ir.tcx.hir().get(hir_id) { - // Handle `ref` and `ref mut`. - let spans = spans.iter() - .map(|_span| (pat.span, format!("{}: _", name))) - .collect(); - - err.multipart_suggestion( - "try ignoring the field", - spans, - Applicability::MachineApplicable, - ); - } - } else { err.multipart_suggestion( - "consider prefixing with an underscore", - spans.iter().map(|span| (*span, format!("_{}", name))).collect(), + "try ignoring the field", + spans, Applicability::MachineApplicable, ); } - - err.emit() + } else { + err.multipart_suggestion( + "consider prefixing with an underscore", + spans.iter().map(|span| (*span, format!("_{}", name))).collect(), + Applicability::MachineApplicable, + ); } + + err.emit() } - true - } else { - false } } - fn warn_about_dead_assign(&self, sp: Span, hir_id: HirId, ln: LiveNode, var: Variable) { + fn warn_about_dead_assign(&self, spans: Vec, hir_id: HirId, ln: LiveNode, var: Variable) { if self.live_on_exit(ln, var).is_none() { - self.report_dead_assign(hir_id, sp, var, false); + self.report_dead_assign(hir_id, spans, var, false); } } - fn report_dead_assign(&self, hir_id: HirId, sp: Span, var: Variable, is_argument: bool) { + fn report_dead_assign(&self, hir_id: HirId, spans: Vec, var: Variable, is_param: bool) { if let Some(name) = self.should_warn(var) { - if is_argument { - self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp, + if is_param { + self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, spans, &format!("value passed to `{}` is never read", name)) .help("maybe it is overwritten before being read?") .emit(); } else { - self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp, + self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, spans, &format!("value assigned to `{}` is never read", name)) .help("maybe it is overwritten before being read?") .emit(); diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index afe4c78dcfc37..6c9e018fafc4f 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -7,7 +7,7 @@ use rustc::ty::TyCtxt; use rustc::hir::def_id::DefId; use rustc::hir::map::Map; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; -use rustc::hir::{self, Node, Destination}; +use rustc::hir::{self, Node, Destination, GeneratorMovability}; use syntax::struct_span_err; use syntax_pos::Span; use errors::Applicability; @@ -16,7 +16,8 @@ use errors::Applicability; enum Context { Normal, Loop(hir::LoopSource), - Closure, + Closure(Span), + AsyncClosure(Span), LabeledBlock, AnonConst, } @@ -53,13 +54,18 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { } fn visit_expr(&mut self, e: &'hir hir::Expr) { - match e.node { + match e.kind { hir::ExprKind::Loop(ref b, _, source) => { self.with_context(Loop(source), |v| v.visit_block(&b)); } - hir::ExprKind::Closure(_, ref function_decl, b, _, _) => { + hir::ExprKind::Closure(_, ref function_decl, b, span, movability) => { + let cx = if let Some(GeneratorMovability::Static) = movability { + AsyncClosure(span) + } else { + Closure(span) + }; self.visit_fn_decl(&function_decl); - self.with_context(Closure, |v| v.visit_nested_body(b)); + self.with_context(cx, |v| v.visit_nested_body(b)); } hir::ExprKind::Block(ref b, Some(_label)) => { self.with_context(LabeledBlock, |v| v.visit_block(&b)); @@ -93,7 +99,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { let loop_kind = if loop_id == hir::DUMMY_HIR_ID { None } else { - Some(match self.hir_map.expect_expr(loop_id).node { + Some(match self.hir_map.expect_expr(loop_id).kind { hir::ExprKind::Loop(_, _, source) => source, ref r => span_bug!(e.span, "break label resolved to a non-loop: {:?}", r), @@ -164,18 +170,22 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { } fn require_break_cx(&self, name: &str, span: Span) { - match self.cx { - LabeledBlock | Loop(_) => {} - Closure => { - struct_span_err!(self.sess, span, E0267, "`{}` inside of a closure", name) - .span_label(span, "cannot break inside of a closure") + let err_inside_of = |article, ty, closure_span| { + struct_span_err!(self.sess, span, E0267, "`{}` inside of {} {}", name, article, ty) + .span_label(span, format!("cannot `{}` inside of {} {}", name, article, ty)) + .span_label(closure_span, &format!("enclosing {}", ty)) .emit(); - } + }; + + match self.cx { + LabeledBlock | Loop(_) => {}, + Closure(closure_span) => err_inside_of("a", "closure", closure_span), + AsyncClosure(closure_span) => err_inside_of("an", "`async` block", closure_span), Normal | AnonConst => { - struct_span_err!(self.sess, span, E0268, "`{}` outside of loop", name) - .span_label(span, "cannot break outside of a loop") + struct_span_err!(self.sess, span, E0268, "`{}` outside of a loop", name) + .span_label(span, format!("cannot `{}` outside of a loop", name)) .emit(); - } + }, } } diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs deleted file mode 100644 index f2461f7016131..0000000000000 --- a/src/librustc_passes/rvalue_promotion.rs +++ /dev/null @@ -1,662 +0,0 @@ -// Verifies that the types and values of const and static items -// are safe. The rules enforced by this module are: -// -// - For each *mutable* static item, it checks that its **type**: -// - doesn't have a destructor -// - doesn't own a box -// -// - For each *immutable* static item, it checks that its **value**: -// - doesn't own a box -// - doesn't contain a struct literal or a call to an enum variant / struct constructor where -// - the type of the struct/enum has a dtor -// -// Rules Enforced Elsewhere: -// - It's not possible to take the address of a static item with unsafe interior. This is enforced -// by borrowck::gather_loans - -use rustc::ty::cast::CastTy; -use rustc::hir::def::{Res, DefKind, CtorKind}; -use rustc::hir::def_id::DefId; -use rustc::middle::expr_use_visitor as euv; -use rustc::middle::mem_categorization as mc; -use rustc::middle::mem_categorization::Categorization; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::query::Providers; -use rustc::ty::subst::{InternalSubsts, SubstsRef}; -use rustc::util::nodemap::{ItemLocalSet, HirIdSet}; -use rustc::hir; -use syntax::symbol::sym; -use syntax_pos::{Span, DUMMY_SP}; -use log::debug; -use Promotability::*; -use std::ops::{BitAnd, BitAndAssign, BitOr}; - -pub fn provide(providers: &mut Providers<'_>) { - *providers = Providers { - rvalue_promotable_map, - const_is_rvalue_promotable_to_static, - ..*providers - }; -} - -fn const_is_rvalue_promotable_to_static(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - assert!(def_id.is_local()); - - let hir_id = tcx.hir().as_local_hir_id(def_id) - .expect("rvalue_promotable_map invoked with non-local def-id"); - let body_id = tcx.hir().body_owned_by(hir_id); - tcx.rvalue_promotable_map(def_id).contains(&body_id.hir_id.local_id) -} - -fn rvalue_promotable_map(tcx: TyCtxt<'_>, def_id: DefId) -> &ItemLocalSet { - let outer_def_id = tcx.closure_base_def_id(def_id); - if outer_def_id != def_id { - return tcx.rvalue_promotable_map(outer_def_id); - } - - let mut visitor = CheckCrateVisitor { - tcx, - tables: &ty::TypeckTables::empty(None), - in_fn: false, - in_static: false, - mut_rvalue_borrows: Default::default(), - param_env: ty::ParamEnv::empty(), - identity_substs: InternalSubsts::empty(), - result: ItemLocalSet::default(), - }; - - // `def_id` should be a `Body` owner - let hir_id = tcx.hir().as_local_hir_id(def_id) - .expect("rvalue_promotable_map invoked with non-local def-id"); - let body_id = tcx.hir().body_owned_by(hir_id); - let _ = visitor.check_nested_body(body_id); - - tcx.arena.alloc(visitor.result) -} - -struct CheckCrateVisitor<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - in_fn: bool, - in_static: bool, - mut_rvalue_borrows: HirIdSet, - param_env: ty::ParamEnv<'tcx>, - identity_substs: SubstsRef<'tcx>, - tables: &'a ty::TypeckTables<'tcx>, - result: ItemLocalSet, -} - -#[must_use] -#[derive(Debug, Clone, Copy, PartialEq)] -enum Promotability { - Promotable, - NotPromotable -} - -impl BitAnd for Promotability { - type Output = Self; - - fn bitand(self, rhs: Self) -> Self { - match (self, rhs) { - (Promotable, Promotable) => Promotable, - _ => NotPromotable, - } - } -} - -impl BitAndAssign for Promotability { - fn bitand_assign(&mut self, rhs: Self) { - *self = *self & rhs - } -} - -impl BitOr for Promotability { - type Output = Self; - - fn bitor(self, rhs: Self) -> Self { - match (self, rhs) { - (NotPromotable, NotPromotable) => NotPromotable, - _ => Promotable, - } - } -} - -impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { - // Returns true iff all the values of the type are promotable. - fn type_promotability(&mut self, ty: Ty<'tcx>) -> Promotability { - debug!("type_promotability({})", ty); - - if ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) && - !ty.needs_drop(self.tcx, self.param_env) { - Promotable - } else { - NotPromotable - } - } - - fn handle_const_fn_call( - &mut self, - def_id: DefId, - ) -> Promotability { - if self.tcx.is_promotable_const_fn(def_id) { - Promotable - } else { - NotPromotable - } - } - - /// While the `ExprUseVisitor` walks, we will identify which - /// expressions are borrowed, and insert their IDs into this - /// table. Actually, we insert the "borrow-id", which is normally - /// the ID of the expression being borrowed: but in the case of - /// `ref mut` borrows, the `id` of the pattern is - /// inserted. Therefore, later we remove that entry from the table - /// and transfer it over to the value being matched. This will - /// then prevent said value from being promoted. - fn remove_mut_rvalue_borrow(&mut self, pat: &hir::Pat) -> bool { - let mut any_removed = false; - pat.walk(|p| { - any_removed |= self.mut_rvalue_borrows.remove(&p.hir_id); - true - }); - any_removed - } -} - -impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { - fn check_nested_body(&mut self, body_id: hir::BodyId) -> Promotability { - let item_id = self.tcx.hir().body_owner(body_id); - let item_def_id = self.tcx.hir().local_def_id(item_id); - - let outer_in_fn = self.in_fn; - let outer_tables = self.tables; - let outer_param_env = self.param_env; - let outer_identity_substs = self.identity_substs; - - self.in_fn = false; - self.in_static = false; - - match self.tcx.hir().body_owner_kind(item_id) { - hir::BodyOwnerKind::Closure | - hir::BodyOwnerKind::Fn => self.in_fn = true, - hir::BodyOwnerKind::Static(_) => self.in_static = true, - _ => {} - }; - - - self.tables = self.tcx.typeck_tables_of(item_def_id); - self.param_env = self.tcx.param_env(item_def_id); - self.identity_substs = InternalSubsts::identity_for_item(self.tcx, item_def_id); - - let body = self.tcx.hir().body(body_id); - - let tcx = self.tcx; - let param_env = self.param_env; - let region_scope_tree = self.tcx.region_scope_tree(item_def_id); - let tables = self.tables; - euv::ExprUseVisitor::new( - self, - tcx, - item_def_id, - param_env, - ®ion_scope_tree, - tables, - None, - ).consume_body(body); - - let body_promotable = self.check_expr(&body.value); - self.in_fn = outer_in_fn; - self.tables = outer_tables; - self.param_env = outer_param_env; - self.identity_substs = outer_identity_substs; - body_promotable - } - - fn check_stmt(&mut self, stmt: &'tcx hir::Stmt) -> Promotability { - match stmt.node { - hir::StmtKind::Local(ref local) => { - if self.remove_mut_rvalue_borrow(&local.pat) { - if let Some(init) = &local.init { - self.mut_rvalue_borrows.insert(init.hir_id); - } - } - - if let Some(ref expr) = local.init { - let _ = self.check_expr(&expr); - } - NotPromotable - } - // Item statements are allowed - hir::StmtKind::Item(..) => Promotable, - hir::StmtKind::Expr(ref box_expr) | - hir::StmtKind::Semi(ref box_expr) => { - let _ = self.check_expr(box_expr); - NotPromotable - } - } - } - - fn check_expr(&mut self, ex: &'tcx hir::Expr) -> Promotability { - let node_ty = self.tables.node_type(ex.hir_id); - let mut outer = check_expr_kind(self, ex, node_ty); - outer &= check_adjustments(self, ex); - - // Handle borrows on (or inside the autorefs of) this expression. - if self.mut_rvalue_borrows.remove(&ex.hir_id) { - outer = NotPromotable - } - - if outer == Promotable { - self.result.insert(ex.hir_id.local_id); - } - outer - } - - fn check_block(&mut self, block: &'tcx hir::Block) -> Promotability { - let mut iter_result = Promotable; - for index in block.stmts.iter() { - iter_result &= self.check_stmt(index); - } - match block.expr { - Some(ref box_expr) => iter_result & self.check_expr(&*box_expr), - None => iter_result, - } - } -} - -/// This function is used to enforce the constraints on -/// const/static items. It walks through the *value* -/// of the item walking down the expression and evaluating -/// every nested expression. If the expression is not part -/// of a const/static item, it is qualified for promotion -/// instead of producing errors. -fn check_expr_kind<'a, 'tcx>( - v: &mut CheckCrateVisitor<'a, 'tcx>, - e: &'tcx hir::Expr, node_ty: Ty<'tcx>) -> Promotability { - - let ty_result = match node_ty.sty { - ty::Adt(def, _) if def.has_dtor(v.tcx) => { - NotPromotable - } - _ => Promotable - }; - - let node_result = match e.node { - hir::ExprKind::Box(ref expr) => { - let _ = v.check_expr(&expr); - NotPromotable - } - hir::ExprKind::Unary(op, ref expr) => { - let expr_promotability = v.check_expr(expr); - if v.tables.is_method_call(e) || op == hir::UnDeref { - return NotPromotable; - } - expr_promotability - } - hir::ExprKind::Binary(op, ref lhs, ref rhs) => { - let lefty = v.check_expr(lhs); - let righty = v.check_expr(rhs); - if v.tables.is_method_call(e) { - return NotPromotable; - } - match v.tables.node_type(lhs.hir_id).sty { - ty::RawPtr(_) | ty::FnPtr(..) => { - assert!(op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne || - op.node == hir::BinOpKind::Le || op.node == hir::BinOpKind::Lt || - op.node == hir::BinOpKind::Ge || op.node == hir::BinOpKind::Gt); - - NotPromotable - } - _ => lefty & righty - } - } - hir::ExprKind::Cast(ref from, _) => { - let expr_promotability = v.check_expr(from); - debug!("checking const cast(id={})", from.hir_id); - let cast_in = CastTy::from_ty(v.tables.expr_ty(from)); - let cast_out = CastTy::from_ty(v.tables.expr_ty(e)); - match (cast_in, cast_out) { - (Some(CastTy::FnPtr), Some(CastTy::Int(_))) | - (Some(CastTy::Ptr(_)), Some(CastTy::Int(_))) => NotPromotable, - (_, _) => expr_promotability - } - } - hir::ExprKind::Path(ref qpath) => { - let res = v.tables.qpath_res(qpath, e.hir_id); - match res { - Res::Def(DefKind::Ctor(..), _) - | Res::Def(DefKind::Fn, _) - | Res::Def(DefKind::Method, _) - | Res::SelfCtor(..) => - Promotable, - - // References to a static that are themselves within a static - // are inherently promotable with the exception - // of "#[thread_local]" statics, which may not - // outlive the current function - Res::Def(DefKind::Static, did) => { - - if v.in_static { - for attr in &v.tcx.get_attrs(did)[..] { - if attr.check_name(sym::thread_local) { - debug!("reference to `Static(id={:?})` is unpromotable \ - due to a `#[thread_local]` attribute", did); - return NotPromotable; - } - } - Promotable - } else { - debug!("reference to `Static(id={:?})` is unpromotable as it is not \ - referenced from a static", did); - NotPromotable - } - } - - Res::Def(DefKind::Const, did) | - Res::Def(DefKind::AssocConst, did) => { - let promotable = if v.tcx.trait_of_item(did).is_some() { - // Don't peek inside trait associated constants. - NotPromotable - } else if v.tcx.at(e.span).const_is_rvalue_promotable_to_static(did) { - Promotable - } else { - NotPromotable - }; - // Just in case the type is more specific than the definition, - // e.g., impl associated const with type parameters, check it. - // Also, trait associated consts are relaxed by this. - promotable | v.type_promotability(node_ty) - } - _ => NotPromotable - } - } - hir::ExprKind::Call(ref callee, ref hirvec) => { - let mut call_result = v.check_expr(callee); - for index in hirvec.iter() { - call_result &= v.check_expr(index); - } - let mut callee = &**callee; - loop { - callee = match callee.node { - hir::ExprKind::Block(ref block, _) => match block.expr { - Some(ref tail) => &tail, - None => break - }, - _ => break - }; - } - // The callee is an arbitrary expression, it doesn't necessarily have a definition. - let def = if let hir::ExprKind::Path(ref qpath) = callee.node { - v.tables.qpath_res(qpath, callee.hir_id) - } else { - Res::Err - }; - let def_result = match def { - Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | - Res::SelfCtor(..) => Promotable, - Res::Def(DefKind::Fn, did) => v.handle_const_fn_call(did), - Res::Def(DefKind::Method, did) => { - match v.tcx.associated_item(did).container { - ty::ImplContainer(_) => v.handle_const_fn_call(did), - ty::TraitContainer(_) => NotPromotable, - } - } - _ => NotPromotable, - }; - def_result & call_result - } - hir::ExprKind::MethodCall(ref _pathsegment, ref _span, ref hirvec) => { - let mut method_call_result = Promotable; - for index in hirvec.iter() { - method_call_result &= v.check_expr(index); - } - if let Some(def_id) = v.tables.type_dependent_def_id(e.hir_id) { - match v.tcx.associated_item(def_id).container { - ty::ImplContainer(_) => method_call_result & v.handle_const_fn_call(def_id), - ty::TraitContainer(_) => NotPromotable, - } - } else { - v.tcx.sess.delay_span_bug(e.span, "no type-dependent def for method call"); - NotPromotable - } - } - hir::ExprKind::Struct(ref _qpath, ref hirvec, ref option_expr) => { - let mut struct_result = Promotable; - for index in hirvec.iter() { - struct_result &= v.check_expr(&index.expr); - } - if let Some(ref expr) = *option_expr { - struct_result &= v.check_expr(&expr); - } - if let ty::Adt(adt, ..) = v.tables.expr_ty(e).sty { - // unsafe_cell_type doesn't necessarily exist with no_core - if Some(adt.did) == v.tcx.lang_items().unsafe_cell_type() { - return NotPromotable; - } - } - struct_result - } - - hir::ExprKind::Lit(_) | - hir::ExprKind::Err => Promotable, - - hir::ExprKind::AddrOf(_, ref expr) | - hir::ExprKind::Repeat(ref expr, _) | - hir::ExprKind::Type(ref expr, _) | - hir::ExprKind::DropTemps(ref expr) => { - v.check_expr(&expr) - } - - hir::ExprKind::Closure(_capture_clause, ref _box_fn_decl, - body_id, _span, _option_generator_movability) => { - let nested_body_promotable = v.check_nested_body(body_id); - // Paths in constant contexts cannot refer to local variables, - // as there are none, and thus closures can't have upvars there. - let closure_def_id = v.tcx.hir().local_def_id(e.hir_id); - if !v.tcx.upvars(closure_def_id).map_or(true, |v| v.is_empty()) { - NotPromotable - } else { - nested_body_promotable - } - } - - hir::ExprKind::Field(ref expr, _ident) => { - let expr_promotability = v.check_expr(&expr); - if let Some(def) = v.tables.expr_ty(expr).ty_adt_def() { - if def.is_union() { - return NotPromotable; - } - } - expr_promotability - } - - hir::ExprKind::Block(ref box_block, ref _option_label) => { - v.check_block(box_block) - } - - hir::ExprKind::Index(ref lhs, ref rhs) => { - let lefty = v.check_expr(lhs); - let righty = v.check_expr(rhs); - if v.tables.is_method_call(e) { - return NotPromotable; - } - lefty & righty - } - - hir::ExprKind::Array(ref hirvec) => { - let mut array_result = Promotable; - for index in hirvec.iter() { - array_result &= v.check_expr(index); - } - array_result - } - - hir::ExprKind::Tup(ref hirvec) => { - let mut tup_result = Promotable; - for index in hirvec.iter() { - tup_result &= v.check_expr(index); - } - tup_result - } - - // Conditional control flow (possible to implement). - hir::ExprKind::Match(ref expr, ref hirvec_arm, ref _match_source) => { - // Compute the most demanding borrow from all the arms' - // patterns and set that on the discriminator. - let mut mut_borrow = false; - for pat in hirvec_arm.iter().flat_map(|arm| &arm.pats) { - mut_borrow = v.remove_mut_rvalue_borrow(pat); - } - if mut_borrow { - v.mut_rvalue_borrows.insert(expr.hir_id); - } - - let _ = v.check_expr(expr); - for index in hirvec_arm.iter() { - let _ = v.check_expr(&*index.body); - if let Some(hir::Guard::If(ref expr)) = index.guard { - let _ = v.check_expr(&expr); - } - } - NotPromotable - } - - hir::ExprKind::Loop(ref box_block, ref _option_label, ref _loop_source) => { - let _ = v.check_block(box_block); - NotPromotable - } - - // More control flow (also not very meaningful). - hir::ExprKind::Break(_, ref option_expr) | hir::ExprKind::Ret(ref option_expr) => { - if let Some(ref expr) = *option_expr { - let _ = v.check_expr(&expr); - } - NotPromotable - } - - hir::ExprKind::Continue(_) => { - NotPromotable - } - - // Generator expressions - hir::ExprKind::Yield(ref expr, _) => { - let _ = v.check_expr(&expr); - NotPromotable - } - - // Expressions with side-effects. - hir::ExprKind::AssignOp(_, ref lhs, ref rhs) | hir::ExprKind::Assign(ref lhs, ref rhs) => { - let _ = v.check_expr(lhs); - let _ = v.check_expr(rhs); - NotPromotable - } - - hir::ExprKind::InlineAsm(ref _inline_asm, ref hirvec_lhs, ref hirvec_rhs) => { - for index in hirvec_lhs.iter().chain(hirvec_rhs.iter()) { - let _ = v.check_expr(index); - } - NotPromotable - } - }; - ty_result & node_result -} - -/// Checks the adjustments of an expression. -fn check_adjustments<'a, 'tcx>( - v: &mut CheckCrateVisitor<'a, 'tcx>, - e: &hir::Expr) -> Promotability { - use rustc::ty::adjustment::*; - - let mut adjustments = v.tables.expr_adjustments(e).iter().peekable(); - while let Some(adjustment) = adjustments.next() { - match adjustment.kind { - Adjust::NeverToAny | - Adjust::Pointer(_) | - Adjust::Borrow(_) => {} - - Adjust::Deref(_) => { - if let Some(next_adjustment) = adjustments.peek() { - if let Adjust::Borrow(_) = next_adjustment.kind { - continue; - } - } - return NotPromotable; - } - } - } - Promotable -} - -impl<'a, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'tcx> { - fn consume(&mut self, - _consume_id: hir::HirId, - _consume_span: Span, - _cmt: &mc::cmt_<'_>, - _mode: euv::ConsumeMode) {} - - fn borrow(&mut self, - borrow_id: hir::HirId, - _borrow_span: Span, - cmt: &mc::cmt_<'tcx>, - _loan_region: ty::Region<'tcx>, - bk: ty::BorrowKind, - loan_cause: euv::LoanCause) { - debug!( - "borrow(borrow_id={:?}, cmt={:?}, bk={:?}, loan_cause={:?})", - borrow_id, - cmt, - bk, - loan_cause, - ); - - // Kind of hacky, but we allow Unsafe coercions in constants. - // These occur when we convert a &T or *T to a *U, as well as - // when making a thin pointer (e.g., `*T`) into a fat pointer - // (e.g., `*Trait`). - if let euv::LoanCause::AutoUnsafe = loan_cause { - return; - } - - let mut cur = cmt; - loop { - match cur.cat { - Categorization::ThreadLocal(..) | - Categorization::Rvalue(..) => { - if loan_cause == euv::MatchDiscriminant { - // Ignore the dummy immutable borrow created by EUV. - break; - } - if bk.to_mutbl_lossy() == hir::MutMutable { - self.mut_rvalue_borrows.insert(borrow_id); - } - break; - } - Categorization::StaticItem => { - break; - } - Categorization::Deref(ref cmt, _) | - Categorization::Downcast(ref cmt, _) | - Categorization::Interior(ref cmt, _) => { - cur = cmt; - } - - Categorization::Upvar(..) | - Categorization::Local(..) => break, - } - } - } - - fn decl_without_init(&mut self, _id: hir::HirId, _span: Span) {} - fn mutate(&mut self, - _assignment_id: hir::HirId, - _assignment_span: Span, - _assignee_cmt: &mc::cmt_<'_>, - _mode: euv::MutateMode) { - } - - fn matched_pat(&mut self, _: &hir::Pat, _: &mc::cmt_<'_>, _: euv::MatchMode) {} - - fn consume_pat(&mut self, - _consume_pat: &hir::Pat, - _cmt: &mc::cmt_<'_>, - _mode: euv::ConsumeMode) {} -} diff --git a/src/librustc_plugin/Cargo.toml b/src/librustc_plugin/Cargo.toml index 7486281c1eac1..3f11430dc82cb 100644 --- a/src/librustc_plugin/Cargo.toml +++ b/src/librustc_plugin/Cargo.toml @@ -1,12 +1,12 @@ [package] authors = ["The Rust Project Developers"] -name = "rustc_plugin" +name = "rustc_plugin_impl" version = "0.0.0" build = false edition = "2018" [lib] -name = "rustc_plugin" +name = "rustc_plugin_impl" path = "lib.rs" doctest = false @@ -15,4 +15,3 @@ rustc = { path = "../librustc" } rustc_metadata = { path = "../librustc_metadata" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_plugin/build.rs b/src/librustc_plugin/build.rs index f1bf1111cf700..01559a95c9c31 100644 --- a/src/librustc_plugin/build.rs +++ b/src/librustc_plugin/build.rs @@ -15,7 +15,7 @@ struct RegistrarFinder { impl<'v> ItemLikeVisitor<'v> for RegistrarFinder { fn visit_item(&mut self, item: &hir::Item) { - if let hir::ItemKind::Fn(..) = item.node { + if let hir::ItemKind::Fn(..) = item.kind { if attr::contains_name(&item.attrs, sym::plugin_registrar) { self.registrars.push((item.hir_id, item.span)); } diff --git a/src/librustc_plugin/deprecated/Cargo.toml b/src/librustc_plugin/deprecated/Cargo.toml new file mode 100644 index 0000000000000..cc75f7b9ab20d --- /dev/null +++ b/src/librustc_plugin/deprecated/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_plugin" +version = "0.0.0" +build = false +edition = "2018" + +[lib] +name = "rustc_plugin" +path = "lib.rs" +doctest = false + +[dependencies] +rustc_plugin_impl = { path = ".." } diff --git a/src/librustc_plugin/deprecated/lib.rs b/src/librustc_plugin/deprecated/lib.rs new file mode 100644 index 0000000000000..1d0afe84c25a8 --- /dev/null +++ b/src/librustc_plugin/deprecated/lib.rs @@ -0,0 +1,8 @@ +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(staged_api)] +#![unstable(feature = "rustc_private", issue = "27812")] +#![rustc_deprecated(since = "1.38.0", reason = "\ + import this through `rustc_driver::plugin` instead to make TLS work correctly. \ + See https://github.com/rust-lang/rust/issues/62717")] + +pub use rustc_plugin_impl::*; diff --git a/src/librustc_plugin/error_codes.rs b/src/librustc_plugin/error_codes.rs index b5f6a8d905d31..7b3f01c0ee111 100644 --- a/src/librustc_plugin/error_codes.rs +++ b/src/librustc_plugin/error_codes.rs @@ -1,9 +1,4 @@ -use syntax::{register_diagnostics, register_long_diagnostics}; - -register_long_diagnostics! { - -} - -register_diagnostics! { - E0498 // malformed plugin attribute +syntax::register_diagnostics! { +; + E0498, // malformed plugin attribute } diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs index 25a7a8cdeb6d6..4e1a47c503e59 100644 --- a/src/librustc_plugin/lib.rs +++ b/src/librustc_plugin/lib.rs @@ -16,12 +16,11 @@ //! #![feature(plugin_registrar)] //! #![feature(rustc_private)] //! -//! extern crate rustc_plugin; //! extern crate rustc_driver; //! extern crate syntax; //! extern crate syntax_pos; //! -//! use rustc_plugin::Registry; +//! use rustc_driver::plugin::Registry; //! use syntax::ext::base::{ExtCtxt, MacResult}; //! use syntax_pos::Span; //! use syntax::tokenstream::TokenTree; @@ -55,15 +54,12 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(nll)] -#![feature(rustc_diagnostic_macros)] #![recursion_limit="256"] pub use registry::Registry; -mod error_codes; +pub mod error_codes; pub mod registry; pub mod load; pub mod build; - -__build_diagnostic_array! { librustc_plugin, DIAGNOSTICS } diff --git a/src/librustc_privacy/error_codes.rs b/src/librustc_privacy/error_codes.rs index 70a799d426a07..03afb547d3a22 100644 --- a/src/librustc_privacy/error_codes.rs +++ b/src/librustc_privacy/error_codes.rs @@ -1,8 +1,9 @@ -register_long_diagnostics! { +syntax::register_diagnostics! { E0445: r##" -A private trait was used on a public type parameter bound. Erroneous code -examples: +A private trait was used on a public type parameter bound. + +Erroneous code examples: ```compile_fail,E0445 #![deny(private_in_public)] @@ -32,7 +33,9 @@ pub fn foo (t: T) {} // ok! "##, E0446: r##" -A private type was used in a public type signature. Erroneous code example: +A private type was used in a public type signature. + +Erroneous code example: ```compile_fail,E0446 #![deny(private_in_public)] @@ -65,7 +68,9 @@ mod Foo { E0447: r##" #### Note: this error code is no longer emitted by the compiler. -The `pub` keyword was used inside a function. Erroneous code example: +The `pub` keyword was used inside a function. + +Erroneous code example: ``` fn foo() { @@ -79,7 +84,11 @@ is invalid. "##, E0448: r##" -The `pub` keyword was used inside a public enum. Erroneous code example: +#### Note: this error code is no longer emitted by the compiler. + +The `pub` keyword was used inside a public enum. + +Erroneous code example: ```compile_fail pub enum Foo { @@ -106,7 +115,9 @@ pub enum Foo { "##, E0451: r##" -A struct constructor with private fields was invoked. Erroneous code example: +A struct constructor with private fields was invoked. + +Erroneous code example: ```compile_fail,E0451 mod Bar { @@ -154,8 +165,5 @@ let f = Bar::Foo::new(); // ok! ``` "##, -} - -register_diagnostics! { // E0450, moved into resolve } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 4040c0166d859..f44692b7aea7d 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -2,7 +2,6 @@ #![feature(in_band_lifetimes)] #![feature(nll)] -#![feature(rustc_diagnostic_macros)] #![recursion_limit="256"] @@ -31,7 +30,7 @@ use syntax_pos::Span; use std::{cmp, fmt, mem}; use std::marker::PhantomData; -mod error_codes; +pub mod error_codes; //////////////////////////////////////////////////////////////////////////////// /// Generic infrastructure used to implement specific visitors below. @@ -130,7 +129,7 @@ where fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { let tcx = self.def_id_visitor.tcx(); // InternalSubsts are not visited here because they are visited below in `super_visit_with`. - match ty.sty { + match ty.kind { ty::Adt(&ty::AdtDef { did: def_id, .. }, ..) | ty::Foreign(def_id) | ty::FnDef(def_id, ..) | @@ -145,7 +144,7 @@ where // Default type visitor doesn't visit signatures of fn types. // Something like `fn() -> Priv {my_func}` is considered a private type even if // `my_func` is public, so we need to visit signatures. - if let ty::FnDef(..) = ty.sty { + if let ty::FnDef(..) = ty.kind { if tcx.fn_sig(def_id).visit_with(self) { return true; } @@ -229,12 +228,19 @@ fn def_id_visibility<'tcx>( let vis = match tcx.hir().get(hir_id) { Node::Item(item) => &item.vis, Node::ForeignItem(foreign_item) => &foreign_item.vis, + Node::MacroDef(macro_def) => { + if attr::contains_name(¯o_def.attrs, sym::macro_export) { + return (ty::Visibility::Public, macro_def.span, "public"); + } else { + ¯o_def.vis + } + }, Node::TraitItem(..) | Node::Variant(..) => { return def_id_visibility(tcx, tcx.hir().get_parent_did(hir_id)); } Node::ImplItem(impl_item) => { match tcx.hir().get(tcx.hir().get_parent_item(hir_id)) { - Node::Item(item) => match &item.node { + Node::Item(item) => match &item.kind { hir::ItemKind::Impl(.., None, _, _) => &impl_item.vis, hir::ItemKind::Impl(.., Some(trait_ref), _, _) => return def_id_visibility(tcx, trait_ref.path.res.def_id()), @@ -433,11 +439,24 @@ impl VisibilityLike for Option { struct EmbargoVisitor<'tcx> { tcx: TyCtxt<'tcx>, - // Accessibility levels for reachable nodes. + /// Accessibility levels for reachable nodes. access_levels: AccessLevels, - // Previous accessibility level; `None` means unreachable. + /// A set of pairs corresponding to modules, where the first module is + /// reachable via a macro that's defined in the second module. This cannot + /// be represented as reachable because it can't handle the following case: + /// + /// pub mod n { // Should be `Public` + /// pub(crate) mod p { // Should *not* be accessible + /// pub fn f() -> i32 { 12 } // Must be `Reachable` + /// } + /// } + /// pub macro m() { + /// n::p::f() + /// } + macro_reachable: FxHashSet<(hir::HirId, DefId)>, + /// Previous accessibility level; `None` means unreachable. prev_level: Option, - // Has something changed in the level map? + /// Has something changed in the level map? changed: bool, } @@ -452,7 +471,7 @@ impl EmbargoVisitor<'tcx> { self.access_levels.map.get(&id).cloned() } - // Updates node level and returns the updated level. + /// Updates node level and returns the updated level. fn update(&mut self, id: hir::HirId, level: Option) -> Option { let old_level = self.get(id); // Accessibility levels can only grow. @@ -477,6 +496,117 @@ impl EmbargoVisitor<'tcx> { } } + /// Updates the item as being reachable through a macro defined in the given + /// module. Returns `true` if the level has changed. + fn update_macro_reachable(&mut self, reachable_mod: hir::HirId, defining_mod: DefId) -> bool { + if self.macro_reachable.insert((reachable_mod, defining_mod)) { + self.update_macro_reachable_mod(reachable_mod, defining_mod); + true + } else { + false + } + } + + fn update_macro_reachable_mod(&mut self, reachable_mod: hir::HirId, defining_mod: DefId) { + let module_def_id = self.tcx.hir().local_def_id(reachable_mod); + let module = self.tcx.hir().get_module(module_def_id).0; + for item_id in &module.item_ids { + let hir_id = item_id.id; + let item_def_id = self.tcx.hir().local_def_id(hir_id); + if let Some(def_kind) = self.tcx.def_kind(item_def_id) { + let item = self.tcx.hir().expect_item(hir_id); + let vis = ty::Visibility::from_hir(&item.vis, hir_id, self.tcx); + self.update_macro_reachable_def(hir_id, def_kind, vis, defining_mod); + } + } + if let Some(exports) = self.tcx.module_exports(module_def_id) { + for export in exports { + if export.vis.is_accessible_from(defining_mod, self.tcx) { + if let Res::Def(def_kind, def_id) = export.res { + let vis = def_id_visibility(self.tcx, def_id).0; + if let Some(hir_id) = self.tcx.hir().as_local_hir_id(def_id) { + self.update_macro_reachable_def(hir_id, def_kind, vis, defining_mod); + } + } + } + } + } + } + + fn update_macro_reachable_def( + &mut self, + hir_id: hir::HirId, + def_kind: DefKind, + vis: ty::Visibility, + module: DefId, + ) { + let level = Some(AccessLevel::Reachable); + if let ty::Visibility::Public = vis { + self.update(hir_id, level); + } + match def_kind { + // No type privacy, so can be directly marked as reachable. + DefKind::Const + | DefKind::Macro(_) + | DefKind::Static + | DefKind::TraitAlias + | DefKind::TyAlias => { + if vis.is_accessible_from(module, self.tcx) { + self.update(hir_id, level); + } + }, + + // We can't use a module name as the final segment of a path, except + // in use statements. Since re-export checking doesn't consider + // hygiene these don't need to be marked reachable. The contents of + // the module, however may be reachable. + DefKind::Mod => { + if vis.is_accessible_from(module, self.tcx) { + self.update_macro_reachable(hir_id, module); + } + } + + DefKind::Struct | DefKind::Union => { + // While structs and unions have type privacy, their fields do + // not. + if let ty::Visibility::Public = vis { + let item = self.tcx.hir().expect_item(hir_id); + if let hir::ItemKind::Struct(ref struct_def, _) + | hir::ItemKind::Union(ref struct_def, _) = item.kind + { + for field in struct_def.fields() { + let field_vis = ty::Visibility::from_hir( + &field.vis, + field.hir_id, + self.tcx, + ); + if field_vis.is_accessible_from(module, self.tcx) { + self.reach(field.hir_id, level).ty(); + } + } + } else { + bug!("item {:?} with DefKind {:?}", item, def_kind); + } + } + } + + // These have type privacy, so are not reachable unless they're + // public + DefKind::AssocConst + | DefKind::AssocTy + | DefKind::AssocOpaqueTy + | DefKind::ConstParam + | DefKind::Ctor(_, _) + | DefKind::Enum + | DefKind::ForeignTy + | DefKind::Fn + | DefKind::OpaqueTy + | DefKind::Method + | DefKind::Trait + | DefKind::TyParam + | DefKind::Variant => (), + } + } /// Given the path segments of a `ItemKind::Use`, then we need /// to update the visibility of the intermediate use so that it isn't linted @@ -500,12 +630,12 @@ impl EmbargoVisitor<'tcx> { .and_then(|def_id| self.tcx.hir().as_local_hir_id(def_id)) .map(|module_hir_id| self.tcx.hir().expect_item(module_hir_id)) { - if let hir::ItemKind::Mod(m) = &item.node { + if let hir::ItemKind::Mod(m) = &item.kind { for item_id in m.item_ids.as_ref() { let item = self.tcx.hir().expect_item(item_id.id); let def_id = self.tcx.hir().local_def_id(item_id.id); if !self.tcx.hygienic_eq(segment.ident, item.ident, def_id) { continue; } - if let hir::ItemKind::Use(..) = item.node { + if let hir::ItemKind::Use(..) = item.kind { self.update(item.hir_id, Some(AccessLevel::Exported)); } } @@ -523,7 +653,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { } fn visit_item(&mut self, item: &'tcx hir::Item) { - let inherited_item_level = match item.node { + let inherited_item_level = match item.kind { hir::ItemKind::Impl(..) => Option::::of_impl(item.hir_id, self.tcx, &self.access_levels), // Foreign modules inherit level from parents. @@ -543,14 +673,14 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { let item_level = self.update(item.hir_id, inherited_item_level); // Update levels of nested things. - match item.node { + match item.kind { hir::ItemKind::Enum(ref def, _) => { for variant in &def.variants { - let variant_level = self.update(variant.node.id, item_level); - if let Some(ctor_hir_id) = variant.node.data.ctor_hir_id() { + let variant_level = self.update(variant.id, item_level); + if let Some(ctor_hir_id) = variant.data.ctor_hir_id() { self.update(ctor_hir_id, item_level); } - for field in variant.node.data.fields() { + for field in variant.data.fields() { self.update(field.hir_id, variant_level); } } @@ -597,7 +727,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { } // Mark all items in interfaces of reachable items as reachable. - match item.node { + match item.kind { // The interface is empty. hir::ItemKind::ExternCrate(..) => {} // All nested items are checked by `visit_item`. @@ -669,9 +799,9 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { self.reach(item.hir_id, item_level).generics().predicates(); } for variant in &def.variants { - let variant_level = self.get(variant.node.id); + let variant_level = self.get(variant.id); if variant_level.is_some() { - for field in variant.node.data.fields() { + for field in variant.data.fields() { self.reach(field.hir_id, variant_level).ty(); } // Corner case: if the variant is reachable, but its @@ -746,40 +876,25 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { return } - let module_did = ty::DefIdTree::parent( + let macro_module_def_id = ty::DefIdTree::parent( self.tcx, self.tcx.hir().local_def_id(md.hir_id) ).unwrap(); - let mut module_id = self.tcx.hir().as_local_hir_id(module_did).unwrap(); + let mut module_id = self.tcx.hir().as_local_hir_id(macro_module_def_id).unwrap(); + if !self.tcx.hir().is_hir_id_module(module_id) { + // `module_id` doesn't correspond to a `mod`, return early (#63164). + return; + } let level = if md.vis.node.is_pub() { self.get(module_id) } else { None }; - let level = self.update(md.hir_id, level); - if level.is_none() { - return + let new_level = self.update(md.hir_id, level); + if new_level.is_none() { + return; } loop { - let module = if module_id == hir::CRATE_HIR_ID { - &self.tcx.hir().krate().module - } else if let hir::ItemKind::Mod(ref module) = - self.tcx.hir().expect_item(module_id).node { - module - } else { - unreachable!() - }; - for id in &module.item_ids { - self.update(id.id, level); - } - let def_id = self.tcx.hir().local_def_id(module_id); - if let Some(exports) = self.tcx.module_exports(def_id) { - for export in exports.iter() { - if let Some(hir_id) = self.tcx.hir().as_local_hir_id(export.res.def_id()) { - self.update(hir_id, level); - } - } - } - - if module_id == hir::CRATE_HIR_ID { - break + let changed_reachability = self.update_macro_reachable(module_id, macro_module_def_id); + if changed_reachability || module_id == hir::CRATE_HIR_ID { + break; } module_id = self.tcx.hir().get_parent_node(module_id); } @@ -826,7 +941,12 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.ev.tcx } fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool { if let Some(hir_id) = self.ev.tcx.hir().as_local_hir_id(def_id) { - self.ev.update(hir_id, self.access_level); + if let ((ty::Visibility::Public, ..), _) + | (_, Some(AccessLevel::ReachableFromImplTrait)) + = (def_id_visibility(self.tcx(), def_id), self.access_level) + { + self.ev.update(hir_id, self.access_level); + } } false } @@ -908,7 +1028,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { } fn visit_expr(&mut self, expr: &'tcx hir::Expr) { - match expr.node { + match expr.kind { hir::ExprKind::Struct(ref qpath, ref fields, ref base) => { let res = self.tables.qpath_res(qpath, expr.hir_id); let adt = self.tables.expr_ty(expr).ty_adt_def().unwrap(); @@ -942,14 +1062,14 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { } fn visit_pat(&mut self, pat: &'tcx hir::Pat) { - match pat.node { + match pat.kind { PatKind::Struct(ref qpath, ref fields, _) => { let res = self.tables.qpath_res(qpath, pat.hir_id); let adt = self.tables.pat_ty(pat).ty_adt_def().unwrap(); let variant = adt.variant_of_res(res); for field in fields { - let use_ctxt = field.node.ident.span; - let index = self.tcx.field_index(field.node.hir_id, self.tables); + let use_ctxt = field.ident.span; + let index = self.tcx.field_index(field.hir_id, self.tables); self.check_field(use_ctxt, field.span, adt, &variant.fields[index]); } } @@ -1077,7 +1197,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { // Do not check nested expressions if the error already happened. return; } - match expr.node { + match expr.kind { hir::ExprKind::Assign(.., ref rhs) | hir::ExprKind::Match(ref rhs, ..) => { // Do not report duplicate errors for `x = y` and `match x { ... }`. if self.check_expr_pat_type(rhs.hir_id, rhs.span) { @@ -1132,7 +1252,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { hir::QPath::Resolved(_, ref path) => path.to_string(), hir::QPath::TypeRelative(_, ref segment) => segment.ident.to_string(), }; - let msg = format!("{} `{}` is private", kind.descr(), name); + let msg = format!("{} `{}` is private", kind.descr(def_id), name); self.tcx.sess.span_err(span, &msg); return; } @@ -1269,14 +1389,14 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a } fn visit_ty(&mut self, ty: &hir::Ty) { - if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = ty.node { + if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = ty.kind { if self.inner.path_is_private_type(path) { self.contains_private = true; // Found what we're looking for, so let's stop working. return } } - if let hir::TyKind::Path(_) = ty.node { + if let hir::TyKind::Path(_) = ty.kind { if self.at_outer_type { self.outer_type_is_public_path = true; } @@ -1297,7 +1417,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { } fn visit_item(&mut self, item: &'tcx hir::Item) { - match item.node { + match item.kind { // Contents of a private mod can be re-exported, so we need // to check internals. hir::ItemKind::Mod(_) => {} @@ -1369,7 +1489,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { impl_item_refs.iter() .any(|impl_item_ref| { let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); - match impl_item.node { + match impl_item.kind { hir::ImplItemKind::Const(..) | hir::ImplItemKind::Method(..) => { self.access_levels.is_reachable( @@ -1395,7 +1515,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { // don't erroneously report errors for private // types in private items. let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); - match impl_item.node { + match impl_item.kind { hir::ImplItemKind::Const(..) | hir::ImplItemKind::Method(..) if self.item_is_public(&impl_item.hir_id, &impl_item.vis) => @@ -1428,7 +1548,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { // Those in 3. are warned with this call. for impl_item_ref in impl_item_refs { let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); - if let hir::ImplItemKind::TyAlias(ref ty) = impl_item.node { + if let hir::ImplItemKind::TyAlias(ref ty) = impl_item.kind { self.visit_ty(ty); } } @@ -1508,7 +1628,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { } fn visit_ty(&mut self, t: &'tcx hir::Ty) { - if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = t.node { + if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = t.kind { if self.path_is_private_type(path) { self.old_error_set.insert(t.hir_id); } @@ -1520,7 +1640,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { v: &'tcx hir::Variant, g: &'tcx hir::Generics, item_id: hir::HirId) { - if self.access_levels.is_reachable(v.node.id) { + if self.access_levels.is_reachable(v.id) { self.in_variant = true; intravisit::walk_variant(self, v, g, item_id); self.in_variant = false; @@ -1733,7 +1853,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> let tcx = self.tcx; let item_visibility = ty::Visibility::from_hir(&item.vis, item.hir_id, tcx); - match item.node { + match item.kind { // Crates are always public. hir::ItemKind::ExternCrate(..) => {} // All nested items are checked by `visit_item`. @@ -1771,7 +1891,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> self.check(item.hir_id, item_visibility).generics().predicates(); for variant in &def.variants { - for field in variant.node.data.fields() { + for field in variant.data.fields() { self.check(field.hir_id, item_visibility).ty(); } } @@ -1865,6 +1985,7 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, krate: CrateNum) -> &AccessLevels { let mut visitor = EmbargoVisitor { tcx, access_levels: Default::default(), + macro_reachable: Default::default(), prev_level: Some(AccessLevel::Public), changed: false, }; @@ -1913,5 +2034,3 @@ fn check_private_in_public(tcx: TyCtxt<'_>, krate: CrateNum) { }; krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor)); } - -__build_diagnostic_array! { librustc_privacy, DIAGNOSTICS } diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index 548f982fe3bf0..936e72ef2c571 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -12,7 +12,6 @@ doctest = false [dependencies] bitflags = "1.0" -indexmap = "1" log = "0.4" syntax = { path = "../libsyntax" } rustc = { path = "../librustc" } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 9d01f33002940..030f9b97eb8b9 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -1,19 +1,22 @@ -//! Reduced graph building. +//! After we obtain a fresh AST fragment from a macro, code in this module helps to integrate +//! that fragment into the module structures that are already partially built. //! -//! Here we build the "reduced graph": the graph of the module tree without -//! any imports resolved. +//! Items from the fragment are placed into modules, +//! unexpanded macros in the fragment are visited and registered. +//! Imports are also considered items and placed into modules here, but not resolved yet. -use crate::macros::{InvocationData, LegacyScope}; +use crate::macros::{LegacyBinding, LegacyScope}; use crate::resolve_imports::ImportDirective; use crate::resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport}; use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding}; use crate::{ModuleOrUniformRoot, ParentScope, PerNS, Resolver, ResolverArenas, ExternPreludeEntry}; use crate::Namespace::{self, TypeNS, ValueNS, MacroNS}; -use crate::{resolve_error, resolve_struct_error, ResolutionError, Determinacy}; +use crate::{ResolutionError, Determinacy, PathResult, CrateLint}; use rustc::bug; use rustc::hir::def::{self, *}; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; +use rustc::hir::map::DefCollector; use rustc::ty; use rustc::middle::cstore::CrateStore; use rustc_metadata::cstore::LoadedMacro; @@ -28,12 +31,14 @@ use syntax::ast::{Name, Ident}; use syntax::attr; use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId}; -use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind, Variant}; -use syntax::ext::base::SyntaxExtension; +use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind}; +use syntax::ext::base::{MacroKind, SyntaxExtension}; +use syntax::ext::expand::AstFragment; use syntax::ext::hygiene::ExpnId; use syntax::feature_gate::is_builtin_attr; use syntax::parse::token::{self, Token}; -use syntax::span_err; +use syntax::{span_err, struct_span_err}; +use syntax::source_map::{respan, Spanned}; use syntax::symbol::{kw, sym}; use syntax::visit::{self, Visitor}; @@ -67,7 +72,7 @@ impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, ExpnId) { } } -pub(crate) struct IsMacroExport; +struct IsMacroExport; impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, ExpnId, IsMacroExport) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { @@ -84,7 +89,7 @@ impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, ExpnId, IsMacroExport impl<'a> Resolver<'a> { /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined; /// otherwise, reports an error. - pub fn define(&mut self, parent: Module<'a>, ident: Ident, ns: Namespace, def: T) + crate fn define(&mut self, parent: Module<'a>, ident: Ident, ns: Namespace, def: T) where T: ToNameBinding<'a>, { let binding = def.to_name_binding(self.arenas); @@ -93,17 +98,268 @@ impl<'a> Resolver<'a> { } } + crate fn get_module(&mut self, def_id: DefId) -> Module<'a> { + if def_id.krate == LOCAL_CRATE { + return self.module_map[&def_id] + } + + let macros_only = self.cstore.dep_kind_untracked(def_id.krate).macros_only(); + if let Some(&module) = self.extern_module_map.get(&(def_id, macros_only)) { + return module; + } + + let (name, parent) = if def_id.index == CRATE_DEF_INDEX { + (self.cstore.crate_name_untracked(def_id.krate).as_interned_str(), None) + } else { + let def_key = self.cstore.def_key(def_id); + (def_key.disambiguated_data.data.get_opt_name().unwrap(), + Some(self.get_module(DefId { index: def_key.parent.unwrap(), ..def_id }))) + }; + + let kind = ModuleKind::Def(DefKind::Mod, def_id, name.as_symbol()); + let module = self.arenas.alloc_module(ModuleData::new( + parent, kind, def_id, ExpnId::root(), DUMMY_SP + )); + self.extern_module_map.insert((def_id, macros_only), module); + module + } + + crate fn macro_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { + let def_id = match self.macro_defs.get(&expn_id) { + Some(def_id) => *def_id, + None => return self.ast_transform_scopes.get(&expn_id) + .unwrap_or(&self.graph_root), + }; + if let Some(id) = self.definitions.as_local_node_id(def_id) { + self.local_macro_def_scopes[&id] + } else { + let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap(); + self.get_module(module_def_id) + } + } + + crate fn get_macro(&mut self, res: Res) -> Option> { + match res { + Res::Def(DefKind::Macro(..), def_id) => self.get_macro_by_def_id(def_id), + Res::NonMacroAttr(attr_kind) => + Some(self.non_macro_attr(attr_kind == NonMacroAttrKind::Tool)), + _ => None, + } + } + + crate fn get_macro_by_def_id(&mut self, def_id: DefId) -> Option> { + if let Some(ext) = self.macro_map.get(&def_id) { + return Some(ext.clone()); + } + + let ext = Lrc::new(match self.cstore.load_macro_untracked(def_id, &self.session) { + LoadedMacro::MacroDef(item) => + self.compile_macro(&item, self.cstore.crate_edition_untracked(def_id.krate)), + LoadedMacro::ProcMacro(ext) => ext, + }); + + self.macro_map.insert(def_id, ext.clone()); + Some(ext) + } + + // FIXME: `extra_placeholders` should be included into the `fragment` as regular placeholders. + crate fn build_reduced_graph( + &mut self, + fragment: &AstFragment, + extra_placeholders: &[NodeId], + parent_scope: ParentScope<'a>, + ) -> LegacyScope<'a> { + let mut def_collector = DefCollector::new(&mut self.definitions, parent_scope.expansion); + fragment.visit_with(&mut def_collector); + for placeholder in extra_placeholders { + def_collector.visit_macro_invoc(*placeholder); + } + + let mut visitor = BuildReducedGraphVisitor { r: self, parent_scope }; + fragment.visit_with(&mut visitor); + for placeholder in extra_placeholders { + visitor.parent_scope.legacy = visitor.visit_invoc(*placeholder); + } + + visitor.parent_scope.legacy + } + + crate fn build_reduced_graph_external(&mut self, module: Module<'a>) { + let def_id = module.def_id().expect("unpopulated module without a def-id"); + for child in self.cstore.item_children_untracked(def_id, self.session) { + let child = child.map_id(|_| panic!("unexpected id")); + BuildReducedGraphVisitor { r: self, parent_scope: ParentScope::module(module) } + .build_reduced_graph_for_external_crate_res(child); + } + } +} + +struct BuildReducedGraphVisitor<'a, 'b> { + r: &'b mut Resolver<'a>, + parent_scope: ParentScope<'a>, +} + +impl<'a> AsMut> for BuildReducedGraphVisitor<'a, '_> { + fn as_mut(&mut self) -> &mut Resolver<'a> { self.r } +} + +impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { + fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility { + let parent_scope = &self.parent_scope; + match vis.node { + ast::VisibilityKind::Public => ty::Visibility::Public, + ast::VisibilityKind::Crate(..) => { + ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)) + } + ast::VisibilityKind::Inherited => { + ty::Visibility::Restricted(parent_scope.module.normal_ancestor_id) + } + ast::VisibilityKind::Restricted { ref path, id, .. } => { + // For visibilities we are not ready to provide correct implementation of "uniform + // paths" right now, so on 2018 edition we only allow module-relative paths for now. + // On 2015 edition visibilities are resolved as crate-relative by default, + // so we are prepending a root segment if necessary. + let ident = path.segments.get(0).expect("empty path in visibility").ident; + let crate_root = if ident.is_path_segment_keyword() { + None + } else if ident.span.rust_2018() { + let msg = "relative paths are not supported in visibilities on 2018 edition"; + self.r.session.struct_span_err(ident.span, msg) + .span_suggestion( + path.span, + "try", + format!("crate::{}", path), + Applicability::MaybeIncorrect, + ) + .emit(); + return ty::Visibility::Public; + } else { + let ctxt = ident.span.ctxt(); + Some(Segment::from_ident(Ident::new( + kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ctxt) + ))) + }; + + let segments = crate_root.into_iter() + .chain(path.segments.iter().map(|seg| seg.into())).collect::>(); + let expected_found_error = |this: &Self, res: Res| { + let path_str = Segment::names_to_string(&segments); + struct_span_err!(this.r.session, path.span, E0577, + "expected module, found {} `{}`", res.descr(), path_str) + .span_label(path.span, "not a module").emit(); + }; + match self.r.resolve_path( + &segments, + Some(TypeNS), + parent_scope, + true, + path.span, + CrateLint::SimplePath(id), + ) { + PathResult::Module(ModuleOrUniformRoot::Module(module)) => { + let res = module.res().expect("visibility resolved to unnamed block"); + self.r.record_partial_res(id, PartialRes::new(res)); + if module.is_normal() { + if res == Res::Err { + ty::Visibility::Public + } else { + let vis = ty::Visibility::Restricted(res.def_id()); + if self.r.is_accessible_from(vis, parent_scope.module) { + vis + } else { + let msg = + "visibilities can only be restricted to ancestor modules"; + self.r.session.span_err(path.span, msg); + ty::Visibility::Public + } + } + } else { + expected_found_error(self, res); + ty::Visibility::Public + } + } + PathResult::Module(..) => { + self.r.session.span_err(path.span, "visibility must resolve to a module"); + ty::Visibility::Public + } + PathResult::NonModule(partial_res) => { + expected_found_error(self, partial_res.base_res()); + ty::Visibility::Public + } + PathResult::Failed { span, label, suggestion, .. } => { + self.r.report_error( + span, ResolutionError::FailedToResolve { label, suggestion } + ); + ty::Visibility::Public + } + PathResult::Indeterminate => { + span_err!(self.r.session, path.span, E0578, + "cannot determine resolution for the visibility"); + ty::Visibility::Public + } + } + } + } + } + + fn insert_field_names(&mut self, def_id: DefId, field_names: Vec>) { + if !field_names.is_empty() { + self.r.field_names.insert(def_id, field_names); + } + } + fn block_needs_anonymous_module(&mut self, block: &Block) -> bool { // If any statements are items, we need to create an anonymous module - block.stmts.iter().any(|statement| match statement.node { + block.stmts.iter().any(|statement| match statement.kind { StmtKind::Item(_) | StmtKind::Mac(_) => true, _ => false, }) } - fn insert_field_names(&mut self, def_id: DefId, field_names: Vec) { - if !field_names.is_empty() { - self.field_names.insert(def_id, field_names); + // Add an import directive to the current module. + fn add_import_directive( + &mut self, + module_path: Vec, + subclass: ImportDirectiveSubclass<'a>, + span: Span, + id: NodeId, + item: &ast::Item, + root_span: Span, + root_id: NodeId, + vis: ty::Visibility, + ) { + let current_module = self.parent_scope.module; + let directive = self.r.arenas.alloc_import_directive(ImportDirective { + parent_scope: self.parent_scope, + module_path, + imported_module: Cell::new(None), + subclass, + span, + id, + use_span: item.span, + use_span_with_attributes: item.span_with_attributes(), + has_attributes: !item.attrs.is_empty(), + root_span, + root_id, + vis: Cell::new(vis), + used: Cell::new(false), + }); + + debug!("add_import_directive({:?})", directive); + + self.r.indeterminate_imports.push(directive); + match directive.subclass { + SingleImport { target, type_ns_only, .. } => { + self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { + let mut resolution = this.resolution(current_module, target, ns).borrow_mut(); + resolution.add_single_import(directive); + }); + } + // We don't add prelude imports to the globs since they only affect lexical scopes, + // which are not relevant to import resolution. + GlobImport { is_prelude: true, .. } => {} + GlobImport { .. } => current_module.globs.borrow_mut().push(directive), + _ => unreachable!(), } } @@ -115,7 +371,6 @@ impl<'a> Resolver<'a> { parent_prefix: &[Segment], nested: bool, // The whole `use` item - parent_scope: ParentScope<'a>, item: &Item, vis: ty::Visibility, root_span: Span, @@ -163,8 +418,7 @@ impl<'a> Resolver<'a> { type_ns_only = true; if empty_for_self(&module_path) { - resolve_error( - self, + self.r.report_error( use_tree.span, ResolutionError:: SelfImportOnlyInImportListWithNonEmptyPrefix @@ -181,14 +435,14 @@ impl<'a> Resolver<'a> { } else { // Disallow `self` if source.ident.name == kw::SelfLower { - resolve_error(self, - use_tree.span, - ResolutionError::SelfImportsOnlyAllowedWithin); + self.r.report_error( + use_tree.span, ResolutionError::SelfImportsOnlyAllowedWithin + ); } // Disallow `use $crate;` if source.ident.name == kw::DollarCrate && module_path.is_empty() { - let crate_root = self.resolve_crate_root(source.ident); + let crate_root = self.r.resolve_crate_root(source.ident); let crate_name = match crate_root.kind { ModuleKind::Def(.., name) => name, ModuleKind::Block(..) => unreachable!(), @@ -203,7 +457,7 @@ impl<'a> Resolver<'a> { name: kw::PathRoot, span: source.ident.span, }, - id: Some(self.session.next_node_id()), + id: Some(self.r.session.next_node_id()), }); source.ident.name = crate_name; } @@ -211,7 +465,7 @@ impl<'a> Resolver<'a> { ident.name = crate_name; } - self.session.struct_span_warn(item.span, "`$crate` may not be imported") + self.r.session.struct_span_warn(item.span, "`$crate` may not be imported") .note("`use $crate;` was erroneously allowed and \ will become a hard error in a future release") .emit(); @@ -219,7 +473,7 @@ impl<'a> Resolver<'a> { } if ident.name == kw::Crate { - self.session.span_err(ident.span, + self.r.session.span_err(ident.span, "crate root imports need to be explicitly named: \ `use crate as name;`"); } @@ -249,7 +503,6 @@ impl<'a> Resolver<'a> { root_span, item.id, vis, - parent_scope, ); } ast::UseTreeKind::Glob => { @@ -266,7 +519,6 @@ impl<'a> Resolver<'a> { root_span, item.id, vis, - parent_scope, ); } ast::UseTreeKind::Nested(ref items) => { @@ -281,7 +533,7 @@ impl<'a> Resolver<'a> { None }).collect::>(); if self_spans.len() > 1 { - let mut e = resolve_struct_error(self, + let mut e = self.r.into_struct_error( self_spans[0], ResolutionError::SelfImportCanOnlyAppearOnceInTheList); @@ -297,7 +549,7 @@ impl<'a> Resolver<'a> { // This particular use tree tree, id, &prefix, true, // The whole `use` item - parent_scope.clone(), item, vis, root_span, + item, vis, root_span, ); } @@ -321,7 +573,7 @@ impl<'a> Resolver<'a> { // This particular use tree &tree, id, &prefix, true, // The whole `use` item - parent_scope, item, ty::Visibility::Invisible, root_span, + item, ty::Visibility::Invisible, root_span, ); } } @@ -329,26 +581,27 @@ impl<'a> Resolver<'a> { } /// Constructs the reduced graph for one item. - fn build_reduced_graph_for_item(&mut self, item: &Item, parent_scope: ParentScope<'a>) { + fn build_reduced_graph_for_item(&mut self, item: &'b Item) { + let parent_scope = &self.parent_scope; let parent = parent_scope.module; let expansion = parent_scope.expansion; let ident = item.ident.gensym_if_underscore(); let sp = item.span; let vis = self.resolve_visibility(&item.vis); - match item.node { + match item.kind { ItemKind::Use(ref use_tree) => { self.build_reduced_graph_for_use_tree( // This particular use tree use_tree, item.id, &[], false, // The whole `use` item - parent_scope, item, vis, use_tree.span, + item, vis, use_tree.span, ); } ItemKind::ExternCrate(orig_name) => { let module = if orig_name.is_none() && ident.name == kw::SelfLower { - self.session + self.r.session .struct_span_err(item.span, "`extern crate self;` requires renaming") .span_suggestion( item.span, @@ -359,26 +612,21 @@ impl<'a> Resolver<'a> { .emit(); return; } else if orig_name == Some(kw::SelfLower) { - self.graph_root + self.r.graph_root } else { - let crate_id = self.crate_loader.process_extern_crate(item, &self.definitions); - self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }) + let crate_id = self.r.crate_loader.process_extern_crate( + item, &self.r.definitions + ); + self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }) }; - self.populate_module_if_necessary(module); - if let Some(name) = self.session.parse_sess.injected_crate_name.try_get() { - if name.as_str() == ident.name.as_str() { - self.injected_crate = Some(module); - } - } - - let used = self.process_legacy_macro_imports(item, module, &parent_scope); + let used = self.process_legacy_macro_imports(item, module); let binding = - (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.arenas); - let directive = self.arenas.alloc_import_directive(ImportDirective { + (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas); + let directive = self.r.arenas.alloc_import_directive(ImportDirective { root_id: item.id, id: item.id, - parent_scope, + parent_scope: self.parent_scope, imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), subclass: ImportDirectiveSubclass::ExternCrate { source: orig_name, @@ -393,18 +641,18 @@ impl<'a> Resolver<'a> { vis: Cell::new(vis), used: Cell::new(used), }); - self.potentially_unused_imports.push(directive); - let imported_binding = self.import(binding, directive); - if ptr::eq(self.current_module, self.graph_root) { - if let Some(entry) = self.extern_prelude.get(&ident.modern()) { + self.r.potentially_unused_imports.push(directive); + let imported_binding = self.r.import(binding, directive); + if ptr::eq(parent, self.r.graph_root) { + if let Some(entry) = self.r.extern_prelude.get(&ident.modern()) { if expansion != ExpnId::root() && orig_name.is_some() && entry.extern_crate_item.is_none() { - self.session.span_err(item.span, "macro-expanded `extern crate` items \ - cannot shadow names passed with \ - `--extern`"); + let msg = "macro-expanded `extern crate` items cannot \ + shadow names passed with `--extern`"; + self.r.session.span_err(item.span, msg); } } - let entry = self.extern_prelude.entry(ident.modern()) + let entry = self.r.extern_prelude.entry(ident.modern()) .or_insert(ExternPreludeEntry { extern_crate_item: None, introduced_by_item: true, @@ -414,7 +662,7 @@ impl<'a> Resolver<'a> { entry.introduced_by_item = true; } } - self.define(parent, ident, TypeNS, imported_binding); + self.r.define(parent, ident, TypeNS, imported_binding); } ItemKind::GlobalAsm(..) => {} @@ -422,19 +670,19 @@ impl<'a> Resolver<'a> { ItemKind::Mod(..) if ident.name == kw::Invalid => {} // Crate root ItemKind::Mod(..) => { - let def_id = self.definitions.local_def_id(item.id); + let def_id = self.r.definitions.local_def_id(item.id); let module_kind = ModuleKind::Def(DefKind::Mod, def_id, ident.name); - let module = self.arenas.alloc_module(ModuleData { + let module = self.r.arenas.alloc_module(ModuleData { no_implicit_prelude: parent.no_implicit_prelude || { attr::contains_name(&item.attrs, sym::no_implicit_prelude) }, ..ModuleData::new(Some(parent), module_kind, def_id, expansion, item.span) }); - self.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - self.module_map.insert(def_id, module); + self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); + self.r.module_map.insert(def_id, module); // Descend into the module. - self.current_module = module; + self.parent_scope.module = module; } // Handled in `rustc_metadata::{native_libs,link_args}` @@ -442,62 +690,57 @@ impl<'a> Resolver<'a> { // These items live in the value namespace. ItemKind::Static(..) => { - let res = Res::Def(DefKind::Static, self.definitions.local_def_id(item.id)); - self.define(parent, ident, ValueNS, (res, vis, sp, expansion)); + let res = Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id)); + self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); } ItemKind::Const(..) => { - let res = Res::Def(DefKind::Const, self.definitions.local_def_id(item.id)); - self.define(parent, ident, ValueNS, (res, vis, sp, expansion)); + let res = Res::Def(DefKind::Const, self.r.definitions.local_def_id(item.id)); + self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); } ItemKind::Fn(..) => { - let res = Res::Def(DefKind::Fn, self.definitions.local_def_id(item.id)); - self.define(parent, ident, ValueNS, (res, vis, sp, expansion)); + let res = Res::Def(DefKind::Fn, self.r.definitions.local_def_id(item.id)); + self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); // Functions introducing procedural macros reserve a slot // in the macro namespace as well (see #52225). - self.define_macro(item, expansion, &mut LegacyScope::Empty); + self.define_macro(item); } // These items live in the type namespace. ItemKind::TyAlias(..) => { - let res = Res::Def(DefKind::TyAlias, self.definitions.local_def_id(item.id)); - self.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + let res = Res::Def(DefKind::TyAlias, self.r.definitions.local_def_id(item.id)); + self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); } ItemKind::OpaqueTy(_, _) => { - let res = Res::Def(DefKind::OpaqueTy, self.definitions.local_def_id(item.id)); - self.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + let res = Res::Def(DefKind::OpaqueTy, self.r.definitions.local_def_id(item.id)); + self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); } - ItemKind::Enum(ref enum_definition, _) => { - let module_kind = ModuleKind::Def( - DefKind::Enum, - self.definitions.local_def_id(item.id), - ident.name, - ); - let module = self.new_module(parent, + ItemKind::Enum(_, _) => { + let def_id = self.r.definitions.local_def_id(item.id); + self.r.variant_vis.insert(def_id, vis); + let module_kind = ModuleKind::Def(DefKind::Enum, def_id, ident.name); + let module = self.r.new_module(parent, module_kind, parent.normal_ancestor_id, expansion, item.span); - self.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - - for variant in &(*enum_definition).variants { - self.build_reduced_graph_for_variant(variant, module, vis, expansion); - } + self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); + self.parent_scope.module = module; } ItemKind::TraitAlias(..) => { - let res = Res::Def(DefKind::TraitAlias, self.definitions.local_def_id(item.id)); - self.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + let res = Res::Def(DefKind::TraitAlias, self.r.definitions.local_def_id(item.id)); + self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); } // These items live in both the type and value namespaces. ItemKind::Struct(ref struct_def, _) => { // Define a name in the type namespace. - let def_id = self.definitions.local_def_id(item.id); + let def_id = self.r.definitions.local_def_id(item.id); let res = Res::Def(DefKind::Struct, def_id); - self.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); let mut ctor_vis = vis; @@ -510,14 +753,14 @@ impl<'a> Resolver<'a> { } // Record field names for error reporting. - let field_names = struct_def.fields().iter().filter_map(|field| { + let field_names = struct_def.fields().iter().map(|field| { let field_vis = self.resolve_visibility(&field.vis); - if ctor_vis.is_at_least(field_vis, &*self) { + if ctor_vis.is_at_least(field_vis, &*self.r) { ctor_vis = field_vis; } - field.ident.map(|ident| ident.name) + respan(field.span, field.ident.map_or(kw::Invalid, |ident| ident.name)) }).collect(); - let item_def_id = self.definitions.local_def_id(item.id); + let item_def_id = self.r.definitions.local_def_id(item.id); self.insert_field_names(item_def_id, field_names); // If this is a tuple or unit struct, define a name @@ -525,306 +768,185 @@ impl<'a> Resolver<'a> { if let Some(ctor_node_id) = struct_def.ctor_id() { let ctor_res = Res::Def( DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(struct_def)), - self.definitions.local_def_id(ctor_node_id), + self.r.definitions.local_def_id(ctor_node_id), ); - self.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion)); - self.struct_constructors.insert(res.def_id(), (ctor_res, ctor_vis)); + self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion)); + self.r.struct_constructors.insert(res.def_id(), (ctor_res, ctor_vis)); } } ItemKind::Union(ref vdata, _) => { - let res = Res::Def(DefKind::Union, self.definitions.local_def_id(item.id)); - self.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + let res = Res::Def(DefKind::Union, self.r.definitions.local_def_id(item.id)); + self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); // Record field names for error reporting. - let field_names = vdata.fields().iter().filter_map(|field| { + let field_names = vdata.fields().iter().map(|field| { self.resolve_visibility(&field.vis); - field.ident.map(|ident| ident.name) + respan(field.span, field.ident.map_or(kw::Invalid, |ident| ident.name)) }).collect(); - let item_def_id = self.definitions.local_def_id(item.id); + let item_def_id = self.r.definitions.local_def_id(item.id); self.insert_field_names(item_def_id, field_names); } - ItemKind::Impl(..) => {} + ItemKind::Impl(.., ref impl_items) => { + for impl_item in impl_items { + self.resolve_visibility(&impl_item.vis); + } + } ItemKind::Trait(..) => { - let def_id = self.definitions.local_def_id(item.id); + let def_id = self.r.definitions.local_def_id(item.id); // Add all the items within to a new module. let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name); - let module = self.new_module(parent, + let module = self.r.new_module(parent, module_kind, parent.normal_ancestor_id, expansion, item.span); - self.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - self.current_module = module; + self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); + self.parent_scope.module = module; } ItemKind::MacroDef(..) | ItemKind::Mac(_) => unreachable!(), } } - // Constructs the reduced graph for one variant. Variants exist in the - // type and value namespaces. - fn build_reduced_graph_for_variant(&mut self, - variant: &Variant, - parent: Module<'a>, - vis: ty::Visibility, - expn_id: ExpnId) { - let ident = variant.node.ident; - - // Define a name in the type namespace. - let def_id = self.definitions.local_def_id(variant.node.id); - let res = Res::Def(DefKind::Variant, def_id); - self.define(parent, ident, TypeNS, (res, vis, variant.span, expn_id)); - - // If the variant is marked as non_exhaustive then lower the visibility to within the - // crate. - let mut ctor_vis = vis; - let has_non_exhaustive = attr::contains_name(&variant.node.attrs, sym::non_exhaustive); - if has_non_exhaustive && vis == ty::Visibility::Public { - ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)); - } - - // Define a constructor name in the value namespace. - // Braced variants, unlike structs, generate unusable names in - // value namespace, they are reserved for possible future use. - // It's ok to use the variant's id as a ctor id since an - // error will be reported on any use of such resolution anyway. - let ctor_node_id = variant.node.data.ctor_id().unwrap_or(variant.node.id); - let ctor_def_id = self.definitions.local_def_id(ctor_node_id); - let ctor_kind = CtorKind::from_ast(&variant.node.data); - let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id); - self.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id)); - } - /// Constructs the reduced graph for one foreign item. - fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem, expn_id: ExpnId) { - let (res, ns) = match item.node { + fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem) { + let (res, ns) = match item.kind { ForeignItemKind::Fn(..) => { - (Res::Def(DefKind::Fn, self.definitions.local_def_id(item.id)), ValueNS) + (Res::Def(DefKind::Fn, self.r.definitions.local_def_id(item.id)), ValueNS) } ForeignItemKind::Static(..) => { - (Res::Def(DefKind::Static, self.definitions.local_def_id(item.id)), ValueNS) + (Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id)), ValueNS) } ForeignItemKind::Ty => { - (Res::Def(DefKind::ForeignTy, self.definitions.local_def_id(item.id)), TypeNS) + (Res::Def(DefKind::ForeignTy, self.r.definitions.local_def_id(item.id)), TypeNS) } ForeignItemKind::Macro(_) => unreachable!(), }; - let parent = self.current_module; + let parent = self.parent_scope.module; + let expansion = self.parent_scope.expansion; let vis = self.resolve_visibility(&item.vis); - self.define(parent, item.ident, ns, (res, vis, item.span, expn_id)); + self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion)); } - fn build_reduced_graph_for_block(&mut self, block: &Block, expn_id: ExpnId) { - let parent = self.current_module; + fn build_reduced_graph_for_block(&mut self, block: &Block) { + let parent = self.parent_scope.module; + let expansion = self.parent_scope.expansion; if self.block_needs_anonymous_module(block) { - let module = self.new_module(parent, + let module = self.r.new_module(parent, ModuleKind::Block(block.id), parent.normal_ancestor_id, - expn_id, + expansion, block.span); - self.block_map.insert(block.id, module); - self.current_module = module; // Descend into the block. + self.r.block_map.insert(block.id, module); + self.parent_scope.module = module; // Descend into the block. } } /// Builds the reduced graph for a single item in an external crate. - fn build_reduced_graph_for_external_crate_res( - &mut self, - parent: Module<'a>, - child: Export, - ) { + fn build_reduced_graph_for_external_crate_res(&mut self, child: Export) { + let parent = self.parent_scope.module; let Export { ident, res, vis, span } = child; // FIXME: We shouldn't create the gensym here, it should come from metadata, // but metadata cannot encode gensyms currently, so we create it here. // This is only a guess, two equivalent idents may incorrectly get different gensyms here. let ident = ident.gensym_if_underscore(); let expansion = ExpnId::root(); // FIXME(jseyfried) intercrate hygiene + // Record primary definitions. match res { Res::Def(kind @ DefKind::Mod, def_id) - | Res::Def(kind @ DefKind::Enum, def_id) => { - let module = self.new_module(parent, + | Res::Def(kind @ DefKind::Enum, def_id) + | Res::Def(kind @ DefKind::Trait, def_id) => { + let module = self.r.new_module(parent, ModuleKind::Def(kind, def_id, ident.name), def_id, expansion, span); - self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion)); + self.r.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion)); } - Res::Def(DefKind::Variant, _) + Res::Def(DefKind::Struct, _) + | Res::Def(DefKind::Union, _) + | Res::Def(DefKind::Variant, _) | Res::Def(DefKind::TyAlias, _) | Res::Def(DefKind::ForeignTy, _) | Res::Def(DefKind::OpaqueTy, _) | Res::Def(DefKind::TraitAlias, _) + | Res::Def(DefKind::AssocTy, _) + | Res::Def(DefKind::AssocOpaqueTy, _) | Res::PrimTy(..) - | Res::ToolMod => { - self.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion)); - } + | Res::ToolMod => + self.r.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion)), Res::Def(DefKind::Fn, _) + | Res::Def(DefKind::Method, _) | Res::Def(DefKind::Static, _) | Res::Def(DefKind::Const, _) - | Res::Def(DefKind::Ctor(CtorOf::Variant, ..), _) => { - self.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion)); + | Res::Def(DefKind::AssocConst, _) + | Res::Def(DefKind::Ctor(..), _) => + self.r.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion)), + Res::Def(DefKind::Macro(..), _) + | Res::NonMacroAttr(..) => + self.r.define(parent, ident, MacroNS, (res, vis, DUMMY_SP, expansion)), + Res::Def(DefKind::TyParam, _) | Res::Def(DefKind::ConstParam, _) + | Res::Local(..) | Res::SelfTy(..) | Res::SelfCtor(..) | Res::Err => + bug!("unexpected resolution: {:?}", res) + } + // Record some extra data for better diagnostics. + match res { + Res::Def(DefKind::Struct, def_id) | Res::Def(DefKind::Union, def_id) => { + let field_names = + self.r.cstore.struct_field_names_untracked(def_id, self.r.session); + self.insert_field_names(def_id, field_names); } - Res::Def(DefKind::Ctor(CtorOf::Struct, ..), def_id) => { - self.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion)); - - if let Some(struct_def_id) = - self.cstore.def_key(def_id).parent - .map(|index| DefId { krate: def_id.krate, index: index }) { - self.struct_constructors.insert(struct_def_id, (res, vis)); + Res::Def(DefKind::Method, def_id) => { + if self.r.cstore.associated_item_cloned_untracked(def_id).method_has_self_argument { + self.r.has_self.insert(def_id); } } - Res::Def(DefKind::Trait, def_id) => { - let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name); - let module = self.new_module(parent, - module_kind, - parent.normal_ancestor_id, - expansion, - span); - self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion)); - - for child in self.cstore.item_children_untracked(def_id, self.session) { - let res = child.res.map_id(|_| panic!("unexpected id")); - let ns = if let Res::Def(DefKind::AssocTy, _) = res { - TypeNS - } else { ValueNS }; - self.define(module, child.ident, ns, - (res, ty::Visibility::Public, DUMMY_SP, expansion)); - - if self.cstore.associated_item_cloned_untracked(child.res.def_id()) - .method_has_self_argument { - self.has_self.insert(res.def_id()); - } + Res::Def(DefKind::Ctor(CtorOf::Struct, ..), def_id) => { + let parent = self.r.cstore.def_key(def_id).parent; + if let Some(struct_def_id) = parent.map(|index| DefId { index, ..def_id }) { + self.r.struct_constructors.insert(struct_def_id, (res, vis)); } - module.populated.set(true); - } - Res::Def(DefKind::Struct, def_id) | Res::Def(DefKind::Union, def_id) => { - self.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion)); - - // Record field names for error reporting. - let field_names = self.cstore.struct_field_names_untracked(def_id); - self.insert_field_names(def_id, field_names); - } - Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => { - self.define(parent, ident, MacroNS, (res, vis, DUMMY_SP, expansion)); } - _ => bug!("unexpected resolution: {:?}", res) - } - } - - pub fn get_module(&mut self, def_id: DefId) -> Module<'a> { - if def_id.krate == LOCAL_CRATE { - return self.module_map[&def_id] - } - - let macros_only = self.cstore.dep_kind_untracked(def_id.krate).macros_only(); - if let Some(&module) = self.extern_module_map.get(&(def_id, macros_only)) { - return module; - } - - let (name, parent) = if def_id.index == CRATE_DEF_INDEX { - (self.cstore.crate_name_untracked(def_id.krate).as_interned_str(), None) - } else { - let def_key = self.cstore.def_key(def_id); - (def_key.disambiguated_data.data.get_opt_name().unwrap(), - Some(self.get_module(DefId { index: def_key.parent.unwrap(), ..def_id }))) - }; - - let kind = ModuleKind::Def(DefKind::Mod, def_id, name.as_symbol()); - let module = self.arenas.alloc_module(ModuleData::new( - parent, kind, def_id, ExpnId::root(), DUMMY_SP - )); - self.extern_module_map.insert((def_id, macros_only), module); - module - } - - pub fn macro_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { - let def_id = match self.macro_defs.get(&expn_id) { - Some(def_id) => *def_id, - None => return self.graph_root, - }; - if let Some(id) = self.definitions.as_local_node_id(def_id) { - self.local_macro_def_scopes[&id] - } else if self.is_builtin_macro(Some(def_id)) { - self.injected_crate.unwrap_or(self.graph_root) - } else { - let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap(); - self.get_module(module_def_id) - } - } - - crate fn get_macro(&mut self, res: Res) -> Option> { - match res { - Res::Def(DefKind::Macro(..), def_id) => self.get_macro_by_def_id(def_id), - Res::NonMacroAttr(attr_kind) => - Some(self.non_macro_attr(attr_kind == NonMacroAttrKind::Tool)), - _ => None, - } - } - - crate fn get_macro_by_def_id(&mut self, def_id: DefId) -> Option> { - if let Some(ext) = self.macro_map.get(&def_id) { - return Some(ext.clone()); - } - - let macro_def = match self.cstore.load_macro_untracked(def_id, &self.session) { - LoadedMacro::MacroDef(macro_def) => macro_def, - LoadedMacro::ProcMacro(ext) => return Some(ext), - }; - - let ext = self.compile_macro(¯o_def, self.cstore.crate_edition_untracked(def_id.krate)); - self.macro_map.insert(def_id, ext.clone()); - Some(ext) - } - - /// Ensures that the reduced graph rooted at the given external module - /// is built, building it if it is not. - pub fn populate_module_if_necessary(&mut self, module: Module<'a>) { - if module.populated.get() { return } - let def_id = module.def_id().unwrap(); - for child in self.cstore.item_children_untracked(def_id, self.session) { - let child = child.map_id(|_| panic!("unexpected id")); - self.build_reduced_graph_for_external_crate_res(module, child); + _ => {} } - module.populated.set(true) } fn legacy_import_macro(&mut self, - name: Name, + name: ast::Name, binding: &'a NameBinding<'a>, span: Span, allow_shadowing: bool) { - if self.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing { + if self.r.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing { let msg = format!("`{}` is already in scope", name); let note = "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)"; - self.session.struct_span_err(span, &msg).note(note).emit(); + self.r.session.struct_span_err(span, &msg).note(note).emit(); } } /// Returns `true` if we should consider the underlying `extern crate` to be used. - fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>, - parent_scope: &ParentScope<'a>) -> bool { + fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>) -> bool { let mut import_all = None; let mut single_imports = Vec::new(); for attr in &item.attrs { if attr.check_name(sym::macro_use) { - if self.current_module.parent.is_some() { - span_err!(self.session, item.span, E0468, + if self.parent_scope.module.parent.is_some() { + span_err!(self.r.session, item.span, E0468, "an `extern crate` loading macros must be at the crate root"); } - if let ItemKind::ExternCrate(Some(orig_name)) = item.node { + if let ItemKind::ExternCrate(Some(orig_name)) = item.kind { if orig_name == kw::SelfLower { - self.session.span_err(attr.span, + self.r.session.span_err(attr.span, "`macro_use` is not supported on `extern crate self`"); } } - let ill_formed = |span| span_err!(self.session, span, E0466, "bad macro import"); + let ill_formed = |span| span_err!(self.r.session, span, E0466, "bad macro import"); match attr.meta() { - Some(meta) => match meta.node { + Some(meta) => match meta.kind { MetaItemKind::Word => { import_all = Some(meta.span); break; @@ -842,11 +964,11 @@ impl<'a> Resolver<'a> { } } - let arenas = self.arenas; - let macro_use_directive = |span| arenas.alloc_import_directive(ImportDirective { + let macro_use_directive = + |this: &Self, span| this.r.arenas.alloc_import_directive(ImportDirective { root_id: item.id, id: item.id, - parent_scope: parent_scope.clone(), + parent_scope: this.parent_scope, imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), subclass: ImportDirectiveSubclass::MacroUse, use_span_with_attributes: item.span_with_attributes(), @@ -859,32 +981,32 @@ impl<'a> Resolver<'a> { used: Cell::new(false), }); - let allow_shadowing = parent_scope.expansion == ExpnId::root(); + let allow_shadowing = self.parent_scope.expansion == ExpnId::root(); if let Some(span) = import_all { - let directive = macro_use_directive(span); - self.potentially_unused_imports.push(directive); - module.for_each_child(|ident, ns, binding| if ns == MacroNS { - let imported_binding = self.import(binding, directive); - self.legacy_import_macro(ident.name, imported_binding, span, allow_shadowing); + let directive = macro_use_directive(self, span); + self.r.potentially_unused_imports.push(directive); + module.for_each_child(self, |this, ident, ns, binding| if ns == MacroNS { + let imported_binding = this.r.import(binding, directive); + this.legacy_import_macro(ident.name, imported_binding, span, allow_shadowing); }); } else { for ident in single_imports.iter().cloned() { - let result = self.resolve_ident_in_module( + let result = self.r.resolve_ident_in_module( ModuleOrUniformRoot::Module(module), ident, MacroNS, - None, + &self.parent_scope, false, ident.span, ); if let Ok(binding) = result { - let directive = macro_use_directive(ident.span); - self.potentially_unused_imports.push(directive); - let imported_binding = self.import(binding, directive); + let directive = macro_use_directive(self, ident.span); + self.r.potentially_unused_imports.push(directive); + let imported_binding = self.r.import(binding, directive); self.legacy_import_macro(ident.name, imported_binding, ident.span, allow_shadowing); } else { - span_err!(self.session, ident.span, E0469, "imported macro not found"); + span_err!(self.r.session, ident.span, E0469, "imported macro not found"); } } } @@ -896,7 +1018,7 @@ impl<'a> Resolver<'a> { for attr in attrs { if attr.check_name(sym::macro_escape) { let msg = "macro_escape is a deprecated synonym for macro_use"; - let mut err = self.session.struct_span_warn(attr.span, msg); + let mut err = self.r.session.struct_span_warn(attr.span, msg); if let ast::AttrStyle::Inner = attr.style { err.help("consider an outer attribute, `#[macro_use]` mod ...").emit(); } else { @@ -907,43 +1029,102 @@ impl<'a> Resolver<'a> { } if !attr.is_word() { - self.session.span_err(attr.span, "arguments to macro_use are not allowed here"); + self.r.session.span_err(attr.span, "arguments to macro_use are not allowed here"); } return true; } false } -} -pub struct BuildReducedGraphVisitor<'a, 'b> { - pub resolver: &'a mut Resolver<'b>, - pub current_legacy_scope: LegacyScope<'b>, - pub expansion: ExpnId, -} - -impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { - fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> { + fn visit_invoc(&mut self, id: NodeId) -> LegacyScope<'a> { let invoc_id = id.placeholder_to_expn_id(); - self.resolver.current_module.unresolved_invocations.borrow_mut().insert(invoc_id); + self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id); - let invocation_data = self.resolver.arenas.alloc_invocation_data(InvocationData { - module: self.resolver.current_module, - parent_legacy_scope: self.current_legacy_scope, - output_legacy_scope: Cell::new(None), - }); - let old_invocation_data = self.resolver.invocations.insert(invoc_id, invocation_data); - assert!(old_invocation_data.is_none(), "invocation data is reset for an invocation"); + let old_parent_scope = self.r.invocation_parent_scopes.insert(invoc_id, self.parent_scope); + assert!(old_parent_scope.is_none(), "invocation data is reset for an invocation"); + + LegacyScope::Invocation(invoc_id) + } - invocation_data + fn proc_macro_stub(item: &ast::Item) -> Option<(MacroKind, Ident, Span)> { + if attr::contains_name(&item.attrs, sym::proc_macro) { + return Some((MacroKind::Bang, item.ident, item.span)); + } else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) { + return Some((MacroKind::Attr, item.ident, item.span)); + } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { + if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { + if let Some(ident) = nested_meta.ident() { + return Some((MacroKind::Derive, ident, ident.span)); + } + } + } + None + } + + fn define_macro(&mut self, item: &ast::Item) -> LegacyScope<'a> { + let parent_scope = &self.parent_scope; + let expansion = parent_scope.expansion; + let (ext, ident, span, is_legacy) = match &item.kind { + ItemKind::MacroDef(def) => { + let ext = Lrc::new(self.r.compile_macro(item, self.r.session.edition())); + (ext, item.ident, item.span, def.legacy) + } + ItemKind::Fn(..) => match Self::proc_macro_stub(item) { + Some((macro_kind, ident, span)) => { + self.r.proc_macro_stubs.insert(item.id); + (self.r.dummy_ext(macro_kind), ident, span, false) + } + None => return parent_scope.legacy, + } + _ => unreachable!(), + }; + + let def_id = self.r.definitions.local_def_id(item.id); + let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id); + self.r.macro_map.insert(def_id, ext); + self.r.local_macro_def_scopes.insert(item.id, parent_scope.module); + + if is_legacy { + let ident = ident.modern(); + self.r.macro_names.insert(ident); + let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export); + let vis = if is_macro_export { + ty::Visibility::Public + } else { + ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)) + }; + let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas); + self.r.set_binding_parent_module(binding, parent_scope.module); + self.r.all_macros.insert(ident.name, res); + if is_macro_export { + let module = self.r.graph_root; + self.r.define(module, ident, MacroNS, + (res, vis, span, expansion, IsMacroExport)); + } else { + self.r.check_reserved_macro_name(ident, res); + self.r.unused_macros.insert(item.id, span); + } + LegacyScope::Binding(self.r.arenas.alloc_legacy_binding(LegacyBinding { + parent_legacy_scope: parent_scope.legacy, binding, ident + })) + } else { + let module = parent_scope.module; + let vis = self.resolve_visibility(&item.vis); + if vis != ty::Visibility::Public { + self.r.unused_macros.insert(item.id, span); + } + self.r.define(module, ident, MacroNS, (res, vis, span, expansion)); + self.parent_scope.legacy + } } } macro_rules! method { ($visit:ident: $ty:ty, $invoc:path, $walk:ident) => { - fn $visit(&mut self, node: &'a $ty) { - if let $invoc(..) = node.node { + fn $visit(&mut self, node: &'b $ty) { + if let $invoc(..) = node.kind { self.visit_invoc(node.id); } else { visit::$walk(self, node); @@ -952,84 +1133,77 @@ macro_rules! method { } } -impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { +impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item); method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr); method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat); method!(visit_ty: ast::Ty, ast::TyKind::Mac, walk_ty); - fn visit_item(&mut self, item: &'a Item) { - let macro_use = match item.node { + fn visit_item(&mut self, item: &'b Item) { + let macro_use = match item.kind { ItemKind::MacroDef(..) => { - self.resolver.define_macro(item, self.expansion, &mut self.current_legacy_scope); + self.parent_scope.legacy = self.define_macro(item); return } ItemKind::Mac(..) => { - self.current_legacy_scope = LegacyScope::Invocation(self.visit_invoc(item.id)); + self.parent_scope.legacy = self.visit_invoc(item.id); return } - ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs), + ItemKind::Mod(..) => self.contains_macro_use(&item.attrs), _ => false, }; - - let orig_current_module = self.resolver.current_module; - let orig_current_legacy_scope = self.current_legacy_scope; - let parent_scope = ParentScope { - module: self.resolver.current_module, - expansion: self.expansion, - legacy: self.current_legacy_scope, - derives: Vec::new(), - }; - self.resolver.build_reduced_graph_for_item(item, parent_scope); + let orig_current_module = self.parent_scope.module; + let orig_current_legacy_scope = self.parent_scope.legacy; + self.build_reduced_graph_for_item(item); visit::walk_item(self, item); - self.resolver.current_module = orig_current_module; + self.parent_scope.module = orig_current_module; if !macro_use { - self.current_legacy_scope = orig_current_legacy_scope; + self.parent_scope.legacy = orig_current_legacy_scope; } } - fn visit_stmt(&mut self, stmt: &'a ast::Stmt) { - if let ast::StmtKind::Mac(..) = stmt.node { - self.current_legacy_scope = LegacyScope::Invocation(self.visit_invoc(stmt.id)); + fn visit_stmt(&mut self, stmt: &'b ast::Stmt) { + if let ast::StmtKind::Mac(..) = stmt.kind { + self.parent_scope.legacy = self.visit_invoc(stmt.id); } else { visit::walk_stmt(self, stmt); } } - fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) { - if let ForeignItemKind::Macro(_) = foreign_item.node { + fn visit_foreign_item(&mut self, foreign_item: &'b ForeignItem) { + if let ForeignItemKind::Macro(_) = foreign_item.kind { self.visit_invoc(foreign_item.id); return; } - self.resolver.build_reduced_graph_for_foreign_item(foreign_item, self.expansion); + self.build_reduced_graph_for_foreign_item(foreign_item); visit::walk_foreign_item(self, foreign_item); } - fn visit_block(&mut self, block: &'a Block) { - let orig_current_module = self.resolver.current_module; - let orig_current_legacy_scope = self.current_legacy_scope; - self.resolver.build_reduced_graph_for_block(block, self.expansion); + fn visit_block(&mut self, block: &'b Block) { + let orig_current_module = self.parent_scope.module; + let orig_current_legacy_scope = self.parent_scope.legacy; + self.build_reduced_graph_for_block(block); visit::walk_block(self, block); - self.resolver.current_module = orig_current_module; - self.current_legacy_scope = orig_current_legacy_scope; + self.parent_scope.module = orig_current_module; + self.parent_scope.legacy = orig_current_legacy_scope; } - fn visit_trait_item(&mut self, item: &'a TraitItem) { - let parent = self.resolver.current_module; + fn visit_trait_item(&mut self, item: &'b TraitItem) { + let parent = self.parent_scope.module; - if let TraitItemKind::Macro(_) = item.node { + if let TraitItemKind::Macro(_) = item.kind { self.visit_invoc(item.id); return } // Add the item to the trait info. - let item_def_id = self.resolver.definitions.local_def_id(item.id); - let (res, ns) = match item.node { + let item_def_id = self.r.definitions.local_def_id(item.id); + let (res, ns) = match item.kind { TraitItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS), TraitItemKind::Method(ref sig, _) => { if sig.decl.has_self() { - self.resolver.has_self.insert(item_def_id); + self.r.has_self.insert(item_def_id); } (Res::Def(DefKind::Method, item_def_id), ValueNS) } @@ -1038,36 +1212,114 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { }; let vis = ty::Visibility::Public; - self.resolver.define(parent, item.ident, ns, (res, vis, item.span, self.expansion)); + let expansion = self.parent_scope.expansion; + self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion)); - self.resolver.current_module = parent.parent.unwrap(); // nearest normal ancestor visit::walk_trait_item(self, item); - self.resolver.current_module = parent; } fn visit_token(&mut self, t: Token) { if let token::Interpolated(nt) = t.kind { if let token::NtExpr(ref expr) = *nt { - if let ast::ExprKind::Mac(..) = expr.node { + if let ast::ExprKind::Mac(..) = expr.kind { self.visit_invoc(expr.id); } } } } - fn visit_attribute(&mut self, attr: &'a ast::Attribute) { + fn visit_attribute(&mut self, attr: &'b ast::Attribute) { if !attr.is_sugared_doc && is_builtin_attr(attr) { - let parent_scope = ParentScope { - module: self.resolver.current_module.nearest_item_scope(), - expansion: self.expansion, - legacy: self.current_legacy_scope, - // Let's hope discerning built-in attributes from derive helpers is not necessary - derives: Vec::new(), - }; - parent_scope.module.builtin_attrs.borrow_mut().push(( - attr.path.segments[0].ident, parent_scope - )); + self.r.builtin_attrs.push((attr.path.segments[0].ident, self.parent_scope)); } visit::walk_attribute(self, attr); } + + fn visit_arm(&mut self, arm: &'b ast::Arm) { + if arm.is_placeholder { + self.visit_invoc(arm.id); + } else { + visit::walk_arm(self, arm); + } + } + + fn visit_field(&mut self, f: &'b ast::Field) { + if f.is_placeholder { + self.visit_invoc(f.id); + } else { + visit::walk_field(self, f); + } + } + + fn visit_field_pattern(&mut self, fp: &'b ast::FieldPat) { + if fp.is_placeholder { + self.visit_invoc(fp.id); + } else { + visit::walk_field_pattern(self, fp); + } + } + + fn visit_generic_param(&mut self, param: &'b ast::GenericParam) { + if param.is_placeholder { + self.visit_invoc(param.id); + } else { + visit::walk_generic_param(self, param); + } + } + + fn visit_param(&mut self, p: &'b ast::Param) { + if p.is_placeholder { + self.visit_invoc(p.id); + } else { + visit::walk_param(self, p); + } + } + + fn visit_struct_field(&mut self, sf: &'b ast::StructField) { + if sf.is_placeholder { + self.visit_invoc(sf.id); + } else { + visit::walk_struct_field(self, sf); + } + } + + // Constructs the reduced graph for one variant. Variants exist in the + // type and value namespaces. + fn visit_variant(&mut self, variant: &'b ast::Variant) { + if variant.is_placeholder { + self.visit_invoc(variant.id); + return; + } + + let parent = self.parent_scope.module; + let vis = self.r.variant_vis[&parent.def_id().expect("enum without def-id")]; + let expn_id = self.parent_scope.expansion; + let ident = variant.ident; + + // Define a name in the type namespace. + let def_id = self.r.definitions.local_def_id(variant.id); + let res = Res::Def(DefKind::Variant, def_id); + self.r.define(parent, ident, TypeNS, (res, vis, variant.span, expn_id)); + + // If the variant is marked as non_exhaustive then lower the visibility to within the + // crate. + let mut ctor_vis = vis; + let has_non_exhaustive = attr::contains_name(&variant.attrs, sym::non_exhaustive); + if has_non_exhaustive && vis == ty::Visibility::Public { + ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)); + } + + // Define a constructor name in the value namespace. + // Braced variants, unlike structs, generate unusable names in + // value namespace, they are reserved for possible future use. + // It's ok to use the variant's id as a ctor id since an + // error will be reported on any use of such resolution anyway. + let ctor_node_id = variant.data.ctor_id().unwrap_or(variant.id); + let ctor_def_id = self.r.definitions.local_def_id(ctor_node_id); + let ctor_kind = CtorKind::from_ast(&variant.data); + let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id); + self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id)); + + visit::walk_variant(self, variant); + } } diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 4fee15c59b33d..737589acf8d81 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -23,11 +23,11 @@ // - `check_crate` finally emits the diagnostics based on the data generated // in the last step -use std::ops::{Deref, DerefMut}; - use crate::Resolver; use crate::resolve_imports::ImportDirectiveSubclass; +use errors::pluralise; + use rustc::util::nodemap::NodeMap; use rustc::{lint, ty}; use rustc_data_structures::fx::FxHashSet; @@ -49,7 +49,7 @@ impl<'a> UnusedImport<'a> { } struct UnusedImportCheckVisitor<'a, 'b> { - resolver: &'a mut Resolver<'b>, + r: &'a mut Resolver<'b>, /// All the (so far) unused imports, grouped path list unused_imports: NodeMap>, base_use_tree: Option<&'a ast::UseTree>, @@ -57,29 +57,14 @@ struct UnusedImportCheckVisitor<'a, 'b> { item_span: Span, } -// Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver. -impl<'a, 'b> Deref for UnusedImportCheckVisitor<'a, 'b> { - type Target = Resolver<'b>; - - fn deref<'c>(&'c self) -> &'c Resolver<'b> { - &*self.resolver - } -} - -impl<'a, 'b> DerefMut for UnusedImportCheckVisitor<'a, 'b> { - fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b> { - &mut *self.resolver - } -} - impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { // We have information about whether `use` (import) directives are actually // used now. If an import is not used at all, we signal a lint error. fn check_import(&mut self, id: ast::NodeId) { let mut used = false; - self.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns))); + self.r.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns))); if !used { - if self.maybe_unused_trait_imports.contains(&id) { + if self.r.maybe_unused_trait_imports.contains(&id) { // Check later. return; } @@ -87,7 +72,7 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { } else { // This trait import is definitely used, in a way other than // method resolution. - self.maybe_unused_trait_imports.remove(&id); + self.r.maybe_unused_trait_imports.remove(&id); if let Some(i) = self.unused_imports.get_mut(&self.base_id) { i.unused.remove(&id); } @@ -118,7 +103,7 @@ impl<'a, 'b> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b> { // whether they're used or not. Also ignore imports with a dummy span // because this means that they were generated in some fashion by the // compiler and we don't need to consider them. - if let ast::ItemKind::Use(..) = item.node { + if let ast::ItemKind::Use(..) = item.kind { if item.vis.node.is_pub() || item.span.is_dummy() { return; } @@ -238,104 +223,102 @@ fn calc_unused_spans( } } -pub fn check_crate(resolver: &mut Resolver<'_>, krate: &ast::Crate) { - for directive in resolver.potentially_unused_imports.iter() { - match directive.subclass { - _ if directive.used.get() || - directive.vis.get() == ty::Visibility::Public || - directive.span.is_dummy() => { - if let ImportDirectiveSubclass::MacroUse = directive.subclass { - if !directive.span.is_dummy() { - resolver.session.buffer_lint( - lint::builtin::MACRO_USE_EXTERN_CRATE, - directive.id, - directive.span, - "deprecated `#[macro_use]` directive used to \ - import macros should be replaced at use sites \ - with a `use` statement to import the macro \ - instead", - ); +impl Resolver<'_> { + crate fn check_unused(&mut self, krate: &ast::Crate) { + for directive in self.potentially_unused_imports.iter() { + match directive.subclass { + _ if directive.used.get() || + directive.vis.get() == ty::Visibility::Public || + directive.span.is_dummy() => { + if let ImportDirectiveSubclass::MacroUse = directive.subclass { + if !directive.span.is_dummy() { + self.session.buffer_lint( + lint::builtin::MACRO_USE_EXTERN_CRATE, + directive.id, + directive.span, + "deprecated `#[macro_use]` directive used to \ + import macros should be replaced at use sites \ + with a `use` statement to import the macro \ + instead", + ); + } } } + ImportDirectiveSubclass::ExternCrate { .. } => { + self.maybe_unused_extern_crates.push((directive.id, directive.span)); + } + ImportDirectiveSubclass::MacroUse => { + let lint = lint::builtin::UNUSED_IMPORTS; + let msg = "unused `#[macro_use]` import"; + self.session.buffer_lint(lint, directive.id, directive.span, msg); + } + _ => {} } - ImportDirectiveSubclass::ExternCrate { .. } => { - resolver.maybe_unused_extern_crates.push((directive.id, directive.span)); - } - ImportDirectiveSubclass::MacroUse => { - let lint = lint::builtin::UNUSED_IMPORTS; - let msg = "unused `#[macro_use]` import"; - resolver.session.buffer_lint(lint, directive.id, directive.span, msg); - } - _ => {} } - } - - for (id, span) in resolver.unused_labels.iter() { - resolver.session.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label"); - } - let mut visitor = UnusedImportCheckVisitor { - resolver, - unused_imports: Default::default(), - base_use_tree: None, - base_id: ast::DUMMY_NODE_ID, - item_span: DUMMY_SP, - }; - visit::walk_crate(&mut visitor, krate); - - for unused in visitor.unused_imports.values() { - let mut fixes = Vec::new(); - let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) { - UnusedSpanResult::Used => continue, - UnusedSpanResult::FlatUnused(span, remove) => { - fixes.push((remove, String::new())); - vec![span] - } - UnusedSpanResult::NestedFullUnused(spans, remove) => { - fixes.push((remove, String::new())); - spans - } - UnusedSpanResult::NestedPartialUnused(spans, remove) => { - for fix in &remove { - fixes.push((*fix, String::new())); - } - spans - } + let mut visitor = UnusedImportCheckVisitor { + r: self, + unused_imports: Default::default(), + base_use_tree: None, + base_id: ast::DUMMY_NODE_ID, + item_span: DUMMY_SP, }; + visit::walk_crate(&mut visitor, krate); - let len = spans.len(); - spans.sort(); - let ms = MultiSpan::from_spans(spans.clone()); - let mut span_snippets = spans.iter() - .filter_map(|s| { - match visitor.session.source_map().span_to_snippet(*s) { - Ok(s) => Some(format!("`{}`", s)), - _ => None, + for unused in visitor.unused_imports.values() { + let mut fixes = Vec::new(); + let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) { + UnusedSpanResult::Used => continue, + UnusedSpanResult::FlatUnused(span, remove) => { + fixes.push((remove, String::new())); + vec![span] } - }).collect::>(); - span_snippets.sort(); - let msg = format!("unused import{}{}", - if len > 1 { "s" } else { "" }, - if !span_snippets.is_empty() { - format!(": {}", span_snippets.join(", ")) - } else { - String::new() - }); + UnusedSpanResult::NestedFullUnused(spans, remove) => { + fixes.push((remove, String::new())); + spans + } + UnusedSpanResult::NestedPartialUnused(spans, remove) => { + for fix in &remove { + fixes.push((*fix, String::new())); + } + spans + } + }; - let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span { - "remove the whole `use` item" - } else if spans.len() > 1 { - "remove the unused imports" - } else { - "remove the unused import" - }; + let len = spans.len(); + spans.sort(); + let ms = MultiSpan::from_spans(spans.clone()); + let mut span_snippets = spans.iter() + .filter_map(|s| { + match visitor.r.session.source_map().span_to_snippet(*s) { + Ok(s) => Some(format!("`{}`", s)), + _ => None, + } + }).collect::>(); + span_snippets.sort(); + let msg = format!("unused import{}{}", + pluralise!(len), + if !span_snippets.is_empty() { + format!(": {}", span_snippets.join(", ")) + } else { + String::new() + }); - visitor.session.buffer_lint_with_diagnostic( - lint::builtin::UNUSED_IMPORTS, - unused.use_tree_id, - ms, - &msg, - lint::builtin::BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes), - ); + let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span { + "remove the whole `use` item" + } else if spans.len() > 1 { + "remove the unused imports" + } else { + "remove the unused import" + }; + + visitor.r.session.buffer_lint_with_diagnostic( + lint::builtin::UNUSED_IMPORTS, + unused.use_tree_id, + ms, + &msg, + lint::builtin::BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes), + ); + } } } diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index aeb6f23da5aa6..d713315decbe9 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -2,55 +2,63 @@ use std::cmp::Reverse; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use log::debug; -use rustc::hir::def::{self, DefKind, CtorKind, NonMacroAttrKind}; +use rustc::bug; +use rustc::hir::def::{self, DefKind, NonMacroAttrKind}; use rustc::hir::def::Namespace::{self, *}; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; -use rustc::hir::PrimTy; -use rustc::session::{Session, config::nightly_options}; +use rustc::session::Session; use rustc::ty::{self, DefIdTree}; use rustc::util::nodemap::FxHashSet; -use syntax::ast::{self, Expr, ExprKind, Ident, NodeId, Path, Ty, TyKind}; +use syntax::ast::{self, Ident, Path}; use syntax::ext::base::MacroKind; use syntax::feature_gate::BUILTIN_ATTRIBUTES; +use syntax::source_map::SourceMap; +use syntax::struct_span_err; use syntax::symbol::{Symbol, kw}; use syntax::util::lev_distance::find_best_match_for_name; -use syntax_pos::{BytePos, Span}; +use syntax_pos::{BytePos, Span, MultiSpan}; use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver}; -use crate::{is_self_type, is_self_value, path_names_to_string, KNOWN_TOOLS}; -use crate::{CrateLint, LegacyScope, Module, ModuleKind, ModuleOrUniformRoot}; -use crate::{PathResult, PathSource, ParentScope, Resolver, RibKind, Scope, ScopeSet, Segment}; +use crate::{path_names_to_string, KNOWN_TOOLS}; +use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot}; +use crate::{PathResult, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Segment}; type Res = def::Res; /// A vector of spans and replacements, a message and applicability. crate type Suggestion = (Vec<(Span, String)>, String, Applicability); -/// A field or associated item from self type suggested in case of resolution failure. -enum AssocSuggestion { - Field, - MethodWithSelf, - AssocItem, -} - -struct TypoSuggestion { - candidate: Symbol, - res: Res, +crate struct TypoSuggestion { + pub candidate: Symbol, + pub res: Res, } impl TypoSuggestion { - fn from_res(candidate: Symbol, res: Res) -> TypoSuggestion { + crate fn from_res(candidate: Symbol, res: Res) -> TypoSuggestion { TypoSuggestion { candidate, res } } } /// A free importable items suggested in case of resolution failure. crate struct ImportSuggestion { - did: Option, + pub did: Option, pub path: Path, } -fn add_typo_suggestion( +/// Adjust the impl span so that just the `impl` keyword is taken by removing +/// everything after `<` (`"impl Iterator for A {}" -> "impl"`) and +/// everything after the first whitespace (`"impl Iterator for A" -> "impl"`). +/// +/// *Attention*: the method used is very fragile since it essentially duplicates the work of the +/// parser. If you need to use this function or something similar, please consider updating the +/// `source_map` functions and this function to something more robust. +fn reduce_impl_span_to_impl_keyword(cm: &SourceMap, impl_span: Span) -> Span { + let impl_span = cm.span_until_char(impl_span, '<'); + let impl_span = cm.span_until_whitespace(impl_span); + impl_span +} + +crate fn add_typo_suggestion( err: &mut DiagnosticBuilder<'_>, suggestion: Option, span: Span ) -> bool { if let Some(suggestion) = suggestion { @@ -65,493 +73,311 @@ fn add_typo_suggestion( false } -fn add_module_candidates( - module: Module<'_>, names: &mut Vec, filter_fn: &impl Fn(Res) -> bool -) { - for (&(ident, _), resolution) in module.resolutions.borrow().iter() { - if let Some(binding) = resolution.borrow().binding { - let res = binding.res(); - if filter_fn(res) { - names.push(TypoSuggestion::from_res(ident.name, res)); - } - } - } -} - impl<'a> Resolver<'a> { - /// Handles error reporting for `smart_resolve_path_fragment` function. - /// Creates base error and amends it with one short label and possibly some longer helps/notes. - pub(crate) fn smart_resolve_report_errors( + crate fn add_module_candidates( &mut self, - path: &[Segment], - span: Span, - source: PathSource<'_>, - res: Option, - ) -> (DiagnosticBuilder<'a>, Vec) { - let ident_span = path.last().map_or(span, |ident| ident.ident.span); - let ns = source.namespace(); - let is_expected = &|res| source.is_expected(res); - let is_enum_variant = &|res| { - if let Res::Def(DefKind::Variant, _) = res { true } else { false } - }; - - // Make the base error. - let expected = source.descr_expected(); - let path_str = Segment::names_to_string(path); - let item_str = path.last().unwrap().ident; - let code = source.error_code(res.is_some()); - let (base_msg, fallback_label, base_span) = if let Some(res) = res { - (format!("expected {}, found {} `{}`", expected, res.descr(), path_str), - format!("not a {}", expected), - span) - } else { - let item_span = path.last().unwrap().ident.span; - let (mod_prefix, mod_str) = if path.len() == 1 { - (String::new(), "this scope".to_string()) - } else if path.len() == 2 && path[0].ident.name == kw::PathRoot { - (String::new(), "the crate root".to_string()) - } else { - let mod_path = &path[..path.len() - 1]; - let mod_prefix = match self.resolve_path_without_parent_scope( - mod_path, Some(TypeNS), false, span, CrateLint::No - ) { - PathResult::Module(ModuleOrUniformRoot::Module(module)) => - module.def_kind(), - _ => None, - }.map_or(String::new(), |kind| format!("{} ", kind.descr())); - (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path))) - }; - (format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str), - format!("not found in {}", mod_str), - item_span) - }; - - let code = DiagnosticId::Error(code.into()); - let mut err = self.session.struct_span_err_with_code(base_span, &base_msg, code); - - // Emit help message for fake-self from other languages (e.g., `this` in Javascript). - if ["this", "my"].contains(&&*item_str.as_str()) - && self.self_value_is_available(path[0].ident.span, span) { - err.span_suggestion( - span, - "did you mean", - "self".to_string(), - Applicability::MaybeIncorrect, - ); - } - - // Emit special messages for unresolved `Self` and `self`. - if is_self_type(path, ns) { - __diagnostic_used!(E0411); - err.code(DiagnosticId::Error("E0411".into())); - err.span_label(span, format!("`Self` is only available in impls, traits, \ - and type definitions")); - return (err, Vec::new()); - } - if is_self_value(path, ns) { - debug!("smart_resolve_path_fragment: E0424, source={:?}", source); - - __diagnostic_used!(E0424); - err.code(DiagnosticId::Error("E0424".into())); - err.span_label(span, match source { - PathSource::Pat => { - format!("`self` value is a keyword \ - and may not be bound to \ - variables or shadowed") - } - _ => { - format!("`self` value is a keyword \ - only available in methods \ - with `self` parameter") + module: Module<'a>, + names: &mut Vec, + filter_fn: &impl Fn(Res) -> bool, + ) { + for (&(ident, _), resolution) in self.resolutions(module).borrow().iter() { + if let Some(binding) = resolution.borrow().binding { + let res = binding.res(); + if filter_fn(res) { + names.push(TypoSuggestion::from_res(ident.name, res)); } - }); - return (err, Vec::new()); + } } + } - // Try to lookup name in more relaxed fashion for better error reporting. - let ident = path.last().unwrap().ident; - let candidates = self.lookup_import_candidates(ident, ns, is_expected) - .drain(..) - .filter(|ImportSuggestion { did, .. }| { - match (did, res.and_then(|res| res.opt_def_id())) { - (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did, - _ => true, - } - }) - .collect::>(); - let crate_def_id = DefId::local(CRATE_DEF_INDEX); - if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) { - let enum_candidates = - self.lookup_import_candidates(ident, ns, is_enum_variant); - let mut enum_candidates = enum_candidates.iter() - .map(|suggestion| { - import_candidate_to_enum_paths(&suggestion) - }).collect::>(); - enum_candidates.sort(); - - if !enum_candidates.is_empty() { - // Contextualize for E0412 "cannot find type", but don't belabor the point - // (that it's a variant) for E0573 "expected type, found variant". - let preamble = if res.is_none() { - let others = match enum_candidates.len() { - 1 => String::new(), - 2 => " and 1 other".to_owned(), - n => format!(" and {} others", n) - }; - format!("there is an enum variant `{}`{}; ", - enum_candidates[0].0, others) - } else { - String::new() - }; - let msg = format!("{}try using the variant's enum", preamble); + /// Combines an error with provided span and emits it. + /// + /// This takes the error provided, combines it with the span and any additional spans inside the + /// error and emits it. + crate fn report_error(&self, span: Span, resolution_error: ResolutionError<'_>) { + self.into_struct_error(span, resolution_error).emit(); + } - err.span_suggestions( + crate fn into_struct_error( + &self, span: Span, resolution_error: ResolutionError<'_> + ) -> DiagnosticBuilder<'_> { + match resolution_error { + ResolutionError::GenericParamsFromOuterFunction(outer_res, has_generic_params) => { + let mut err = struct_span_err!(self.session, span, - &msg, - enum_candidates.into_iter() - .map(|(_variant_path, enum_ty_path)| enum_ty_path) - // Variants re-exported in prelude doesn't mean `prelude::v1` is the - // type name! - // FIXME: is there a more principled way to do this that - // would work for other re-exports? - .filter(|enum_ty_path| enum_ty_path != "std::prelude::v1") - // Also write `Option` rather than `std::prelude::v1::Option`. - .map(|enum_ty_path| { - // FIXME #56861: DRY-er prelude filtering. - enum_ty_path.trim_start_matches("std::prelude::v1::").to_owned() - }), - Applicability::MachineApplicable, + E0401, + "can't use generic parameters from outer function", ); - } - } - if path.len() == 1 && self.self_type_is_available(span) { - if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) { - let self_is_available = self.self_value_is_available(path[0].ident.span, span); - match candidate { - AssocSuggestion::Field => { - if self_is_available { - err.span_suggestion( - span, - "you might have meant to use the available field", - format!("self.{}", path_str), - Applicability::MachineApplicable, - ); - } else { + err.span_label(span, format!("use of generic parameter from outer function")); + + let cm = self.session.source_map(); + match outer_res { + Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => { + if let Some(impl_span) = maybe_impl_defid.and_then(|def_id| { + self.definitions.opt_span(def_id) + }) { err.span_label( - span, - "a field by this name exists in `Self`", + reduce_impl_span_to_impl_keyword(cm, impl_span), + "`Self` type implicitly declared here, by this `impl`", ); } + match (maybe_trait_defid, maybe_impl_defid) { + (Some(_), None) => { + err.span_label(span, "can't use `Self` here"); + } + (_, Some(_)) => { + err.span_label(span, "use a type here instead"); + } + (None, None) => bug!("`impl` without trait nor type?"), + } + return err; + }, + Res::Def(DefKind::TyParam, def_id) => { + if let Some(span) = self.definitions.opt_span(def_id) { + err.span_label(span, "type parameter from outer function"); + } } - AssocSuggestion::MethodWithSelf if self_is_available => { - err.span_suggestion( - span, - "try", - format!("self.{}", path_str), - Applicability::MachineApplicable, - ); + Res::Def(DefKind::ConstParam, def_id) => { + if let Some(span) = self.definitions.opt_span(def_id) { + err.span_label(span, "const parameter from outer function"); + } } - AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => { - err.span_suggestion( - span, - "try", - format!("Self::{}", path_str), - Applicability::MachineApplicable, - ); + _ => { + bug!("GenericParamsFromOuterFunction should only be used with Res::SelfTy, \ + DefKind::TyParam"); } } - return (err, candidates); - } - } - - // Try Levenshtein algorithm. - let levenshtein_worked = add_typo_suggestion( - &mut err, self.lookup_typo_candidate(path, ns, is_expected, span), ident_span - ); - - // Try context-dependent help if relaxed lookup didn't work. - if let Some(res) = res { - if self.smart_resolve_context_dependent_help(&mut err, - span, - source, - res, - &path_str, - &fallback_label) { - return (err, candidates); - } - } - // Fallback label. - if !levenshtein_worked { - err.span_label(base_span, fallback_label); - self.type_ascription_suggestion(&mut err, base_span); - } - (err, candidates) - } - - fn followed_by_brace(&self, span: Span) -> (bool, Option<(Span, String)>) { - // HACK(estebank): find a better way to figure out that this was a - // parser issue where a struct literal is being used on an expression - // where a brace being opened means a block is being started. Look - // ahead for the next text to see if `span` is followed by a `{`. - let sm = self.session.source_map(); - let mut sp = span; - loop { - sp = sm.next_point(sp); - match sm.span_to_snippet(sp) { - Ok(ref snippet) => { - if snippet.chars().any(|c| { !c.is_whitespace() }) { - break; - } - } - _ => break, - } - } - let followed_by_brace = match sm.span_to_snippet(sp) { - Ok(ref snippet) if snippet == "{" => true, - _ => false, - }; - // In case this could be a struct literal that needs to be surrounded - // by parenthesis, find the appropriate span. - let mut i = 0; - let mut closing_brace = None; - loop { - sp = sm.next_point(sp); - match sm.span_to_snippet(sp) { - Ok(ref snippet) => { - if snippet == "}" { - let sp = span.to(sp); - if let Ok(snippet) = sm.span_to_snippet(sp) { - closing_brace = Some((sp, snippet)); - } - break; + if has_generic_params == HasGenericParams::Yes { + // Try to retrieve the span of the function signature and generate a new + // message with a local type or const parameter. + let sugg_msg = &format!("try using a local generic parameter instead"); + if let Some((sugg_span, snippet)) = cm.generate_local_type_param_snippet(span) { + // Suggest the modification to the user + err.span_suggestion( + sugg_span, + sugg_msg, + snippet, + Applicability::MachineApplicable, + ); + } else if let Some(sp) = cm.generate_fn_name_span(span) { + err.span_label(sp, + format!("try adding a local generic parameter in this method instead")); + } else { + err.help(&format!("try using a local generic parameter instead")); } } - _ => break, - } - i += 1; - // The bigger the span, the more likely we're incorrect -- - // bound it to 100 chars long. - if i > 100 { - break; - } - } - return (followed_by_brace, closing_brace) - } - /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment` - /// function. - /// Returns `true` if able to provide context-dependent help. - fn smart_resolve_context_dependent_help( - &mut self, - err: &mut DiagnosticBuilder<'a>, - span: Span, - source: PathSource<'_>, - res: Res, - path_str: &str, - fallback_label: &str, - ) -> bool { - let ns = source.namespace(); - let is_expected = &|res| source.is_expected(res); - - let path_sep = |err: &mut DiagnosticBuilder<'_>, expr: &Expr| match expr.node { - ExprKind::Field(_, ident) => { - err.span_suggestion( - expr.span, - "use the path separator to refer to an item", - format!("{}::{}", path_str, ident), - Applicability::MaybeIncorrect, - ); - true + err } - ExprKind::MethodCall(ref segment, ..) => { - let span = expr.span.with_hi(segment.ident.span.hi()); - err.span_suggestion( + ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => { + let mut err = struct_span_err!( + self.session, span, - "use the path separator to refer to an item", - format!("{}::{}", path_str, segment.ident), - Applicability::MaybeIncorrect, + E0403, + "the name `{}` is already used for a generic \ + parameter in this item's generic parameters", + name, ); - true + err.span_label(span, "already used"); + err.span_label(first_use_span, format!("first use of `{}`", name)); + err } - _ => false, - }; - - let mut bad_struct_syntax_suggestion = || { - let (followed_by_brace, closing_brace) = self.followed_by_brace(span); - let mut suggested = false; - match source { - PathSource::Expr(Some(parent)) => { - suggested = path_sep(err, &parent); - } - PathSource::Expr(None) if followed_by_brace == true => { - if let Some((sp, snippet)) = closing_brace { - err.span_suggestion( - sp, - "surround the struct literal with parenthesis", - format!("({})", snippet), - Applicability::MaybeIncorrect, - ); - } else { - err.span_label( - span, // Note the parenthesis surrounding the suggestion below - format!("did you mean `({} {{ /* fields */ }})`?", path_str), - ); - } - suggested = true; - }, - _ => {} + ResolutionError::MethodNotMemberOfTrait(method, trait_) => { + let mut err = struct_span_err!(self.session, + span, + E0407, + "method `{}` is not a member of trait `{}`", + method, + trait_); + err.span_label(span, format!("not a member of trait `{}`", trait_)); + err } - if !suggested { - err.span_label( - span, - format!("did you mean `{} {{ /* fields */ }}`?", path_str), - ); + ResolutionError::TypeNotMemberOfTrait(type_, trait_) => { + let mut err = struct_span_err!(self.session, + span, + E0437, + "type `{}` is not a member of trait `{}`", + type_, + trait_); + err.span_label(span, format!("not a member of trait `{}`", trait_)); + err } - }; + ResolutionError::ConstNotMemberOfTrait(const_, trait_) => { + let mut err = struct_span_err!(self.session, + span, + E0438, + "const `{}` is not a member of trait `{}`", + const_, + trait_); + err.span_label(span, format!("not a member of trait `{}`", trait_)); + err + } + ResolutionError::VariableNotBoundInPattern(binding_error) => { + let BindingError { name, target, origin, could_be_path } = binding_error; - match (res, source) { - (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => { - err.span_suggestion( - span, - "use `!` to invoke the macro", - format!("{}!", path_str), - Applicability::MaybeIncorrect, + let target_sp = target.iter().copied().collect::>(); + let origin_sp = origin.iter().copied().collect::>(); + + let msp = MultiSpan::from_spans(target_sp.clone()); + let msg = format!("variable `{}` is not bound in all patterns", name); + let mut err = self.session.struct_span_err_with_code( + msp, + &msg, + DiagnosticId::Error("E0408".into()), ); - if path_str == "try" && span.rust_2015() { - err.note("if you want the `try` keyword, you need to be in the 2018 edition"); + for sp in target_sp { + err.span_label(sp, format!("pattern doesn't bind `{}`", name)); } - } - (Res::Def(DefKind::TyAlias, _), PathSource::Trait(_)) => { - err.span_label(span, "type aliases cannot be used as traits"); - if nightly_options::is_nightly_build() { - err.note("did you mean to use a trait alias?"); + for sp in origin_sp { + err.span_label(sp, "variable not in all patterns"); } - } - (Res::Def(DefKind::Mod, _), PathSource::Expr(Some(parent))) => { - if !path_sep(err, &parent) { - return false; + if *could_be_path { + let help_msg = format!( + "if you meant to match on a variant or a `const` item, consider \ + making the path in the pattern qualified: `?::{}`", + name, + ); + err.span_help(span, &help_msg); } + err } - (Res::Def(DefKind::Enum, def_id), PathSource::TupleStruct) - | (Res::Def(DefKind::Enum, def_id), PathSource::Expr(..)) => { - if let Some(variants) = self.collect_enum_variants(def_id) { - if !variants.is_empty() { - let msg = if variants.len() == 1 { - "try using the enum's variant" - } else { - "try using one of the enum's variants" - }; - - err.span_suggestions( - span, - msg, - variants.iter().map(path_names_to_string), - Applicability::MaybeIncorrect, - ); - } - } else { - err.note("did you mean to use one of the enum's variants?"); - } - }, - (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => { - if let Some((ctor_def, ctor_vis)) - = self.struct_constructors.get(&def_id).cloned() { - let accessible_ctor = self.is_accessible(ctor_vis); - if is_expected(ctor_def) && !accessible_ctor { - err.span_label( - span, - format!("constructor is not visible here due to private fields"), - ); - } + ResolutionError::VariableBoundWithDifferentMode(variable_name, + first_binding_span) => { + let mut err = struct_span_err!(self.session, + span, + E0409, + "variable `{}` is bound in inconsistent \ + ways within the same match arm", + variable_name); + err.span_label(span, "bound in different ways"); + err.span_label(first_binding_span, "first binding"); + err + } + ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => { + let mut err = struct_span_err!(self.session, + span, + E0415, + "identifier `{}` is bound more than once in this parameter list", + identifier); + err.span_label(span, "used as parameter more than once"); + err + } + ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => { + let mut err = struct_span_err!(self.session, + span, + E0416, + "identifier `{}` is bound more than once in the same pattern", + identifier); + err.span_label(span, "used in a pattern more than once"); + err + } + ResolutionError::UndeclaredLabel(name, lev_candidate) => { + let mut err = struct_span_err!(self.session, + span, + E0426, + "use of undeclared label `{}`", + name); + if let Some(lev_candidate) = lev_candidate { + err.span_suggestion( + span, + "a label with a similar name exists in this scope", + lev_candidate.to_string(), + Applicability::MaybeIncorrect, + ); } else { - bad_struct_syntax_suggestion(); + err.span_label(span, format!("undeclared label `{}`", name)); } + err } - (Res::Def(DefKind::Union, _), _) | - (Res::Def(DefKind::Variant, _), _) | - (Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _), _) if ns == ValueNS => { - bad_struct_syntax_suggestion(); + ResolutionError::SelfImportsOnlyAllowedWithin => { + struct_span_err!(self.session, + span, + E0429, + "{}", + "`self` imports are only allowed within a { } list") } - (Res::SelfTy(..), _) if ns == ValueNS => { - err.span_label(span, fallback_label); - err.note("can't use `Self` as a constructor, you must use the implemented struct"); + ResolutionError::SelfImportCanOnlyAppearOnceInTheList => { + let mut err = struct_span_err!(self.session, span, E0430, + "`self` import can only appear once in an import list"); + err.span_label(span, "can only appear once in an import list"); + err } - (Res::Def(DefKind::TyAlias, _), _) - | (Res::Def(DefKind::AssocTy, _), _) if ns == ValueNS => { - err.note("can't use a type alias as a constructor"); + ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => { + let mut err = struct_span_err!(self.session, span, E0431, + "`self` import can only appear in an import list with \ + a non-empty prefix"); + err.span_label(span, "can only appear in an import list with a non-empty prefix"); + err } - _ => return false, - } - true - } + ResolutionError::FailedToResolve { label, suggestion } => { + let mut err = struct_span_err!(self.session, span, E0433, + "failed to resolve: {}", &label); + err.span_label(span, label); - fn lookup_assoc_candidate(&mut self, - ident: Ident, - ns: Namespace, - filter_fn: FilterFn) - -> Option - where FilterFn: Fn(Res) -> bool - { - fn extract_node_id(t: &Ty) -> Option { - match t.node { - TyKind::Path(None, _) => Some(t.id), - TyKind::Rptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty), - // This doesn't handle the remaining `Ty` variants as they are not - // that commonly the self_type, it might be interesting to provide - // support for those in future. - _ => None, - } - } - - // Fields are generally expected in the same contexts as locals. - if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) { - if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) { - // Look for a field with the same name in the current self_type. - if let Some(resolution) = self.partial_res_map.get(&node_id) { - match resolution.base_res() { - Res::Def(DefKind::Struct, did) | Res::Def(DefKind::Union, did) - if resolution.unresolved_segments() == 0 => { - if let Some(field_names) = self.field_names.get(&did) { - if field_names.iter().any(|&field_name| ident.name == field_name) { - return Some(AssocSuggestion::Field); - } - } - } - _ => {} - } + if let Some((suggestions, msg, applicability)) = suggestion { + err.multipart_suggestion(&msg, suggestions, applicability); } - } - } - for assoc_type_ident in &self.current_trait_assoc_types { - if *assoc_type_ident == ident { - return Some(AssocSuggestion::AssocItem); + err } - } - - // Look for associated items in the current trait. - if let Some((module, _)) = self.current_trait_ref { - if let Ok(binding) = self.resolve_ident_in_module( - ModuleOrUniformRoot::Module(module), - ident, - ns, - None, - false, - module.span, - ) { + ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => { + let mut err = struct_span_err!(self.session, + span, + E0434, + "{}", + "can't capture dynamic environment in a fn item"); + err.help("use the `|| { ... }` closure form instead"); + err + } + ResolutionError::AttemptToUseNonConstantValueInConstant => { + let mut err = struct_span_err!(self.session, span, E0435, + "attempt to use a non-constant value in a constant"); + err.span_label(span, "non-constant value"); + err + } + ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => { let res = binding.res(); - if filter_fn(res) { - return Some(if self.has_self.contains(&res.def_id()) { - AssocSuggestion::MethodWithSelf - } else { - AssocSuggestion::AssocItem - }); - } + let shadows_what = res.descr(); + let mut err = struct_span_err!(self.session, span, E0530, "{}s cannot shadow {}s", + what_binding, shadows_what); + err.span_label(span, format!("cannot be named the same as {} {}", + res.article(), shadows_what)); + let participle = if binding.is_import() { "imported" } else { "defined" }; + let msg = format!("the {} `{}` is {} here", shadows_what, name, participle); + err.span_label(binding.span, msg); + err + } + ResolutionError::ForwardDeclaredTyParam => { + let mut err = struct_span_err!(self.session, span, E0128, + "type parameters with a default cannot use \ + forward declared identifiers"); + err.span_label( + span, "defaulted type parameters cannot be forward declared".to_string()); + err + } + ResolutionError::SelfInTyParamDefault => { + let mut err = struct_span_err!( + self.session, + span, + E0735, + "type parameters cannot use `Self` in their defaults" + ); + err.span_label( + span, "`Self` in type parameter default".to_string()); + err + } + ResolutionError::ConstParamDependentOnTypeParam => { + let mut err = struct_span_err!( + self.session, + span, + E0671, + "const parameters cannot depend on type parameters" + ); + err.span_label(span, format!("const parameter depends on type parameter")); + err } } - - None } /// Lookup typo candidate in scope for a macro or import. @@ -568,10 +394,11 @@ impl<'a> Resolver<'a> { Scope::DeriveHelpers => { let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); if filter_fn(res) { - for derive in &parent_scope.derives { - let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope }; + for derive in parent_scope.derives { + let parent_scope = + &ParentScope { derives: &[], ..*parent_scope }; if let Ok((Some(ext), _)) = this.resolve_macro_path( - derive, Some(MacroKind::Derive), &parent_scope, false, false + derive, Some(MacroKind::Derive), parent_scope, false, false ) { suggestions.extend(ext.helper_attrs.iter().map(|name| { TypoSuggestion::from_res(*name, res) @@ -593,10 +420,10 @@ impl<'a> Resolver<'a> { Scope::CrateRoot => { let root_ident = Ident::new(kw::PathRoot, ident.span); let root_module = this.resolve_crate_root(root_ident); - add_module_candidates(root_module, &mut suggestions, filter_fn); + this.add_module_candidates(root_module, &mut suggestions, filter_fn); } Scope::Module(module) => { - add_module_candidates(module, &mut suggestions, filter_fn); + this.add_module_candidates(module, &mut suggestions, filter_fn); } Scope::MacroUsePrelude => { suggestions.extend(this.macro_use_prelude.iter().filter_map(|(name, binding)| { @@ -644,9 +471,9 @@ impl<'a> Resolver<'a> { Scope::StdLibPrelude => { if let Some(prelude) = this.prelude { let mut tmp_suggestions = Vec::new(); - add_module_candidates(prelude, &mut tmp_suggestions, filter_fn); + this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn); suggestions.extend(tmp_suggestions.into_iter().filter(|s| { - use_prelude || this.is_builtin_macro(s.res.opt_def_id()) + use_prelude || this.is_builtin_macro(s.res) })); } } @@ -683,98 +510,6 @@ impl<'a> Resolver<'a> { } } - fn lookup_typo_candidate( - &mut self, - path: &[Segment], - ns: Namespace, - filter_fn: &impl Fn(Res) -> bool, - span: Span, - ) -> Option { - let mut names = Vec::new(); - if path.len() == 1 { - // Search in lexical scope. - // Walk backwards up the ribs in scope and collect candidates. - for rib in self.ribs[ns].iter().rev() { - // Locals and type parameters - for (ident, &res) in &rib.bindings { - if filter_fn(res) { - names.push(TypoSuggestion::from_res(ident.name, res)); - } - } - // Items in scope - if let RibKind::ModuleRibKind(module) = rib.kind { - // Items from this module - add_module_candidates(module, &mut names, &filter_fn); - - if let ModuleKind::Block(..) = module.kind { - // We can see through blocks - } else { - // Items from the prelude - if !module.no_implicit_prelude { - names.extend(self.extern_prelude.clone().iter().flat_map(|(ident, _)| { - self.crate_loader - .maybe_process_path_extern(ident.name, ident.span) - .and_then(|crate_id| { - let crate_mod = Res::Def( - DefKind::Mod, - DefId { - krate: crate_id, - index: CRATE_DEF_INDEX, - }, - ); - - if filter_fn(crate_mod) { - Some(TypoSuggestion::from_res(ident.name, crate_mod)) - } else { - None - } - }) - })); - - if let Some(prelude) = self.prelude { - add_module_candidates(prelude, &mut names, &filter_fn); - } - } - break; - } - } - } - // Add primitive types to the mix - if filter_fn(Res::PrimTy(PrimTy::Bool)) { - names.extend( - self.primitive_type_table.primitive_types.iter().map(|(name, prim_ty)| { - TypoSuggestion::from_res(*name, Res::PrimTy(*prim_ty)) - }) - ) - } - } else { - // Search in module. - let mod_path = &path[..path.len() - 1]; - if let PathResult::Module(module) = self.resolve_path_without_parent_scope( - mod_path, Some(TypeNS), false, span, CrateLint::No - ) { - if let ModuleOrUniformRoot::Module(module) = module { - add_module_candidates(module, &mut names, &filter_fn); - } - } - } - - let name = path[path.len() - 1].ident.name; - // Make sure error reporting is deterministic. - names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str()); - - match find_best_match_for_name( - names.iter().map(|suggestion| &suggestion.candidate), - &name.as_str(), - None, - ) { - Some(found) if found != name => names - .into_iter() - .find(|suggestion| suggestion.candidate == found), - _ => None, - } - } - fn lookup_import_candidates_from_module(&mut self, lookup_ident: Ident, namespace: Namespace, @@ -792,11 +527,9 @@ impl<'a> Resolver<'a> { while let Some((in_module, path_segments, in_module_is_extern)) = worklist.pop() { - self.populate_module_if_necessary(in_module); - // We have to visit module children in deterministic order to avoid // instabilities in reported imports (#43552). - in_module.for_each_child_stable(|ident, ns, name_binding| { + in_module.for_each_child(self, |this, ident, ns, name_binding| { // avoid imports entirely if name_binding.is_import() && !name_binding.is_extern_crate() { return; } // avoid non-importable candidates as well @@ -830,7 +563,7 @@ impl<'a> Resolver<'a> { // outside crate private modules => no need to check this) if !in_module_is_extern || name_binding.vis == ty::Visibility::Public { let did = match res { - Res::Def(DefKind::Ctor(..), did) => self.parent(did), + Res::Def(DefKind::Ctor(..), did) => this.parent(did), _ => res.opt_def_id(), }; candidates.push(ImportSuggestion { did, path }); @@ -878,20 +611,26 @@ impl<'a> Resolver<'a> { where FilterFn: Fn(Res) -> bool { let mut suggestions = self.lookup_import_candidates_from_module( - lookup_ident, namespace, self.graph_root, Ident::with_empty_ctxt(kw::Crate), &filter_fn + lookup_ident, namespace, self.graph_root, Ident::with_dummy_span(kw::Crate), &filter_fn ); if lookup_ident.span.rust_2018() { let extern_prelude_names = self.extern_prelude.clone(); for (ident, _) in extern_prelude_names.into_iter() { + if ident.span.from_expansion() { + // Idents are adjusted to the root context before being + // resolved in the extern prelude, so reporting this to the + // user is no help. This skips the injected + // `extern crate std` in the 2018 edition, which would + // otherwise cause duplicate suggestions. + continue; + } if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name, ident.span) { let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX, }); - self.populate_module_if_necessary(&crate_root); - suggestions.extend(self.lookup_import_candidates_from_module( lookup_ident, namespace, crate_root, ident, &filter_fn)); } @@ -901,65 +640,6 @@ impl<'a> Resolver<'a> { suggestions } - fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> { - let mut result = None; - let mut seen_modules = FxHashSet::default(); - let mut worklist = vec![(self.graph_root, Vec::new())]; - - while let Some((in_module, path_segments)) = worklist.pop() { - // abort if the module is already found - if result.is_some() { break; } - - self.populate_module_if_necessary(in_module); - - in_module.for_each_child_stable(|ident, _, name_binding| { - // abort if the module is already found or if name_binding is private external - if result.is_some() || !name_binding.vis.is_visible_locally() { - return - } - if let Some(module) = name_binding.module() { - // form the path - let mut path_segments = path_segments.clone(); - path_segments.push(ast::PathSegment::from_ident(ident)); - let module_def_id = module.def_id().unwrap(); - if module_def_id == def_id { - let path = Path { - span: name_binding.span, - segments: path_segments, - }; - result = Some((module, ImportSuggestion { did: Some(def_id), path })); - } else { - // add the module to the lookup - if seen_modules.insert(module_def_id) { - worklist.push((module, path_segments)); - } - } - } - }); - } - - result - } - - fn collect_enum_variants(&mut self, def_id: DefId) -> Option> { - self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| { - self.populate_module_if_necessary(enum_module); - - let mut variants = Vec::new(); - enum_module.for_each_child_stable(|ident, _, name_binding| { - if let Res::Def(DefKind::Variant, _) = name_binding.res() { - let mut segms = enum_import_suggestion.path.segments.clone(); - segms.push(ast::PathSegment::from_ident(ident)); - variants.push(Path { - span: name_binding.span, - segments: segms, - }); - } - }); - variants - }) - } - crate fn unresolved_macro_suggestions( &mut self, err: &mut DiagnosticBuilder<'a>, @@ -969,7 +649,7 @@ impl<'a> Resolver<'a> { ) { let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind); let suggestion = self.early_lookup_typo_candidate( - ScopeSet::Macro(macro_kind), &parent_scope, ident, is_expected + ScopeSet::Macro(macro_kind), parent_scope, ident, is_expected ); add_typo_suggestion(err, suggestion, ident.span); @@ -1029,7 +709,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { ) -> Option<(Vec, Vec)> { // Replace first ident with `self` and check if that is valid. path[0].ident.name = kw::SelfLower; - let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); + let result = self.r.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result); if let PathResult::Module(..) = result { Some((path, Vec::new())) @@ -1053,7 +733,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { ) -> Option<(Vec, Vec)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Crate; - let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); + let result = self.r.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result); if let PathResult::Module(..) = result { Some(( @@ -1084,7 +764,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { ) -> Option<(Vec, Vec)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Super; - let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); + let result = self.r.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result); if let PathResult::Module(..) = result { Some((path, Vec::new())) @@ -1117,13 +797,13 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // 1) some consistent ordering for emitted dignostics, and // 2) `std` suggestions before `core` suggestions. let mut extern_crate_names = - self.resolver.extern_prelude.iter().map(|(ident, _)| ident.name).collect::>(); + self.r.extern_prelude.iter().map(|(ident, _)| ident.name).collect::>(); extern_crate_names.sort_by_key(|name| Reverse(name.as_str())); for name in extern_crate_names.into_iter() { // Replace first ident with a crate name and check if that is valid. path[0].ident.name = name; - let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); + let result = self.r.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}", name, path, result); if let PathResult::Module(..) = result { @@ -1147,7 +827,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// at the root of the crate instead of the module where it is defined /// ``` pub(crate) fn check_for_module_export_macro( - &self, + &mut self, directive: &'b ImportDirective<'b>, module: ModuleOrUniformRoot<'b>, ident: Ident, @@ -1168,7 +848,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { return None; } - let resolutions = crate_module.resolutions.borrow(); + let resolutions = self.r.resolutions(crate_module).borrow(); let resolution = resolutions.get(&(ident, MacroNS))?; let binding = resolution.borrow().binding()?; if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() { @@ -1189,7 +869,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // ie. `use a::b::{c, d, e};` // ^^^ let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding( - self.resolver.session, directive.span, directive.use_span, + self.r.session, directive.span, directive.use_span, ); debug!("check_for_module_export_macro: found_closing_brace={:?} binding_span={:?}", found_closing_brace, binding_span); @@ -1204,7 +884,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // ie. `use a::b::{c, d};` // ^^^ if let Some(previous_span) = extend_span_to_previous_binding( - self.resolver.session, binding_span, + self.r.session, binding_span, ) { debug!("check_for_module_export_macro: previous_span={:?}", previous_span); removal_span = removal_span.with_lo(previous_span.lo()); @@ -1222,12 +902,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // or `use a::{b, c, d}};` // ^^^^^^^^^^^ let (has_nested, after_crate_name) = find_span_immediately_after_crate_name( - self.resolver.session, module_name, directive.use_span, + self.r.session, module_name, directive.use_span, ); debug!("check_for_module_export_macro: has_nested={:?} after_crate_name={:?}", has_nested, after_crate_name); - let source_map = self.resolver.session.source_map(); + let source_map = self.r.session.source_map(); // Add the import to the start, with a `{` if required. let start_point = source_map.start_point(after_crate_name); @@ -1415,21 +1095,6 @@ fn find_span_immediately_after_crate_name( (next_left_bracket == after_second_colon, from_second_colon) } -/// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant. -fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) { - let variant_path = &suggestion.path; - let variant_path_string = path_names_to_string(variant_path); - - let path_len = suggestion.path.segments.len(); - let enum_path = ast::Path { - span: suggestion.path.span, - segments: suggestion.path.segments[0..path_len - 1].to_vec(), - }; - let enum_path_string = path_names_to_string(&enum_path); - - (variant_path_string, enum_path_string) -} - /// When an entity with a given name is not available in scope, we search for /// entities with that name in all crates. This method allows outputting the /// results of this search in a programmer-friendly way diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs index e01f53786edab..47346774180fe 100644 --- a/src/librustc_resolve/error_codes.rs +++ b/src/librustc_resolve/error_codes.rs @@ -1,18 +1,16 @@ -use syntax::{register_diagnostics, register_long_diagnostics}; - // Error messages for EXXXX errors. Each message should start and end with a // new line, and be wrapped to 80 characters. In vim you can `:set tw=80` and // use `gq` to wrap paragraphs. Use `:set tw=0` to disable. -register_long_diagnostics! { +syntax::register_diagnostics! { E0128: r##" Type parameter defaults can only use parameters that occur before them. Erroneous code example: ```compile_fail,E0128 -struct Foo { +struct Foo { field1: T, - filed2: U, + field2: U, } // error: type parameters with a default cannot use forward declared // identifiers @@ -22,9 +20,9 @@ Since type parameters are evaluated in-order, you may be able to fix this issue by doing: ``` -struct Foo { +struct Foo { field1: T, - filed2: U, + field2: U, } ``` @@ -526,15 +524,25 @@ Some type parameters have the same name. Erroneous code example: ```compile_fail,E0403 -fn foo(s: T, u: T) {} // error: the name `T` is already used for a type - // parameter in this type parameter list +fn f(s: T, u: T) {} // error: the name `T` is already used for a generic + // parameter in this item's generic parameters ``` Please verify that none of the type parameters are misspelled, and rename any clashing parameters. Example: ``` -fn foo(s: T, u: Y) {} // ok! +fn f(s: T, u: Y) {} // ok! +``` + +Type parameters in an associated item also cannot shadow parameters from the +containing item: + +```compile_fail,E0403 +trait Foo { + fn do_something(&self) -> T; + fn do_something_else(&self, bar: T); +} ``` "##, @@ -1517,6 +1525,51 @@ match r { ``` "##, +E0531: r##" +An unknown tuple struct/variant has been used. + +Erroneous code example: + +```compile_fail,E0531 +let Type(x) = Type(12); // error! +match Bar(12) { + Bar(x) => {} // error! + _ => {} +} +``` + +In most cases, it's either a forgotten import or a typo. However, let's look at +how you can have such a type: + +```edition2018 +struct Type(u32); // this is a tuple struct + +enum Foo { + Bar(u32), // this is a tuple variant +} + +use Foo::*; // To use Foo's variant directly, we need to import them in + // the scope. +``` + +Either way, it should work fine with our previous code: + +```edition2018 +struct Type(u32); + +enum Foo { + Bar(u32), +} +use Foo::*; + +let Type(x) = Type(12); // ok! +match Type(12) { + Type(x) => {} // ok! + _ => {} +} +``` +"##, + E0532: r##" Pattern arm did not match expected kind. @@ -1653,9 +1706,21 @@ fn const_id() -> T { // error: const parameter ``` "##, +E0735: r##" +Type parameter defaults cannot use `Self` on structs, enums, or unions. + +Erroneous code example: + +```compile_fail,E0735 +struct Foo> { + field1: Option, + field2: Option, } +// error: type parameters cannot use `Self` in their defaults. +``` +"##, -register_diagnostics! { +; // E0153, unused error code // E0157, unused error code // E0257, @@ -1670,7 +1735,6 @@ register_diagnostics! { // E0419, merged into 531 // E0420, merged into 532 // E0421, merged into 531 - E0531, // unresolved pattern path kind `name` // E0427, merged into 530 // E0467, removed // E0470, removed diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs new file mode 100644 index 0000000000000..bb9f895c5f39b --- /dev/null +++ b/src/librustc_resolve/late.rs @@ -0,0 +1,2095 @@ +//! "Late resolution" is the pass that resolves most of names in a crate beside imports and macros. +//! It runs when the crate is fully expanded and its module structure is fully built. +//! So it just walks through the crate and resolves all the expressions, types, etc. +//! +//! If you wonder why there's no `early.rs`, that's because it's split into three files - +//! `build_reduced_graph.rs`, `macros.rs` and `resolve_imports.rs`. + +use RibKind::*; + +use crate::{path_names_to_string, BindingError, CrateLint, LexicalScopeBinding}; +use crate::{Module, ModuleOrUniformRoot, NameBindingKind, ParentScope, PathResult}; +use crate::{ResolutionError, Resolver, Segment, UseError}; + +use log::debug; +use rustc::{bug, lint, span_bug}; +use rustc::hir::def::{self, PartialRes, DefKind, CtorKind, PerNS}; +use rustc::hir::def::Namespace::{self, *}; +use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc::hir::TraitCandidate; +use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use smallvec::{smallvec, SmallVec}; +use syntax::{unwrap_or, walk_list}; +use syntax::ast::*; +use syntax::ptr::P; +use syntax::symbol::{kw, sym}; +use syntax::util::lev_distance::find_best_match_for_name; +use syntax::visit::{self, Visitor, FnKind}; +use syntax_pos::Span; + +use std::collections::BTreeSet; +use std::mem::replace; + +mod diagnostics; + +type Res = def::Res; + +type IdentMap = FxHashMap; + +/// Map from the name in a pattern to its binding mode. +type BindingMap = IdentMap; + +#[derive(Copy, Clone, Debug)] +struct BindingInfo { + span: Span, + binding_mode: BindingMode, +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum PatternSource { + Match, + Let, + For, + FnParam, +} + +impl PatternSource { + fn descr(self) -> &'static str { + match self { + PatternSource::Match => "match binding", + PatternSource::Let => "let binding", + PatternSource::For => "for binding", + PatternSource::FnParam => "function parameter", + } + } +} + +/// Denotes whether the context for the set of already bound bindings is a `Product` +/// or `Or` context. This is used in e.g., `fresh_binding` and `resolve_pattern_inner`. +/// See those functions for more information. +enum PatBoundCtx { + /// A product pattern context, e.g., `Variant(a, b)`. + Product, + /// An or-pattern context, e.g., `p_0 | ... | p_n`. + Or, +} + +/// Does this the item (from the item rib scope) allow generic parameters? +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +crate enum HasGenericParams { Yes, No } + +/// The rib kind restricts certain accesses, +/// e.g. to a `Res::Local` of an outer item. +#[derive(Copy, Clone, Debug)] +crate enum RibKind<'a> { + /// No restriction needs to be applied. + NormalRibKind, + + /// We passed through an impl or trait and are now in one of its + /// methods or associated types. Allow references to ty params that impl or trait + /// binds. Disallow any other upvars (including other ty params that are + /// upvars). + AssocItemRibKind, + + /// We passed through a function definition. Disallow upvars. + /// Permit only those const parameters that are specified in the function's generics. + FnItemRibKind, + + /// We passed through an item scope. Disallow upvars. + ItemRibKind(HasGenericParams), + + /// We're in a constant item. Can't refer to dynamic stuff. + ConstantItemRibKind, + + /// We passed through a module. + ModuleRibKind(Module<'a>), + + /// We passed through a `macro_rules!` statement + MacroDefinition(DefId), + + /// All bindings in this rib are type parameters that can't be used + /// from the default of a type parameter because they're not declared + /// before said type parameter. Also see the `visit_generics` override. + ForwardTyParamBanRibKind, + + /// We forbid the use of type parameters as the types of const parameters. + TyParamAsConstParamTy, +} + +impl RibKind<'_> { + // Whether this rib kind contains generic parameters, as opposed to local + // variables. + crate fn contains_params(&self) -> bool { + match self { + NormalRibKind + | FnItemRibKind + | ConstantItemRibKind + | ModuleRibKind(_) + | MacroDefinition(_) => false, + AssocItemRibKind + | ItemRibKind(_) + | ForwardTyParamBanRibKind + | TyParamAsConstParamTy => true, + } + } +} + +/// A single local scope. +/// +/// A rib represents a scope names can live in. Note that these appear in many places, not just +/// around braces. At any place where the list of accessible names (of the given namespace) +/// changes or a new restrictions on the name accessibility are introduced, a new rib is put onto a +/// stack. This may be, for example, a `let` statement (because it introduces variables), a macro, +/// etc. +/// +/// Different [rib kinds](enum.RibKind) are transparent for different names. +/// +/// The resolution keeps a separate stack of ribs as it traverses the AST for each namespace. When +/// resolving, the name is looked up from inside out. +#[derive(Debug)] +crate struct Rib<'a, R = Res> { + pub bindings: IdentMap, + pub kind: RibKind<'a>, +} + +impl<'a, R> Rib<'a, R> { + fn new(kind: RibKind<'a>) -> Rib<'a, R> { + Rib { + bindings: Default::default(), + kind, + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +crate enum AliasPossibility { + No, + Maybe, +} + +#[derive(Copy, Clone, Debug)] +crate enum PathSource<'a> { + // Type paths `Path`. + Type, + // Trait paths in bounds or impls. + Trait(AliasPossibility), + // Expression paths `path`, with optional parent context. + Expr(Option<&'a Expr>), + // Paths in path patterns `Path`. + Pat, + // Paths in struct expressions and patterns `Path { .. }`. + Struct, + // Paths in tuple struct patterns `Path(..)`. + TupleStruct, + // `m::A::B` in `::B::C`. + TraitItem(Namespace), +} + +impl<'a> PathSource<'a> { + fn namespace(self) -> Namespace { + match self { + PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS, + PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS, + PathSource::TraitItem(ns) => ns, + } + } + + fn defer_to_typeck(self) -> bool { + match self { + PathSource::Type | PathSource::Expr(..) | PathSource::Pat | + PathSource::Struct | PathSource::TupleStruct => true, + PathSource::Trait(_) | PathSource::TraitItem(..) => false, + } + } + + fn descr_expected(self) -> &'static str { + match self { + PathSource::Type => "type", + PathSource::Trait(_) => "trait", + PathSource::Pat => "unit struct/variant or constant", + PathSource::Struct => "struct, variant or union type", + PathSource::TupleStruct => "tuple struct/variant", + PathSource::TraitItem(ns) => match ns { + TypeNS => "associated type", + ValueNS => "method or associated constant", + MacroNS => bug!("associated macro"), + }, + PathSource::Expr(parent) => match parent.map(|p| &p.kind) { + // "function" here means "anything callable" rather than `DefKind::Fn`, + // this is not precise but usually more helpful than just "value". + Some(&ExprKind::Call(..)) => "function", + _ => "value", + }, + } + } + + crate fn is_expected(self, res: Res) -> bool { + match self { + PathSource::Type => match res { + Res::Def(DefKind::Struct, _) + | Res::Def(DefKind::Union, _) + | Res::Def(DefKind::Enum, _) + | Res::Def(DefKind::Trait, _) + | Res::Def(DefKind::TraitAlias, _) + | Res::Def(DefKind::TyAlias, _) + | Res::Def(DefKind::AssocTy, _) + | Res::PrimTy(..) + | Res::Def(DefKind::TyParam, _) + | Res::SelfTy(..) + | Res::Def(DefKind::OpaqueTy, _) + | Res::Def(DefKind::ForeignTy, _) => true, + _ => false, + }, + PathSource::Trait(AliasPossibility::No) => match res { + Res::Def(DefKind::Trait, _) => true, + _ => false, + }, + PathSource::Trait(AliasPossibility::Maybe) => match res { + Res::Def(DefKind::Trait, _) => true, + Res::Def(DefKind::TraitAlias, _) => true, + _ => false, + }, + PathSource::Expr(..) => match res { + Res::Def(DefKind::Ctor(_, CtorKind::Const), _) + | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) + | Res::Def(DefKind::Const, _) + | Res::Def(DefKind::Static, _) + | Res::Local(..) + | Res::Def(DefKind::Fn, _) + | Res::Def(DefKind::Method, _) + | Res::Def(DefKind::AssocConst, _) + | Res::SelfCtor(..) + | Res::Def(DefKind::ConstParam, _) => true, + _ => false, + }, + PathSource::Pat => match res { + Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | + Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) | + Res::SelfCtor(..) => true, + _ => false, + }, + PathSource::TupleStruct => match res { + Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => true, + _ => false, + }, + PathSource::Struct => match res { + Res::Def(DefKind::Struct, _) + | Res::Def(DefKind::Union, _) + | Res::Def(DefKind::Variant, _) + | Res::Def(DefKind::TyAlias, _) + | Res::Def(DefKind::AssocTy, _) + | Res::SelfTy(..) => true, + _ => false, + }, + PathSource::TraitItem(ns) => match res { + Res::Def(DefKind::AssocConst, _) + | Res::Def(DefKind::Method, _) if ns == ValueNS => true, + Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true, + _ => false, + }, + } + } + + fn error_code(self, has_unexpected_resolution: bool) -> &'static str { + syntax::diagnostic_used!(E0404); + syntax::diagnostic_used!(E0405); + syntax::diagnostic_used!(E0412); + syntax::diagnostic_used!(E0422); + syntax::diagnostic_used!(E0423); + syntax::diagnostic_used!(E0425); + syntax::diagnostic_used!(E0531); + syntax::diagnostic_used!(E0532); + syntax::diagnostic_used!(E0573); + syntax::diagnostic_used!(E0574); + syntax::diagnostic_used!(E0575); + syntax::diagnostic_used!(E0576); + match (self, has_unexpected_resolution) { + (PathSource::Trait(_), true) => "E0404", + (PathSource::Trait(_), false) => "E0405", + (PathSource::Type, true) => "E0573", + (PathSource::Type, false) => "E0412", + (PathSource::Struct, true) => "E0574", + (PathSource::Struct, false) => "E0422", + (PathSource::Expr(..), true) => "E0423", + (PathSource::Expr(..), false) => "E0425", + (PathSource::Pat, true) | (PathSource::TupleStruct, true) => "E0532", + (PathSource::Pat, false) | (PathSource::TupleStruct, false) => "E0531", + (PathSource::TraitItem(..), true) => "E0575", + (PathSource::TraitItem(..), false) => "E0576", + } + } +} + +struct LateResolutionVisitor<'a, 'b> { + r: &'b mut Resolver<'a>, + + /// The module that represents the current item scope. + parent_scope: ParentScope<'a>, + + /// The current set of local scopes for types and values. + /// FIXME #4948: Reuse ribs to avoid allocation. + ribs: PerNS>>, + + /// The current set of local scopes, for labels. + label_ribs: Vec>, + + /// The trait that the current context can refer to. + current_trait_ref: Option<(Module<'a>, TraitRef)>, + + /// The current trait's associated types' ident, used for diagnostic suggestions. + current_trait_assoc_types: Vec, + + /// The current self type if inside an impl (used for better errors). + current_self_type: Option, + + /// The current self item if inside an ADT (used for better errors). + current_self_item: Option, + + /// A list of labels as of yet unused. Labels will be removed from this map when + /// they are used (in a `break` or `continue` statement) + unused_labels: FxHashMap, + + /// Only used for better errors on `fn(): fn()`. + current_type_ascription: Vec, +} + +/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes. +impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> { + fn visit_item(&mut self, item: &'tcx Item) { + self.resolve_item(item); + } + fn visit_arm(&mut self, arm: &'tcx Arm) { + self.resolve_arm(arm); + } + fn visit_block(&mut self, block: &'tcx Block) { + self.resolve_block(block); + } + fn visit_anon_const(&mut self, constant: &'tcx AnonConst) { + debug!("visit_anon_const {:?}", constant); + self.with_constant_rib(|this| { + visit::walk_anon_const(this, constant); + }); + } + fn visit_expr(&mut self, expr: &'tcx Expr) { + self.resolve_expr(expr, None); + } + fn visit_local(&mut self, local: &'tcx Local) { + self.resolve_local(local); + } + fn visit_ty(&mut self, ty: &'tcx Ty) { + match ty.kind { + TyKind::Path(ref qself, ref path) => { + self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type); + } + TyKind::ImplicitSelf => { + let self_ty = Ident::with_dummy_span(kw::SelfUpper); + let res = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.id), ty.span) + .map_or(Res::Err, |d| d.res()); + self.r.record_partial_res(ty.id, PartialRes::new(res)); + } + _ => (), + } + visit::walk_ty(self, ty); + } + fn visit_poly_trait_ref(&mut self, + tref: &'tcx PolyTraitRef, + m: &'tcx TraitBoundModifier) { + self.smart_resolve_path(tref.trait_ref.ref_id, None, + &tref.trait_ref.path, PathSource::Trait(AliasPossibility::Maybe)); + visit::walk_poly_trait_ref(self, tref, m); + } + fn visit_foreign_item(&mut self, foreign_item: &'tcx ForeignItem) { + match foreign_item.kind { + ForeignItemKind::Fn(_, ref generics) => { + self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { + visit::walk_foreign_item(this, foreign_item); + }); + } + ForeignItemKind::Static(..) => { + self.with_item_rib(HasGenericParams::No, |this| { + visit::walk_foreign_item(this, foreign_item); + }); + } + ForeignItemKind::Ty | ForeignItemKind::Macro(..) => { + visit::walk_foreign_item(self, foreign_item); + } + } + } + fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, declaration: &'tcx FnDecl, _: Span, _: NodeId) { + debug!("(resolving function) entering function"); + let rib_kind = match fn_kind { + FnKind::ItemFn(..) => FnItemRibKind, + FnKind::Method(..) | FnKind::Closure(_) => NormalRibKind, + }; + + // Create a value rib for the function. + self.with_rib(ValueNS, rib_kind, |this| { + // Create a label rib for the function. + this.with_label_rib(rib_kind, |this| { + // Add each argument to the rib. + this.resolve_params(&declaration.inputs); + + visit::walk_fn_ret_ty(this, &declaration.output); + + // Resolve the function body, potentially inside the body of an async closure + match fn_kind { + FnKind::ItemFn(.., body) | + FnKind::Method(.., body) => this.visit_block(body), + FnKind::Closure(body) => this.visit_expr(body), + }; + + debug!("(resolving function) leaving function"); + }) + }); + } + + fn visit_generics(&mut self, generics: &'tcx Generics) { + // For type parameter defaults, we have to ban access + // to following type parameters, as the InternalSubsts can only + // provide previous type parameters as they're built. We + // put all the parameters on the ban list and then remove + // them one by one as they are processed and become available. + let mut default_ban_rib = Rib::new(ForwardTyParamBanRibKind); + let mut found_default = false; + default_ban_rib.bindings.extend(generics.params.iter() + .filter_map(|param| match param.kind { + GenericParamKind::Const { .. } | + GenericParamKind::Lifetime { .. } => None, + GenericParamKind::Type { ref default, .. } => { + found_default |= default.is_some(); + if found_default { + Some((Ident::with_dummy_span(param.ident.name), Res::Err)) + } else { + None + } + } + })); + + // rust-lang/rust#61631: The type `Self` is essentially + // another type parameter. For ADTs, we consider it + // well-defined only after all of the ADT type parameters have + // been provided. Therefore, we do not allow use of `Self` + // anywhere in ADT type parameter defaults. + // + // (We however cannot ban `Self` for defaults on *all* generic + // lists; e.g. trait generics can usefully refer to `Self`, + // such as in the case of `trait Add`.) + if self.current_self_item.is_some() { // (`Some` if + only if we are in ADT's generics.) + default_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err); + } + + // We also ban access to type parameters for use as the types of const parameters. + let mut const_ty_param_ban_rib = Rib::new(TyParamAsConstParamTy); + const_ty_param_ban_rib.bindings.extend(generics.params.iter() + .filter(|param| { + if let GenericParamKind::Type { .. } = param.kind { + true + } else { + false + } + }) + .map(|param| (Ident::with_dummy_span(param.ident.name), Res::Err))); + + for param in &generics.params { + match param.kind { + GenericParamKind::Lifetime { .. } => self.visit_generic_param(param), + GenericParamKind::Type { ref default, .. } => { + for bound in ¶m.bounds { + self.visit_param_bound(bound); + } + + if let Some(ref ty) = default { + self.ribs[TypeNS].push(default_ban_rib); + self.visit_ty(ty); + default_ban_rib = self.ribs[TypeNS].pop().unwrap(); + } + + // Allow all following defaults to refer to this type parameter. + default_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name)); + } + GenericParamKind::Const { ref ty } => { + self.ribs[TypeNS].push(const_ty_param_ban_rib); + + for bound in ¶m.bounds { + self.visit_param_bound(bound); + } + + self.visit_ty(ty); + + const_ty_param_ban_rib = self.ribs[TypeNS].pop().unwrap(); + } + } + } + for p in &generics.where_clause.predicates { + self.visit_where_predicate(p); + } + } +} + +impl<'a, 'b> LateResolutionVisitor<'a, '_> { + fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b> { + // During late resolution we only track the module component of the parent scope, + // although it may be useful to track other components as well for diagnostics. + let graph_root = resolver.graph_root; + let parent_scope = ParentScope::module(graph_root); + let start_rib_kind = ModuleRibKind(graph_root); + LateResolutionVisitor { + r: resolver, + parent_scope, + ribs: PerNS { + value_ns: vec![Rib::new(start_rib_kind)], + type_ns: vec![Rib::new(start_rib_kind)], + macro_ns: vec![Rib::new(start_rib_kind)], + }, + label_ribs: Vec::new(), + current_trait_ref: None, + current_trait_assoc_types: Vec::new(), + current_self_type: None, + current_self_item: None, + unused_labels: Default::default(), + current_type_ascription: Vec::new(), + } + } + + fn resolve_ident_in_lexical_scope(&mut self, + ident: Ident, + ns: Namespace, + record_used_id: Option, + path_span: Span) + -> Option> { + self.r.resolve_ident_in_lexical_scope( + ident, ns, &self.parent_scope, record_used_id, path_span, &self.ribs[ns] + ) + } + + fn resolve_path( + &mut self, + path: &[Segment], + opt_ns: Option, // `None` indicates a module path in import + record_used: bool, + path_span: Span, + crate_lint: CrateLint, + ) -> PathResult<'a> { + self.r.resolve_path_with_ribs( + path, opt_ns, &self.parent_scope, record_used, path_span, crate_lint, Some(&self.ribs) + ) + } + + // AST resolution + // + // We maintain a list of value ribs and type ribs. + // + // Simultaneously, we keep track of the current position in the module + // graph in the `parent_scope.module` pointer. When we go to resolve a name in + // the value or type namespaces, we first look through all the ribs and + // then query the module graph. When we resolve a name in the module + // namespace, we can skip all the ribs (since nested modules are not + // allowed within blocks in Rust) and jump straight to the current module + // graph node. + // + // Named implementations are handled separately. When we find a method + // call, we consult the module node to find all of the implementations in + // scope. This information is lazily cached in the module node. We then + // generate a fake "implementation scope" containing all the + // implementations thus found, for compatibility with old resolve pass. + + /// Do some `work` within a new innermost rib of the given `kind` in the given namespace (`ns`). + fn with_rib( + &mut self, + ns: Namespace, + kind: RibKind<'a>, + work: impl FnOnce(&mut Self) -> T, + ) -> T { + self.ribs[ns].push(Rib::new(kind)); + let ret = work(self); + self.ribs[ns].pop(); + ret + } + + fn with_scope(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { + let id = self.r.definitions.local_def_id(id); + let module = self.r.module_map.get(&id).cloned(); // clones a reference + if let Some(module) = module { + // Move down in the graph. + let orig_module = replace(&mut self.parent_scope.module, module); + self.with_rib(ValueNS, ModuleRibKind(module), |this| { + this.with_rib(TypeNS, ModuleRibKind(module), |this| { + let ret = f(this); + this.parent_scope.module = orig_module; + ret + }) + }) + } else { + f(self) + } + } + + /// Searches the current set of local scopes for labels. Returns the first non-`None` label that + /// is returned by the given predicate function + /// + /// Stops after meeting a closure. + fn search_label(&self, mut ident: Ident, pred: P) -> Option + where P: Fn(&Rib<'_, NodeId>, Ident) -> Option + { + for rib in self.label_ribs.iter().rev() { + match rib.kind { + NormalRibKind => {} + // If an invocation of this macro created `ident`, give up on `ident` + // and switch to `ident`'s source from the macro definition. + MacroDefinition(def) => { + if def == self.r.macro_def(ident.span.ctxt()) { + ident.span.remove_mark(); + } + } + _ => { + // Do not resolve labels across function boundary + return None; + } + } + let r = pred(rib, ident); + if r.is_some() { + return r; + } + } + None + } + + fn resolve_adt(&mut self, item: &Item, generics: &Generics) { + debug!("resolve_adt"); + self.with_current_self_item(item, |this| { + this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { + let item_def_id = this.r.definitions.local_def_id(item.id); + this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| { + visit::walk_item(this, item); + }); + }); + }); + } + + fn future_proof_import(&mut self, use_tree: &UseTree) { + let segments = &use_tree.prefix.segments; + if !segments.is_empty() { + let ident = segments[0].ident; + if ident.is_path_segment_keyword() || ident.span.rust_2015() { + return; + } + + let nss = match use_tree.kind { + UseTreeKind::Simple(..) if segments.len() == 1 => &[TypeNS, ValueNS][..], + _ => &[TypeNS], + }; + let report_error = |this: &Self, ns| { + let what = if ns == TypeNS { "type parameters" } else { "local variables" }; + this.r.session.span_err(ident.span, &format!("imports cannot refer to {}", what)); + }; + + for &ns in nss { + match self.resolve_ident_in_lexical_scope(ident, ns, None, use_tree.prefix.span) { + Some(LexicalScopeBinding::Res(..)) => { + report_error(self, ns); + } + Some(LexicalScopeBinding::Item(binding)) => { + let orig_blacklisted_binding = + replace(&mut self.r.blacklisted_binding, Some(binding)); + if let Some(LexicalScopeBinding::Res(..)) = + self.resolve_ident_in_lexical_scope(ident, ns, None, + use_tree.prefix.span) { + report_error(self, ns); + } + self.r.blacklisted_binding = orig_blacklisted_binding; + } + None => {} + } + } + } else if let UseTreeKind::Nested(use_trees) = &use_tree.kind { + for (use_tree, _) in use_trees { + self.future_proof_import(use_tree); + } + } + } + + fn resolve_item(&mut self, item: &Item) { + let name = item.ident.name; + debug!("(resolving item) resolving {} ({:?})", name, item.kind); + + match item.kind { + ItemKind::TyAlias(_, ref generics) | + ItemKind::OpaqueTy(_, ref generics) | + ItemKind::Fn(_, _, ref generics, _) => { + self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), + |this| visit::walk_item(this, item)); + } + + ItemKind::Enum(_, ref generics) | + ItemKind::Struct(_, ref generics) | + ItemKind::Union(_, ref generics) => { + self.resolve_adt(item, generics); + } + + ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) => + self.resolve_implementation(generics, + opt_trait_ref, + &self_type, + item.id, + impl_items), + + ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => { + // Create a new rib for the trait-wide type parameters. + self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { + let local_def_id = this.r.definitions.local_def_id(item.id); + this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| { + this.visit_generics(generics); + walk_list!(this, visit_param_bound, bounds); + + for trait_item in trait_items { + this.with_trait_items(trait_items, |this| { + this.with_generic_param_rib(&trait_item.generics, AssocItemRibKind, + |this| { + match trait_item.kind { + TraitItemKind::Const(ref ty, ref default) => { + this.visit_ty(ty); + + // Only impose the restrictions of + // ConstRibKind for an actual constant + // expression in a provided default. + if let Some(ref expr) = *default{ + this.with_constant_rib(|this| { + this.visit_expr(expr); + }); + } + } + TraitItemKind::Method(_, _) => { + visit::walk_trait_item(this, trait_item) + } + TraitItemKind::Type(..) => { + visit::walk_trait_item(this, trait_item) + } + TraitItemKind::Macro(_) => { + panic!("unexpanded macro in resolve!") + } + }; + }); + }); + } + }); + }); + } + + ItemKind::TraitAlias(ref generics, ref bounds) => { + // Create a new rib for the trait-wide type parameters. + self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { + let local_def_id = this.r.definitions.local_def_id(item.id); + this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| { + this.visit_generics(generics); + walk_list!(this, visit_param_bound, bounds); + }); + }); + } + + ItemKind::Mod(_) | ItemKind::ForeignMod(_) => { + self.with_scope(item.id, |this| { + visit::walk_item(this, item); + }); + } + + ItemKind::Static(ref ty, _, ref expr) | + ItemKind::Const(ref ty, ref expr) => { + debug!("resolve_item ItemKind::Const"); + self.with_item_rib(HasGenericParams::No, |this| { + this.visit_ty(ty); + this.with_constant_rib(|this| { + this.visit_expr(expr); + }); + }); + } + + ItemKind::Use(ref use_tree) => { + self.future_proof_import(use_tree); + } + + ItemKind::ExternCrate(..) | + ItemKind::MacroDef(..) | ItemKind::GlobalAsm(..) => { + // do nothing, these are just around to be encoded + } + + ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"), + } + } + + fn with_generic_param_rib<'c, F>(&'c mut self, generics: &'c Generics, kind: RibKind<'a>, f: F) + where F: FnOnce(&mut Self) + { + debug!("with_generic_param_rib"); + let mut function_type_rib = Rib::new(kind); + let mut function_value_rib = Rib::new(kind); + let mut seen_bindings = FxHashMap::default(); + + // We also can't shadow bindings from the parent item + if let AssocItemRibKind = kind { + let mut add_bindings_for_ns = |ns| { + let parent_rib = self.ribs[ns].iter() + .rfind(|r| if let ItemRibKind(_) = r.kind { true } else { false }) + .expect("associated item outside of an item"); + seen_bindings.extend( + parent_rib.bindings.iter().map(|(ident, _)| (*ident, ident.span)), + ); + }; + add_bindings_for_ns(ValueNS); + add_bindings_for_ns(TypeNS); + } + + for param in &generics.params { + if let GenericParamKind::Lifetime { .. } = param.kind { + continue; + } + + let def_kind = match param.kind { + GenericParamKind::Type { .. } => DefKind::TyParam, + GenericParamKind::Const { .. } => DefKind::ConstParam, + _ => unreachable!(), + }; + + let ident = param.ident.modern(); + debug!("with_generic_param_rib: {}", param.id); + + if seen_bindings.contains_key(&ident) { + let span = seen_bindings.get(&ident).unwrap(); + let err = ResolutionError::NameAlreadyUsedInParameterList( + ident.name, + *span, + ); + self.r.report_error(param.ident.span, err); + } + seen_bindings.entry(ident).or_insert(param.ident.span); + + // Plain insert (no renaming). + let res = Res::Def(def_kind, self.r.definitions.local_def_id(param.id)); + + match param.kind { + GenericParamKind::Type { .. } => { + function_type_rib.bindings.insert(ident, res); + self.r.record_partial_res(param.id, PartialRes::new(res)); + } + GenericParamKind::Const { .. } => { + function_value_rib.bindings.insert(ident, res); + self.r.record_partial_res(param.id, PartialRes::new(res)); + } + _ => unreachable!(), + } + } + + self.ribs[ValueNS].push(function_value_rib); + self.ribs[TypeNS].push(function_type_rib); + + f(self); + + self.ribs[TypeNS].pop(); + self.ribs[ValueNS].pop(); + } + + fn with_label_rib(&mut self, kind: RibKind<'a>, f: impl FnOnce(&mut Self)) { + self.label_ribs.push(Rib::new(kind)); + f(self); + self.label_ribs.pop(); + } + + fn with_item_rib(&mut self, has_generic_params: HasGenericParams, f: impl FnOnce(&mut Self)) { + let kind = ItemRibKind(has_generic_params); + self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f)) + } + + fn with_constant_rib(&mut self, f: impl FnOnce(&mut Self)) { + debug!("with_constant_rib"); + self.with_rib(ValueNS, ConstantItemRibKind, |this| { + this.with_label_rib(ConstantItemRibKind, f); + }); + } + + fn with_current_self_type(&mut self, self_type: &Ty, f: impl FnOnce(&mut Self) -> T) -> T { + // Handle nested impls (inside fn bodies) + let previous_value = replace(&mut self.current_self_type, Some(self_type.clone())); + let result = f(self); + self.current_self_type = previous_value; + result + } + + fn with_current_self_item(&mut self, self_item: &Item, f: impl FnOnce(&mut Self) -> T) -> T { + let previous_value = replace(&mut self.current_self_item, Some(self_item.id)); + let result = f(self); + self.current_self_item = previous_value; + result + } + + /// When evaluating a `trait` use its associated types' idents for suggestionsa in E0412. + fn with_trait_items( + &mut self, + trait_items: &Vec, + f: impl FnOnce(&mut Self) -> T, + ) -> T { + let trait_assoc_types = replace( + &mut self.current_trait_assoc_types, + trait_items.iter().filter_map(|item| match &item.kind { + TraitItemKind::Type(bounds, _) if bounds.len() == 0 => Some(item.ident), + _ => None, + }).collect(), + ); + let result = f(self); + self.current_trait_assoc_types = trait_assoc_types; + result + } + + /// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`). + fn with_optional_trait_ref( + &mut self, + opt_trait_ref: Option<&TraitRef>, + f: impl FnOnce(&mut Self, Option) -> T + ) -> T { + let mut new_val = None; + let mut new_id = None; + if let Some(trait_ref) = opt_trait_ref { + let path: Vec<_> = Segment::from_path(&trait_ref.path); + let res = self.smart_resolve_path_fragment( + trait_ref.ref_id, + None, + &path, + trait_ref.path.span, + PathSource::Trait(AliasPossibility::No), + CrateLint::SimplePath(trait_ref.ref_id), + ).base_res(); + if res != Res::Err { + new_id = Some(res.def_id()); + let span = trait_ref.path.span; + if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = + self.resolve_path( + &path, + Some(TypeNS), + false, + span, + CrateLint::SimplePath(trait_ref.ref_id), + ) + { + new_val = Some((module, trait_ref.clone())); + } + } + } + let original_trait_ref = replace(&mut self.current_trait_ref, new_val); + let result = f(self, new_id); + self.current_trait_ref = original_trait_ref; + result + } + + fn with_self_rib_ns(&mut self, ns: Namespace, self_res: Res, f: impl FnOnce(&mut Self)) { + let mut self_type_rib = Rib::new(NormalRibKind); + + // Plain insert (no renaming, since types are not currently hygienic) + self_type_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), self_res); + self.ribs[ns].push(self_type_rib); + f(self); + self.ribs[ns].pop(); + } + + fn with_self_rib(&mut self, self_res: Res, f: impl FnOnce(&mut Self)) { + self.with_self_rib_ns(TypeNS, self_res, f) + } + + fn resolve_implementation(&mut self, + generics: &Generics, + opt_trait_reference: &Option, + self_type: &Ty, + item_id: NodeId, + impl_items: &[ImplItem]) { + debug!("resolve_implementation"); + // If applicable, create a rib for the type parameters. + self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { + // Dummy self type for better errors if `Self` is used in the trait path. + this.with_self_rib(Res::SelfTy(None, None), |this| { + // Resolve the trait reference, if necessary. + this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| { + let item_def_id = this.r.definitions.local_def_id(item_id); + this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| { + if let Some(trait_ref) = opt_trait_reference.as_ref() { + // Resolve type arguments in the trait path. + visit::walk_trait_ref(this, trait_ref); + } + // Resolve the self type. + this.visit_ty(self_type); + // Resolve the generic parameters. + this.visit_generics(generics); + // Resolve the items within the impl. + this.with_current_self_type(self_type, |this| { + this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| { + debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); + for impl_item in impl_items { + // We also need a new scope for the impl item type parameters. + this.with_generic_param_rib(&impl_item.generics, + AssocItemRibKind, + |this| { + use crate::ResolutionError::*; + match impl_item.kind { + ImplItemKind::Const(..) => { + debug!( + "resolve_implementation ImplItemKind::Const", + ); + // If this is a trait impl, ensure the const + // exists in trait + this.check_trait_item( + impl_item.ident, + ValueNS, + impl_item.span, + |n, s| ConstNotMemberOfTrait(n, s), + ); + + this.with_constant_rib(|this| { + visit::walk_impl_item(this, impl_item) + }); + } + ImplItemKind::Method(..) => { + // If this is a trait impl, ensure the method + // exists in trait + this.check_trait_item(impl_item.ident, + ValueNS, + impl_item.span, + |n, s| MethodNotMemberOfTrait(n, s)); + + visit::walk_impl_item(this, impl_item); + } + ImplItemKind::TyAlias(ref ty) => { + // If this is a trait impl, ensure the type + // exists in trait + this.check_trait_item(impl_item.ident, + TypeNS, + impl_item.span, + |n, s| TypeNotMemberOfTrait(n, s)); + + this.visit_ty(ty); + } + ImplItemKind::OpaqueTy(ref bounds) => { + // If this is a trait impl, ensure the type + // exists in trait + this.check_trait_item(impl_item.ident, + TypeNS, + impl_item.span, + |n, s| TypeNotMemberOfTrait(n, s)); + + for bound in bounds { + this.visit_param_bound(bound); + } + } + ImplItemKind::Macro(_) => + panic!("unexpanded macro in resolve!"), + } + }); + } + }); + }); + }); + }); + }); + }); + } + + fn check_trait_item(&mut self, ident: Ident, ns: Namespace, span: Span, err: F) + where F: FnOnce(Name, &str) -> ResolutionError<'_> + { + // If there is a TraitRef in scope for an impl, then the method must be in the + // trait. + if let Some((module, _)) = self.current_trait_ref { + if self.r.resolve_ident_in_module( + ModuleOrUniformRoot::Module(module), + ident, + ns, + &self.parent_scope, + false, + span, + ).is_err() { + let path = &self.current_trait_ref.as_ref().unwrap().1.path; + self.r.report_error(span, err(ident.name, &path_names_to_string(path))); + } + } + } + + fn resolve_params(&mut self, params: &[Param]) { + let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; + for Param { pat, ty, .. } in params { + self.resolve_pattern(pat, PatternSource::FnParam, &mut bindings); + self.visit_ty(ty); + debug!("(resolving function / closure) recorded parameter"); + } + } + + fn resolve_local(&mut self, local: &Local) { + // Resolve the type. + walk_list!(self, visit_ty, &local.ty); + + // Resolve the initializer. + walk_list!(self, visit_expr, &local.init); + + // Resolve the pattern. + self.resolve_pattern_top(&local.pat, PatternSource::Let); + } + + /// build a map from pattern identifiers to binding-info's. + /// this is done hygienically. This could arise for a macro + /// that expands into an or-pattern where one 'x' was from the + /// user and one 'x' came from the macro. + fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap { + let mut binding_map = FxHashMap::default(); + + pat.walk(&mut |pat| { + match pat.kind { + PatKind::Ident(binding_mode, ident, ref sub_pat) + if sub_pat.is_some() || self.is_base_res_local(pat.id) => + { + binding_map.insert(ident, BindingInfo { span: ident.span, binding_mode }); + } + PatKind::Or(ref ps) => { + // Check the consistency of this or-pattern and + // then add all bindings to the larger map. + for bm in self.check_consistent_bindings(ps) { + binding_map.extend(bm); + } + return false; + } + _ => {} + } + + true + }); + + binding_map + } + + fn is_base_res_local(&self, nid: NodeId) -> bool { + match self.r.partial_res_map.get(&nid).map(|res| res.base_res()) { + Some(Res::Local(..)) => true, + _ => false, + } + } + + /// Checks that all of the arms in an or-pattern have exactly the + /// same set of bindings, with the same binding modes for each. + fn check_consistent_bindings(&mut self, pats: &[P]) -> Vec { + let mut missing_vars = FxHashMap::default(); + let mut inconsistent_vars = FxHashMap::default(); + + // 1) Compute the binding maps of all arms. + let maps = pats.iter() + .map(|pat| self.binding_mode_map(pat)) + .collect::>(); + + // 2) Record any missing bindings or binding mode inconsistencies. + for (map_outer, pat_outer) in pats.iter().enumerate().map(|(idx, pat)| (&maps[idx], pat)) { + // Check against all arms except for the same pattern which is always self-consistent. + let inners = pats.iter().enumerate() + .filter(|(_, pat)| pat.id != pat_outer.id) + .flat_map(|(idx, _)| maps[idx].iter()) + .map(|(key, binding)| (key.name, map_outer.get(&key), binding)); + + for (name, info, &binding_inner) in inners { + match info { + None => { // The inner binding is missing in the outer. + let binding_error = missing_vars + .entry(name) + .or_insert_with(|| BindingError { + name, + origin: BTreeSet::new(), + target: BTreeSet::new(), + could_be_path: name.as_str().starts_with(char::is_uppercase), + }); + binding_error.origin.insert(binding_inner.span); + binding_error.target.insert(pat_outer.span); + } + Some(binding_outer) => { + if binding_outer.binding_mode != binding_inner.binding_mode { + // The binding modes in the outer and inner bindings differ. + inconsistent_vars + .entry(name) + .or_insert((binding_inner.span, binding_outer.span)); + } + } + } + } + } + + // 3) Report all missing variables we found. + let mut missing_vars = missing_vars.iter_mut().collect::>(); + missing_vars.sort(); + for (name, mut v) in missing_vars { + if inconsistent_vars.contains_key(name) { + v.could_be_path = false; + } + self.r.report_error( + *v.origin.iter().next().unwrap(), + ResolutionError::VariableNotBoundInPattern(v)); + } + + // 4) Report all inconsistencies in binding modes we found. + let mut inconsistent_vars = inconsistent_vars.iter().collect::>(); + inconsistent_vars.sort(); + for (name, v) in inconsistent_vars { + self.r.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1)); + } + + // 5) Finally bubble up all the binding maps. + maps + } + + /// Check the consistency of the outermost or-patterns. + fn check_consistent_bindings_top(&mut self, pat: &Pat) { + pat.walk(&mut |pat| match pat.kind { + PatKind::Or(ref ps) => { + self.check_consistent_bindings(ps); + false + }, + _ => true, + }) + } + + fn resolve_arm(&mut self, arm: &Arm) { + self.with_rib(ValueNS, NormalRibKind, |this| { + this.resolve_pattern_top(&arm.pat, PatternSource::Match); + walk_list!(this, visit_expr, &arm.guard); + this.visit_expr(&arm.body); + }); + } + + /// Arising from `source`, resolve a top level pattern. + fn resolve_pattern_top(&mut self, pat: &Pat, pat_src: PatternSource) { + let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; + self.resolve_pattern(pat, pat_src, &mut bindings); + } + + fn resolve_pattern( + &mut self, + pat: &Pat, + pat_src: PatternSource, + bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet); 1]>, + ) { + self.resolve_pattern_inner(pat, pat_src, bindings); + // This has to happen *after* we determine which pat_idents are variants: + self.check_consistent_bindings_top(pat); + visit::walk_pat(self, pat); + } + + /// Resolve bindings in a pattern. This is a helper to `resolve_pattern`. + /// + /// ### `bindings` + /// + /// A stack of sets of bindings accumulated. + /// + /// In each set, `PatBoundCtx::Product` denotes that a found binding in it should + /// be interpreted as re-binding an already bound binding. This results in an error. + /// Meanwhile, `PatBound::Or` denotes that a found binding in the set should result + /// in reusing this binding rather than creating a fresh one. + /// + /// When called at the top level, the stack must have a single element + /// with `PatBound::Product`. Otherwise, pushing to the stack happens as + /// or-patterns (`p_0 | ... | p_n`) are encountered and the context needs + /// to be switched to `PatBoundCtx::Or` and then `PatBoundCtx::Product` for each `p_i`. + /// When each `p_i` has been dealt with, the top set is merged with its parent. + /// When a whole or-pattern has been dealt with, the thing happens. + /// + /// See the implementation and `fresh_binding` for more details. + fn resolve_pattern_inner( + &mut self, + pat: &Pat, + pat_src: PatternSource, + bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet); 1]>, + ) { + // Visit all direct subpatterns of this pattern. + pat.walk(&mut |pat| { + debug!("resolve_pattern pat={:?} node={:?}", pat, pat.kind); + match pat.kind { + PatKind::Ident(bmode, ident, ref sub) => { + // First try to resolve the identifier as some existing entity, + // then fall back to a fresh binding. + let has_sub = sub.is_some(); + let res = self.try_resolve_as_non_binding(pat_src, pat, bmode, ident, has_sub) + .unwrap_or_else(|| self.fresh_binding(ident, pat.id, pat_src, bindings)); + self.r.record_partial_res(pat.id, PartialRes::new(res)); + } + PatKind::TupleStruct(ref path, ..) => { + self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct); + } + PatKind::Path(ref qself, ref path) => { + self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat); + } + PatKind::Struct(ref path, ..) => { + self.smart_resolve_path(pat.id, None, path, PathSource::Struct); + } + PatKind::Or(ref ps) => { + // Add a new set of bindings to the stack. `Or` here records that when a + // binding already exists in this set, it should not result in an error because + // `V1(a) | V2(a)` must be allowed and are checked for consistency later. + bindings.push((PatBoundCtx::Or, Default::default())); + for p in ps { + // Now we need to switch back to a product context so that each + // part of the or-pattern internally rejects already bound names. + // For example, `V1(a) | V2(a, a)` and `V1(a, a) | V2(a)` are bad. + bindings.push((PatBoundCtx::Product, Default::default())); + self.resolve_pattern_inner(p, pat_src, bindings); + // Move up the non-overlapping bindings to the or-pattern. + // Existing bindings just get "merged". + let collected = bindings.pop().unwrap().1; + bindings.last_mut().unwrap().1.extend(collected); + } + // This or-pattern itself can itself be part of a product, + // e.g. `(V1(a) | V2(a), a)` or `(a, V1(a) | V2(a))`. + // Both cases bind `a` again in a product pattern and must be rejected. + let collected = bindings.pop().unwrap().1; + bindings.last_mut().unwrap().1.extend(collected); + + // Prevent visiting `ps` as we've already done so above. + return false; + } + _ => {} + } + true + }); + } + + fn fresh_binding( + &mut self, + ident: Ident, + pat_id: NodeId, + pat_src: PatternSource, + bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet); 1]>, + ) -> Res { + // Add the binding to the local ribs, if it doesn't already exist in the bindings map. + // (We must not add it if it's in the bindings map because that breaks the assumptions + // later passes make about or-patterns.) + let ident = ident.modern_and_legacy(); + + // Walk outwards the stack of products / or-patterns and + // find out if the identifier has been bound in any of these. + let mut already_bound_and = false; + let mut already_bound_or = false; + for (is_sum, set) in bindings.iter_mut().rev() { + match (is_sum, set.get(&ident).cloned()) { + // Already bound in a product pattern, e.g. `(a, a)` which is not allowed. + (PatBoundCtx::Product, Some(..)) => already_bound_and = true, + // Already bound in an or-pattern, e.g. `V1(a) | V2(a)`. + // This is *required* for consistency which is checked later. + (PatBoundCtx::Or, Some(..)) => already_bound_or = true, + // Not already bound here. + _ => {} + } + } + + if already_bound_and { + // Overlap in a product pattern somewhere; report an error. + use ResolutionError::*; + let error = match pat_src { + // `fn f(a: u8, a: u8)`: + PatternSource::FnParam => IdentifierBoundMoreThanOnceInParameterList, + // `Variant(a, a)`: + _ => IdentifierBoundMoreThanOnceInSamePattern, + }; + self.r.report_error(ident.span, error(&ident.as_str())); + } + + // Record as bound if it's valid: + let ident_valid = ident.name != kw::Invalid; + if ident_valid { + bindings.last_mut().unwrap().1.insert(ident); + } + + if already_bound_or { + // `Variant1(a) | Variant2(a)`, ok + // Reuse definition from the first `a`. + self.innermost_rib_bindings(ValueNS)[&ident] + } else { + let res = Res::Local(pat_id); + if ident_valid { + // A completely fresh binding add to the set if it's valid. + self.innermost_rib_bindings(ValueNS).insert(ident, res); + } + res + } + } + + fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut IdentMap { + &mut self.ribs[ns].last_mut().unwrap().bindings + } + + fn try_resolve_as_non_binding( + &mut self, + pat_src: PatternSource, + pat: &Pat, + bm: BindingMode, + ident: Ident, + has_sub: bool, + ) -> Option { + let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, pat.span)?.item()?; + let res = binding.res(); + + // An immutable (no `mut`) by-value (no `ref`) binding pattern without + // a sub pattern (no `@ $pat`) is syntactically ambiguous as it could + // also be interpreted as a path to e.g. a constant, variant, etc. + let is_syntactic_ambiguity = !has_sub && bm == BindingMode::ByValue(Mutability::Immutable); + + match res { + Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | + Res::Def(DefKind::Const, _) if is_syntactic_ambiguity => { + // Disambiguate in favor of a unit struct/variant or constant pattern. + self.r.record_use(ident, ValueNS, binding, false); + Some(res) + } + Res::Def(DefKind::Ctor(..), _) + | Res::Def(DefKind::Const, _) + | Res::Def(DefKind::Static, _) => { + // This is unambiguously a fresh binding, either syntactically + // (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves + // to something unusable as a pattern (e.g., constructor function), + // but we still conservatively report an error, see + // issues/33118#issuecomment-233962221 for one reason why. + self.r.report_error( + ident.span, + ResolutionError::BindingShadowsSomethingUnacceptable( + pat_src.descr(), + ident.name, + binding, + ), + ); + None + } + Res::Def(DefKind::Fn, _) | Res::Err => { + // These entities are explicitly allowed to be shadowed by fresh bindings. + None + } + res => { + span_bug!(ident.span, "unexpected resolution for an \ + identifier in pattern: {:?}", res); + } + } + } + + // High-level and context dependent path resolution routine. + // Resolves the path and records the resolution into definition map. + // If resolution fails tries several techniques to find likely + // resolution candidates, suggest imports or other help, and report + // errors in user friendly way. + fn smart_resolve_path(&mut self, + id: NodeId, + qself: Option<&QSelf>, + path: &Path, + source: PathSource<'_>) { + self.smart_resolve_path_fragment( + id, + qself, + &Segment::from_path(path), + path.span, + source, + CrateLint::SimplePath(id), + ); + } + + fn smart_resolve_path_fragment(&mut self, + id: NodeId, + qself: Option<&QSelf>, + path: &[Segment], + span: Span, + source: PathSource<'_>, + crate_lint: CrateLint) + -> PartialRes { + let ns = source.namespace(); + let is_expected = &|res| source.is_expected(res); + + let report_errors = |this: &mut Self, res: Option| { + let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res); + let def_id = this.parent_scope.module.normal_ancestor_id; + let node_id = this.r.definitions.as_local_node_id(def_id).unwrap(); + let better = res.is_some(); + this.r.use_injections.push(UseError { err, candidates, node_id, better }); + PartialRes::new(Res::Err) + }; + + let partial_res = match self.resolve_qpath_anywhere( + id, + qself, + path, + ns, + span, + source.defer_to_typeck(), + crate_lint, + ) { + Some(partial_res) if partial_res.unresolved_segments() == 0 => { + if is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err { + partial_res + } else { + // Add a temporary hack to smooth the transition to new struct ctor + // visibility rules. See #38932 for more details. + let mut res = None; + if let Res::Def(DefKind::Struct, def_id) = partial_res.base_res() { + if let Some((ctor_res, ctor_vis)) + = self.r.struct_constructors.get(&def_id).cloned() { + if is_expected(ctor_res) && + self.r.is_accessible_from(ctor_vis, self.parent_scope.module) { + let lint = lint::builtin::LEGACY_CONSTRUCTOR_VISIBILITY; + self.r.session.buffer_lint(lint, id, span, + "private struct constructors are not usable through \ + re-exports in outer modules", + ); + res = Some(PartialRes::new(ctor_res)); + } + } + } + + res.unwrap_or_else(|| report_errors(self, Some(partial_res.base_res()))) + } + } + Some(partial_res) if source.defer_to_typeck() => { + // Not fully resolved associated item `T::A::B` or `::A::B` + // or `::A::B`. If `B` should be resolved in value namespace then + // it needs to be added to the trait map. + if ns == ValueNS { + let item_name = path.last().unwrap().ident; + let traits = self.get_traits_containing_item(item_name, ns); + self.r.trait_map.insert(id, traits); + } + + let mut std_path = vec![Segment::from_ident(Ident::with_dummy_span(sym::std))]; + std_path.extend(path); + if self.r.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) { + let cl = CrateLint::No; + let ns = Some(ns); + if let PathResult::Module(_) | PathResult::NonModule(_) = + self.resolve_path(&std_path, ns, false, span, cl) { + // check if we wrote `str::from_utf8` instead of `std::str::from_utf8` + let item_span = path.iter().last().map(|segment| segment.ident.span) + .unwrap_or(span); + debug!("accessed item from `std` submodule as a bare type {:?}", std_path); + let mut hm = self.r.session.confused_type_with_std_module.borrow_mut(); + hm.insert(item_span, span); + // In some places (E0223) we only have access to the full path + hm.insert(span, span); + } + } + partial_res + } + _ => report_errors(self, None) + }; + + if let PathSource::TraitItem(..) = source {} else { + // Avoid recording definition of `A::B` in `::B::C`. + self.r.record_partial_res(id, partial_res); + } + partial_res + } + + fn self_type_is_available(&mut self, span: Span) -> bool { + let binding = self.resolve_ident_in_lexical_scope( + Ident::with_dummy_span(kw::SelfUpper), + TypeNS, + None, + span, + ); + if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false } + } + + fn self_value_is_available(&mut self, self_span: Span, path_span: Span) -> bool { + let ident = Ident::new(kw::SelfLower, self_span); + let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, path_span); + if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false } + } + + // Resolve in alternative namespaces if resolution in the primary namespace fails. + fn resolve_qpath_anywhere( + &mut self, + id: NodeId, + qself: Option<&QSelf>, + path: &[Segment], + primary_ns: Namespace, + span: Span, + defer_to_typeck: bool, + crate_lint: CrateLint, + ) -> Option { + let mut fin_res = None; + for (i, ns) in [primary_ns, TypeNS, ValueNS].iter().cloned().enumerate() { + if i == 0 || ns != primary_ns { + match self.resolve_qpath(id, qself, path, ns, span, crate_lint) { + // If defer_to_typeck, then resolution > no resolution, + // otherwise full resolution > partial resolution > no resolution. + Some(partial_res) if partial_res.unresolved_segments() == 0 || + defer_to_typeck => + return Some(partial_res), + partial_res => if fin_res.is_none() { fin_res = partial_res }, + } + } + } + + // `MacroNS` + assert!(primary_ns != MacroNS); + if qself.is_none() { + let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); + let path = Path { segments: path.iter().map(path_seg).collect(), span }; + if let Ok((_, res)) = self.r.resolve_macro_path( + &path, None, &self.parent_scope, false, false + ) { + return Some(PartialRes::new(res)); + } + } + + fin_res + } + + /// Handles paths that may refer to associated items. + fn resolve_qpath( + &mut self, + id: NodeId, + qself: Option<&QSelf>, + path: &[Segment], + ns: Namespace, + span: Span, + crate_lint: CrateLint, + ) -> Option { + debug!( + "resolve_qpath(id={:?}, qself={:?}, path={:?}, ns={:?}, span={:?})", + id, + qself, + path, + ns, + span, + ); + + if let Some(qself) = qself { + if qself.position == 0 { + // This is a case like `::B`, where there is no + // trait to resolve. In that case, we leave the `B` + // segment to be resolved by type-check. + return Some(PartialRes::with_unresolved_segments( + Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)), path.len() + )); + } + + // Make sure `A::B` in `::C` is a trait item. + // + // Currently, `path` names the full item (`A::B::C`, in + // our example). so we extract the prefix of that that is + // the trait (the slice upto and including + // `qself.position`). And then we recursively resolve that, + // but with `qself` set to `None`. + // + // However, setting `qself` to none (but not changing the + // span) loses the information about where this path + // *actually* appears, so for the purposes of the crate + // lint we pass along information that this is the trait + // name from a fully qualified path, and this also + // contains the full span (the `CrateLint::QPathTrait`). + let ns = if qself.position + 1 == path.len() { ns } else { TypeNS }; + let partial_res = self.smart_resolve_path_fragment( + id, + None, + &path[..=qself.position], + span, + PathSource::TraitItem(ns), + CrateLint::QPathTrait { + qpath_id: id, + qpath_span: qself.path_span, + }, + ); + + // The remaining segments (the `C` in our example) will + // have to be resolved by type-check, since that requires doing + // trait resolution. + return Some(PartialRes::with_unresolved_segments( + partial_res.base_res(), + partial_res.unresolved_segments() + path.len() - qself.position - 1, + )); + } + + let result = match self.resolve_path(&path, Some(ns), true, span, crate_lint) { + PathResult::NonModule(path_res) => path_res, + PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => { + PartialRes::new(module.res().unwrap()) + } + // In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we + // don't report an error right away, but try to fallback to a primitive type. + // So, we are still able to successfully resolve something like + // + // use std::u8; // bring module u8 in scope + // fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8 + // u8::max_value() // OK, resolves to associated function ::max_value, + // // not to non-existent std::u8::max_value + // } + // + // Such behavior is required for backward compatibility. + // The same fallback is used when `a` resolves to nothing. + PathResult::Module(ModuleOrUniformRoot::Module(_)) | + PathResult::Failed { .. } + if (ns == TypeNS || path.len() > 1) && + self.r.primitive_type_table.primitive_types + .contains_key(&path[0].ident.name) => { + let prim = self.r.primitive_type_table.primitive_types[&path[0].ident.name]; + PartialRes::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1) + } + PathResult::Module(ModuleOrUniformRoot::Module(module)) => + PartialRes::new(module.res().unwrap()), + PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => { + self.r.report_error(span, ResolutionError::FailedToResolve { label, suggestion }); + PartialRes::new(Res::Err) + } + PathResult::Module(..) | PathResult::Failed { .. } => return None, + PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"), + }; + + if path.len() > 1 && result.base_res() != Res::Err && + path[0].ident.name != kw::PathRoot && + path[0].ident.name != kw::DollarCrate { + let unqualified_result = { + match self.resolve_path( + &[*path.last().unwrap()], + Some(ns), + false, + span, + CrateLint::No, + ) { + PathResult::NonModule(path_res) => path_res.base_res(), + PathResult::Module(ModuleOrUniformRoot::Module(module)) => + module.res().unwrap(), + _ => return Some(result), + } + }; + if result.base_res() == unqualified_result { + let lint = lint::builtin::UNUSED_QUALIFICATIONS; + self.r.session.buffer_lint(lint, id, span, "unnecessary qualification") + } + } + + Some(result) + } + + fn with_resolved_label(&mut self, label: Option

` (where P is one \ + of the previous types except `Self`)"; + fn check_method_receiver<'fcx, 'tcx>( fcx: &FnCtxt<'fcx, 'tcx>, method_sig: &hir::MethodSig, method: &ty::AssocItem, self_ty: Ty<'tcx>, ) { - const HELP_FOR_SELF_TYPE: &str = - "consider changing to `self`, `&self`, `&mut self`, `self: Box`, \ - `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one \ - of the previous types except `Self`)"; // Check that the method has a valid receiver type, given the type `Self`. - debug!("check_method_receiver({:?}, self_ty={:?})", - method, self_ty); + debug!("check_method_receiver({:?}, self_ty={:?})", method, self_ty); if !method.method_has_self_argument { return; @@ -806,12 +851,7 @@ fn check_method_receiver<'fcx, 'tcx>( if fcx.tcx.features().arbitrary_self_types { if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) { // Report error; `arbitrary_self_types` was enabled. - fcx.tcx.sess.diagnostic().mut_span_err( - span, &format!("invalid method receiver type: {:?}", receiver_ty) - ).note("type of `self` must be `Self` or a type that dereferences to it") - .help(HELP_FOR_SELF_TYPE) - .code(DiagnosticId::Error("E0307".into())) - .emit(); + e0307(fcx, span, receiver_ty); } } else { if !receiver_is_valid(fcx, span, receiver_ty, self_ty, false) { @@ -831,17 +871,22 @@ fn check_method_receiver<'fcx, 'tcx>( .emit(); } else { // Report error; would not have worked with `arbitrary_self_types`. - fcx.tcx.sess.diagnostic().mut_span_err( - span, &format!("invalid method receiver type: {:?}", receiver_ty) - ).note("type must be `Self` or a type that dereferences to it") - .help(HELP_FOR_SELF_TYPE) - .code(DiagnosticId::Error("E0307".into())) - .emit(); + e0307(fcx, span, receiver_ty); } } } } +fn e0307(fcx: &FnCtxt<'fcx, 'tcx>, span: Span, receiver_ty: Ty<'_>) { + fcx.tcx.sess.diagnostic().struct_span_err( + span, + &format!("invalid `self` parameter type: {:?}", receiver_ty) + ).note("type of `self` must be `Self` or a type that dereferences to it") + .help(HELP_FOR_SELF_TYPE) + .code(DiagnosticId::Error("E0307".into())) + .emit(); +} + /// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If /// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly /// through a `*const/mut T` raw pointer. If the feature is not enabled, the requirements are more @@ -990,42 +1035,19 @@ fn report_bivariance(tcx: TyCtxt<'_>, span: Span, param_name: ast::Name) { let suggested_marker_id = tcx.lang_items().phantom_data(); // Help is available only in presence of lang items. - if let Some(def_id) = suggested_marker_id { - err.help(&format!("consider removing `{}` or using a marker such as `{}`", - param_name, - tcx.def_path_str(def_id))); - } + let msg = if let Some(def_id) = suggested_marker_id { + format!( + "consider removing `{}`, referring to it in a field, or using a marker such as `{}`", + param_name, + tcx.def_path_str(def_id), + ) + } else { + format!( "consider removing `{}` or referring to it in a field", param_name) + }; + err.help(&msg); err.emit(); } -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.params.iter().flat_map(|param| match param.kind { - GenericParamDefKind::Lifetime => None, - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => { - Some((param.name, param.def_id)) - } - }).collect(); - - for method_param in &generics.params { - // Shadowing is checked in `resolve_lifetime`. - if let GenericParamDefKind::Lifetime = method_param.kind { - 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); - - // The expectation here is that the original trait declaration is - // local so it should be okay to just unwrap everything. - let trait_def_id = impl_params[&method_param.name]; - let trait_decl_span = tcx.def_span(trait_def_id); - error_194(tcx, type_span, trait_decl_span, &method_param.name.as_str()[..]); - } - } -} - /// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that /// aren't true. fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, span: Span, id: hir::HirId) { @@ -1119,7 +1141,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn enum_variants(&self, enum_def: &hir::EnumDef) -> Vec> { enum_def.variants.iter() - .map(|variant| self.non_enum_variant(&variant.node.data)) + .map(|variant| self.non_enum_variant(&variant.data)) .collect() } @@ -1152,12 +1174,3 @@ fn error_392( err.span_label(span, "unused parameter"); err } - -fn error_194(tcx: TyCtxt<'_>, span: Span, trait_decl_span: Span, name: &str) { - struct_span_err!(tcx.sess, span, E0194, - "type parameter `{}` shadows another type parameter of the same name", - name) - .span_label(span, "shadows another type parameter") - .span_label(trait_decl_span, format!("first `{}` declared here", name)) - .emit(); -} diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 67a8ecaf1da85..7a8a209a5350c 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -3,7 +3,6 @@ // substitutions. use crate::check::FnCtxt; -use errors::DiagnosticBuilder; use rustc::hir; use rustc::hir::def_id::{DefId, DefIndex}; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; @@ -39,8 +38,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, sym::rustc_dump_user_substs); let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_substs); - for arg in &body.arguments { - wbcx.visit_node_id(arg.pat.span, arg.hir_id); + for param in &body.params { + wbcx.visit_node_id(param.pat.span, param.hir_id); } // Type only exists for constants and statics, not functions. match self.tcx.hir().body_owner_kind(item_id) { @@ -59,6 +58,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wbcx.visit_free_region_map(); wbcx.visit_user_provided_tys(); wbcx.visit_user_provided_sigs(); + wbcx.visit_generator_interior_types(); let used_trait_imports = mem::replace( &mut self.tables.borrow_mut().used_trait_imports, @@ -135,7 +135,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // we observe that something like `a+b` is (known to be) // operating on scalars, we clear the overload. fn fix_scalar_builtin_expr(&mut self, e: &hir::Expr) { - match e.node { + match e.kind { hir::ExprKind::Unary(hir::UnNeg, ref inner) | hir::ExprKind::Unary(hir::UnNot, ref inner) => { let inner_ty = self.fcx.node_ty(inner.hir_id); @@ -160,7 +160,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { tables.type_dependent_defs_mut().remove(e.hir_id); tables.node_substs_mut().remove(e.hir_id); - match e.node { + match e.kind { hir::ExprKind::Binary(..) => { if !op.node.is_by_value() { let mut adjustments = tables.adjustments_mut(); @@ -187,12 +187,29 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // to use builtin indexing because the index type is known to be // usize-ish fn fix_index_builtin_expr(&mut self, e: &hir::Expr) { - if let hir::ExprKind::Index(ref base, ref index) = e.node { + if let hir::ExprKind::Index(ref base, ref index) = e.kind { let mut tables = self.fcx.tables.borrow_mut(); - // All valid indexing looks like this; might encounter non-valid indexes at this point - if let ty::Ref(_, base_ty, _) = tables.expr_ty_adjusted(&base).sty { - let index_ty = tables.expr_ty_adjusted(&index); + // All valid indexing looks like this; might encounter non-valid indexes at this point. + let base_ty = tables.expr_ty_adjusted_opt(&base).map(|t| &t.kind); + if base_ty.is_none() { + // When encountering `return [0][0]` outside of a `fn` body we can encounter a base + // that isn't in the type table. We assume more relevant errors have already been + // emitted, so we delay an ICE if none have. (#64638) + self.tcx().sess.delay_span_bug(e.span, &format!("bad base: `{:?}`", base)); + } + if let Some(ty::Ref(_, base_ty, _)) = base_ty { + let index_ty = tables.expr_ty_adjusted_opt(&index).unwrap_or_else(|| { + // When encountering `return [0][0]` outside of a `fn` body we would attempt + // to access an unexistend index. We assume that more relevant errors will + // already have been emitted, so we only gate on this with an ICE if no + // error has been emitted. (#64638) + self.tcx().sess.delay_span_bug( + e.span, + &format!("bad index {:?} for base: `{:?}`", index, base), + ); + self.fcx.tcx.types.err + }); let index_ty = self.fcx.resolve_vars_if_possible(&index_ty); if base_ty.builtin_index().is_some() && index_ty == self.fcx.tcx.types.usize { @@ -242,11 +259,11 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { self.visit_node_id(e.span, e.hir_id); - match e.node { + match e.kind { hir::ExprKind::Closure(_, _, body, _, _) => { let body = self.fcx.tcx.hir().body(body); - for arg in &body.arguments { - self.visit_node_id(e.span, arg.hir_id); + for param in &body.params { + self.visit_node_id(e.span, param.hir_id); } self.visit_body(body); @@ -271,7 +288,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { } fn visit_pat(&mut self, p: &'tcx hir::Pat) { - match p.node { + match p.kind { hir::PatKind::Binding(..) => { if let Some(&bm) = self.fcx.tables.borrow().pat_binding_modes().get(p.hir_id) { self.tables.pat_binding_modes_mut().insert(p.hir_id, bm); @@ -283,7 +300,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { } hir::PatKind::Struct(_, ref fields, _) => { for field in fields { - self.visit_field_id(field.node.hir_id); + self.visit_field_id(field.hir_id); } } _ => {} @@ -407,7 +424,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { if !errors_buffer.is_empty() { errors_buffer.sort_by_key(|diag| diag.span.primary_span()); for diag in errors_buffer.drain(..) { - DiagnosticBuilder::new_diagnostic(self.tcx().sess.diagnostic(), diag).emit(); + self.tcx().sess.diagnostic().emit_diagnostic(&diag); } } } @@ -431,6 +448,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + fn visit_generator_interior_types(&mut self) { + let fcx_tables = self.fcx.tables.borrow(); + debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); + self.tables.generator_interior_types = fcx_tables.generator_interior_types.clone(); + } + fn visit_opaque_types(&mut self, span: Span) { for (&def_id, opaque_defn) in self.fcx.opaque_types.borrow().iter() { let hir_id = self.tcx().hir().as_local_hir_id(def_id).unwrap(); @@ -455,7 +478,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let mut skip_add = false; - if let ty::Opaque(defin_ty_def_id, _substs) = definition_ty.sty { + if let ty::Opaque(defin_ty_def_id, _substs) = definition_ty.kind { if def_id == defin_ty_def_id { debug!("Skipping adding concrete definition for opaque type {:?} {:?}", opaque_defn, defin_ty_def_id); diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index ffc66ec16de13..7af1a342ff36e 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -33,7 +33,7 @@ impl ItemLikeVisitor<'v> for CheckVisitor<'tcx> { if item.vis.node.is_pub() || item.span.is_dummy() { return; } - if let hir::ItemKind::Use(ref path, _) = item.node { + if let hir::ItemKind::Use(ref path, _) = item.kind { self.check_import(item.hir_id, path.span); } } @@ -218,7 +218,7 @@ struct ExternCrateToLint { impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CollectExternCrateVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { - if let hir::ItemKind::ExternCrate(orig_name) = item.node { + if let hir::ItemKind::ExternCrate(orig_name) = item.kind { let extern_crate_def_id = self.tcx.hir().local_def_id(item.hir_id); self.crates_to_lint.push( ExternCrateToLint { diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index a95b9a03dcf77..1e3939cbfcdf2 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -47,13 +47,13 @@ impl<'tcx> Checker<'tcx> { } fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: DefId) { - if let ty::Adt(..) = tcx.type_of(impl_did).sty { + if let ty::Adt(..) = tcx.type_of(impl_did).kind { /* do nothing */ } else { // Destructors only work on nominal types. if let Some(impl_hir_id) = tcx.hir().as_local_hir_id(impl_did) { if let Some(Node::Item(item)) = tcx.hir().find(impl_hir_id) { - let span = match item.node { + let span = match item.kind { ItemKind::Impl(.., ref ty, _) => ty.span, _ => item.span, }; @@ -99,7 +99,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: DefId) { Ok(()) => {} Err(CopyImplementationError::InfrigingFields(fields)) => { let item = tcx.hir().expect_item(impl_hir_id); - let span = if let ItemKind::Impl(.., Some(ref tr), _, _) = item.node { + let span = if let ItemKind::Impl(.., Some(ref tr), _, _) = item.kind { tr.path.span } else { span @@ -116,7 +116,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: DefId) { } Err(CopyImplementationError::NotAnAdt) => { let item = tcx.hir().expect_item(impl_hir_id); - let span = if let ItemKind::Impl(.., ref ty, _) = item.node { + let span = if let ItemKind::Impl(.., ref ty, _) = item.kind { ty.span } else { span @@ -186,7 +186,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: DefId) { let cause = ObligationCause::misc(span, impl_hir_id); use ty::TyKind::*; - match (&source.sty, &target.sty) { + match (&source.kind, &target.kind) { (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b)) if infcx.at(&cause, param_env).eq(r_a, r_b).is_ok() && mutbl_a == *mutbl_b => (), @@ -322,29 +322,29 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: DefId) { } } -pub fn coerce_unsized_info<'tcx>(gcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo { +pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo { debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did); - let coerce_unsized_trait = gcx.lang_items().coerce_unsized_trait().unwrap(); + let coerce_unsized_trait = tcx.lang_items().coerce_unsized_trait().unwrap(); - let unsize_trait = gcx.lang_items().require(UnsizeTraitLangItem).unwrap_or_else(|err| { - gcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err)); + let unsize_trait = tcx.lang_items().require(UnsizeTraitLangItem).unwrap_or_else(|err| { + tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err)); }); // this provider should only get invoked for local def-ids - let impl_hir_id = gcx.hir().as_local_hir_id(impl_did).unwrap_or_else(|| { + let impl_hir_id = tcx.hir().as_local_hir_id(impl_did).unwrap_or_else(|| { bug!("coerce_unsized_info: invoked for non-local def-id {:?}", impl_did) }); - let source = gcx.type_of(impl_did); - let trait_ref = gcx.impl_trait_ref(impl_did).unwrap(); + let source = tcx.type_of(impl_did); + let trait_ref = tcx.impl_trait_ref(impl_did).unwrap(); assert_eq!(trait_ref.def_id, coerce_unsized_trait); let target = trait_ref.substs.type_at(1); debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target); - let span = gcx.hir().span(impl_hir_id); - let param_env = gcx.param_env(impl_did); + let span = tcx.hir().span(impl_hir_id); + let param_env = tcx.param_env(impl_did); assert!(!source.has_escaping_bound_vars()); let err_info = CoerceUnsizedInfo { custom_kind: None }; @@ -353,7 +353,7 @@ pub fn coerce_unsized_info<'tcx>(gcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn source, target); - gcx.infer_ctxt().enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let cause = ObligationCause::misc(span, impl_hir_id); let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>, @@ -367,29 +367,29 @@ pub fn coerce_unsized_info<'tcx>(gcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn } (mt_a.ty, mt_b.ty, unsize_trait, None) }; - let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) { + let (source, target, trait_def_id, kind) = match (&source.kind, &target.kind) { (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => { infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b }; - check_mutbl(mt_a, mt_b, &|ty| gcx.mk_imm_ref(r_b, ty)) + check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty)) } (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => { let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; - check_mutbl(mt_a, mt_b, &|ty| gcx.mk_imm_ptr(ty)) + check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)) } (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => { - check_mutbl(mt_a, mt_b, &|ty| gcx.mk_imm_ptr(ty)) + check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)) } (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b)) if def_a.is_struct() && def_b.is_struct() => { if def_a != def_b { - let source_path = gcx.def_path_str(def_a.did); - let target_path = gcx.def_path_str(def_b.did); - span_err!(gcx.sess, + let source_path = tcx.def_path_str(def_a.did); + let target_path = tcx.def_path_str(def_b.did); + span_err!(tcx.sess, span, E0377, "the trait `CoerceUnsized` may only be implemented \ @@ -443,9 +443,9 @@ pub fn coerce_unsized_info<'tcx>(gcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn let diff_fields = fields.iter() .enumerate() .filter_map(|(i, f)| { - let (a, b) = (f.ty(gcx, substs_a), f.ty(gcx, substs_b)); + let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b)); - if gcx.type_of(f.did).is_phantom_data() { + if tcx.type_of(f.did).is_phantom_data() { // Ignore PhantomData fields return None; } @@ -472,7 +472,7 @@ pub fn coerce_unsized_info<'tcx>(gcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn .collect::>(); if diff_fields.is_empty() { - span_err!(gcx.sess, + span_err!(tcx.sess, span, E0374, "the trait `CoerceUnsized` may only be implemented \ @@ -480,14 +480,14 @@ pub fn coerce_unsized_info<'tcx>(gcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn being coerced, none found"); return err_info; } else if diff_fields.len() > 1 { - let item = gcx.hir().expect_item(impl_hir_id); - let span = if let ItemKind::Impl(.., Some(ref t), _, _) = item.node { + let item = tcx.hir().expect_item(impl_hir_id); + let span = if let ItemKind::Impl(.., Some(ref t), _, _) = item.kind { t.path.span } else { - gcx.hir().span(impl_hir_id) + tcx.hir().span(impl_hir_id) }; - let mut err = struct_span_err!(gcx.sess, + let mut err = struct_span_err!(tcx.sess, span, E0375, "implementing the trait \ @@ -514,7 +514,7 @@ pub fn coerce_unsized_info<'tcx>(gcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn } _ => { - span_err!(gcx.sess, + span_err!(tcx.sess, span, E0376, "the trait `CoerceUnsized` may only be implemented \ @@ -527,7 +527,7 @@ pub fn coerce_unsized_info<'tcx>(gcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn // Register an obligation for `A: Trait`. let cause = traits::ObligationCause::misc(span, impl_hir_id); - let predicate = gcx.predicate_for_trait_def(param_env, + let predicate = tcx.predicate_for_trait_def(param_env, cause, trait_def_id, 0, diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index fb79a85ea25bf..90cedb455e3dd 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -49,7 +49,7 @@ struct InherentCollect<'tcx> { impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { fn visit_item(&mut self, item: &hir::Item) { - let ty = match item.node { + let ty = match item.kind { hir::ItemKind::Impl(.., None, ref ty, _) => ty, _ => return }; @@ -57,7 +57,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { let def_id = self.tcx.hir().local_def_id(item.hir_id); let self_ty = self.tcx.type_of(def_id); let lang_items = self.tcx.lang_items(); - match self_ty.sty { + match self_ty.kind { ty::Adt(def, _) => { self.check_def_id(item, def.did); } @@ -67,6 +67,14 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { ty::Dynamic(ref data, ..) if data.principal_def_id().is_some() => { self.check_def_id(item, data.principal_def_id().unwrap()); } + ty::Bool => { + self.check_primitive_impl(def_id, + lang_items.bool_impl(), + None, + "bool", + "bool", + item.span); + } ty::Char => { self.check_primitive_impl(def_id, lang_items.char_impl(), diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index 04b59a63e1d8a..0aae8fbe13178 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -84,7 +84,7 @@ impl InherentOverlapChecker<'tcx> { impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> { fn visit_item(&mut self, item: &'v hir::Item) { - match item.node { + match item.kind { hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Trait(..) | diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 1d0e433f07b3a..a44c475e0f8a9 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -167,7 +167,7 @@ fn check_impl_overlap<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId) { tcx.specialization_graph_of(trait_def_id); // check for overlap with the automatic `impl Trait for Trait` - if let ty::Dynamic(ref data, ..) = trait_ref.self_ty().sty { + if let ty::Dynamic(ref data, ..) = trait_ref.self_ty().kind { // This is something like impl Trait1 for Trait2. Illegal // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe. diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 299e18337bd30..667fa50a7cfa4 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -24,7 +24,7 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { fn visit_item(&mut self, item: &hir::Item) { let def_id = self.tcx.hir().local_def_id(item.hir_id); // "Trait" impl - if let hir::ItemKind::Impl(.., Some(_), _, _) = item.node { + if let hir::ItemKind::Impl(.., Some(_), _, _) = item.kind { debug!("coherence2::orphan check: trait impl {}", self.tcx.hir().node_to_string(item.hir_id)); let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap(); @@ -102,7 +102,7 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { if self.tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() { let self_ty = trait_ref.self_ty(); - let opt_self_def_id = match self_ty.sty { + let opt_self_def_id = match self_ty.kind { ty::Adt(self_def, _) => Some(self_def.did), ty::Foreign(did) => Some(did), _ => None, diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index 07fbfddd96e43..b7cc6feee4453 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -71,7 +71,7 @@ impl UnsafetyChecker<'tcx> { impl ItemLikeVisitor<'v> for UnsafetyChecker<'tcx> { fn visit_item(&mut self, item: &'v hir::Item) { - if let hir::ItemKind::Impl(unsafety, polarity, _, ref generics, ..) = item.node { + if let hir::ItemKind::Impl(unsafety, polarity, _, ref generics, ..) = item.kind { self.check_unsafety_coherence(item, Some(generics), unsafety, polarity); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 0f0568907c646..5b2081bef78dc 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -16,7 +16,7 @@ use crate::astconv::{AstConv, Bounds, SizedByDefault}; use crate::constrained_generic_params as cgp; -use crate::check::intrinsic::intrisic_operation_unsafety; +use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::lint; use crate::middle::resolve_lifetime as rl; use crate::middle::weak_lang_items; @@ -25,7 +25,7 @@ use rustc::ty::query::Providers; use rustc::ty::subst::{Subst, InternalSubsts}; use rustc::ty::util::Discr; use rustc::ty::util::IntTypeExt; -use rustc::ty::subst::UnpackedKind; +use rustc::ty::subst::GenericArgKind; use rustc::ty::{self, AdtKind, DefIdTree, ToPolyTraitRef, Ty, TyCtxt, Const}; use rustc::ty::{ReprOptions, ToPredicate}; use rustc::util::captures::Captures; @@ -35,7 +35,6 @@ use rustc_target::spec::abi; use syntax::ast; use syntax::ast::{Ident, MetaItemKind}; use syntax::attr::{InlineAttr, OptimizeAttr, list_contains_name, mark_used}; -use syntax::source_map::Spanned; use syntax::feature_gate; use syntax::symbol::{InternedString, kw, Symbol, sym}; use syntax_pos::{Span, DUMMY_SP}; @@ -47,7 +46,7 @@ use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::hir::GenericParamKind; use rustc::hir::{self, CodegenFnAttrFlags, CodegenFnAttrs, Unsafety}; -use errors::{Applicability, DiagnosticId}; +use errors::{Applicability, DiagnosticId, StashKey}; struct OnlySelfBounds(bool); @@ -136,7 +135,7 @@ impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { } fn visit_expr(&mut self, expr: &'tcx hir::Expr) { - if let hir::ExprKind::Closure(..) = expr.node { + if let hir::ExprKind::Closure(..) = expr.kind { let def_id = self.tcx.hir().local_def_id(expr.hir_id); self.tcx.generics_of(def_id); self.tcx.type_of(def_id); @@ -289,7 +288,7 @@ fn type_param_predicates( Node::ImplItem(item) => &item.generics, Node::Item(item) => { - match item.node { + match item.kind { ItemKind::Fn(.., ref generics, _) | ItemKind::Impl(_, _, _, ref generics, ..) | ItemKind::TyAlias(_, ref generics) @@ -313,7 +312,7 @@ fn type_param_predicates( } } - Node::ForeignItem(item) => match item.node { + Node::ForeignItem(item) => match item.kind { ForeignItemKind::Fn(_, _, ref generics) => generics, _ => return result, }, @@ -388,7 +387,7 @@ impl ItemCtxt<'tcx> { /// `ast_ty_to_ty`, because we want to avoid triggering an all-out /// conversion of the type to avoid inducing unnecessary cycles. fn is_param(tcx: TyCtxt<'_>, ast_ty: &hir::Ty, param_id: hir::HirId) -> bool { - if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = ast_ty.node { + if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = ast_ty.kind { match path.res { Res::SelfTy(Some(def_id), None) | Res::Def(DefKind::TyParam, def_id) => { def_id == tcx.hir().local_def_id(param_id) @@ -404,7 +403,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::HirId) { let it = tcx.hir().expect_item(item_id); debug!("convert: item {} with id {}", it.ident, it.hir_id); let def_id = tcx.hir().local_def_id(item_id); - match it.node { + match it.kind { // These don't define types. hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) @@ -416,7 +415,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::HirId) { tcx.generics_of(def_id); tcx.type_of(def_id); tcx.predicates_of(def_id); - if let hir::ForeignItemKind::Fn(..) = item.node { + if let hir::ForeignItemKind::Fn(..) = item.kind { tcx.fn_sig(def_id); } } @@ -475,7 +474,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::HirId) { tcx.generics_of(def_id); tcx.type_of(def_id); tcx.predicates_of(def_id); - if let hir::ItemKind::Fn(..) = it.node { + if let hir::ItemKind::Fn(..) = it.kind { tcx.fn_sig(def_id); } } @@ -487,12 +486,12 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::HirId) { let def_id = tcx.hir().local_def_id(trait_item.hir_id); tcx.generics_of(def_id); - match trait_item.node { + match trait_item.kind { hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(_, Some(_)) | hir::TraitItemKind::Method(..) => { tcx.type_of(def_id); - if let hir::TraitItemKind::Method(..) = trait_item.node { + if let hir::TraitItemKind::Method(..) = trait_item.kind { tcx.fn_sig(def_id); } } @@ -508,7 +507,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::HirId) { tcx.generics_of(def_id); tcx.type_of(def_id); tcx.predicates_of(def_id); - if let hir::ImplItemKind::Method(..) = tcx.hir().expect_impl_item(impl_item_id).node { + if let hir::ImplItemKind::Method(..) = tcx.hir().expect_impl_item(impl_item_id).kind { tcx.fn_sig(def_id); } } @@ -520,17 +519,21 @@ fn convert_variant_ctor(tcx: TyCtxt<'_>, ctor_id: hir::HirId) { tcx.predicates_of(def_id); } -fn convert_enum_variant_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, variants: &[hir::Variant]) { +fn convert_enum_variant_types( + tcx: TyCtxt<'_>, + def_id: DefId, + variants: &[hir::Variant] +) { let def = tcx.adt_def(def_id); let repr_type = def.repr.discr_type(); let initial = repr_type.initial_discriminant(tcx); - let mut prev_discr = None::>; + let mut prev_discr = None::>; // fill the discriminant values and field types for variant in variants { let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx)); prev_discr = Some( - if let Some(ref e) = variant.node.disr_expr { + if let Some(ref e) = variant.disr_expr { let expr_did = tcx.hir().local_def_id(e.hir_id); def.eval_explicit_discr(tcx, expr_did) } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) { @@ -546,14 +549,14 @@ fn convert_enum_variant_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, variants: format!("overflowed on value after {}", prev_discr.unwrap()), ).note(&format!( "explicitly set `{} = {}` if that is desired outcome", - variant.node.ident, wrapped_discr + variant.ident, wrapped_discr )) .emit(); None }.unwrap_or(wrapped_discr), ); - for f in variant.node.data.fields() { + for f in variant.data.fields() { let def_id = tcx.hir().local_def_id(f.hir_id); tcx.generics_of(def_id); tcx.type_of(def_id); @@ -562,7 +565,7 @@ fn convert_enum_variant_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, variants: // Convert the ctor, if any. This also registers the variant as // an item. - if let Some(ctor_hir_id) = variant.node.data.ctor_hir_id() { + if let Some(ctor_hir_id) = variant.data.ctor_hir_id() { convert_variant_ctor(tcx, ctor_hir_id); } } @@ -635,17 +638,17 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::AdtDef { }; let repr = ReprOptions::new(tcx, def_id); - let (kind, variants) = match item.node { + let (kind, variants) = match item.kind { ItemKind::Enum(ref def, _) => { let mut distance_from_explicit = 0; let variants = def.variants .iter() .map(|v| { - let variant_did = Some(tcx.hir().local_def_id(v.node.id)); - let ctor_did = v.node.data.ctor_hir_id() + let variant_did = Some(tcx.hir().local_def_id(v.id)); + let ctor_did = v.data.ctor_hir_id() .map(|hir_id| tcx.hir().local_def_id(hir_id)); - let discr = if let Some(ref e) = v.node.disr_expr { + let discr = if let Some(ref e) = v.disr_expr { distance_from_explicit = 0; ty::VariantDiscr::Explicit(tcx.hir().local_def_id(e.hir_id)) } else { @@ -653,8 +656,8 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::AdtDef { }; distance_from_explicit += 1; - convert_variant(tcx, variant_did, ctor_did, v.node.ident, discr, - &v.node.data, AdtKind::Enum, def_id) + convert_variant(tcx, variant_did, ctor_did, v.ident, discr, + &v.data, AdtKind::Enum, def_id) }) .collect(); @@ -704,7 +707,7 @@ fn super_predicates_of( _ => bug!("trait_node_id {} is not an item", trait_hir_id), }; - let (generics, bounds) = match item.node { + let (generics, bounds) = match item.kind { hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits), hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits), _ => span_bug!(item.span, "super_predicates invoked on non-trait"), @@ -713,7 +716,7 @@ fn super_predicates_of( let icx = ItemCtxt::new(tcx, trait_def_id); // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`. - let self_param_ty = tcx.mk_self_type(); + let self_param_ty = tcx.types.self_param; let superbounds1 = AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span); @@ -750,7 +753,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TraitDef { let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); let item = tcx.hir().expect_item(hir_id); - let (is_auto, unsafety) = match item.node { + let (is_auto, unsafety) = match item.kind { hir::ItemKind::Trait(is_auto, unsafety, ..) => (is_auto == hir::IsAuto::Yes, unsafety), hir::ItemKind::TraitAlias(..) => (false, hir::Unsafety::Normal), _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"), @@ -793,7 +796,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option { self.outer_index.shift_in(1); intravisit::walk_ty(self, ty); @@ -857,25 +860,25 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option match item.node { + Node::TraitItem(item) => match item.kind { hir::TraitItemKind::Method(ref sig, _) => { has_late_bound_regions(tcx, &item.generics, &sig.decl) } _ => None, }, - Node::ImplItem(item) => match item.node { + Node::ImplItem(item) => match item.kind { hir::ImplItemKind::Method(ref sig, _) => { has_late_bound_regions(tcx, &item.generics, &sig.decl) } _ => None, }, - Node::ForeignItem(item) => match item.node { + Node::ForeignItem(item) => match item.kind { hir::ForeignItemKind::Fn(ref fn_decl, _, ref generics) => { has_late_bound_regions(tcx, generics, fn_decl) } _ => None, }, - Node::Item(item) => match item.node { + Node::Item(item) => match item.kind { hir::ItemKind::Fn(ref fn_decl, .., ref generics, _) => { has_late_bound_regions(tcx, generics, fn_decl) } @@ -897,11 +900,25 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics { let parent_id = tcx.hir().get_parent_item(hir_id); Some(tcx.hir().local_def_id(parent_id)) } + // FIXME(#43408) enable this in all cases when we get lazy normalization. + Node::AnonConst(&anon_const) => { + // HACK(eddyb) this provides the correct generics when the workaround + // for a const parameter `AnonConst` is being used elsewhere, as then + // there won't be the kind of cyclic dependency blocking #43408. + let expr = &tcx.hir().body(anon_const.body).value; + let icx = ItemCtxt::new(tcx, def_id); + if AstConv::const_param_def_id(&icx, expr).is_some() { + let parent_id = tcx.hir().get_parent_item(hir_id); + Some(tcx.hir().local_def_id(parent_id)) + } else { + None + } + } Node::Expr(&hir::Expr { - node: hir::ExprKind::Closure(..), + kind: hir::ExprKind::Closure(..), .. }) => Some(tcx.closure_base_def_id(def_id)), - Node::Item(item) => match item.node { + Node::Item(item) => match item.kind { ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => impl_trait_fn, _ => None, }, @@ -918,7 +935,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics { Node::ImplItem(item) => &item.generics, Node::Item(item) => { - match item.node { + match item.kind { ItemKind::Fn(.., ref generics, _) | ItemKind::Impl(_, _, _, ref generics, ..) => { generics } @@ -960,7 +977,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics { } } - Node::ForeignItem(item) => match item.node { + Node::ForeignItem(item) => match item.kind { ForeignItemKind::Static(..) => &no_generics, ForeignItemKind::Fn(_, _, ref generics) => generics, ForeignItemKind::Type => &no_generics, @@ -1011,13 +1028,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics { synthetic, .. } => { - if param.name.ident().name == kw::SelfUpper { - span_bug!( - param.span, - "`Self` should not be the name of a regular parameter" - ); - } - if !allow_defaults && default.is_some() { if !tcx.features().default_type_parameter_fallback { tcx.lint_hir( @@ -1041,13 +1051,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics { } } GenericParamKind::Const { .. } => { - if param.name.ident().name == kw::SelfUpper { - span_bug!( - param.span, - "`Self` should not be the name of a regular parameter", - ); - } - ty::GenericParamDefKind::Const } _ => return None, @@ -1069,7 +1072,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics { // cares about anything but the length is instantiation, // and we don't do that for closures. if let Node::Expr(&hir::Expr { - node: hir::ExprKind::Closure(.., gen), + kind: hir::ExprKind::Closure(.., gen), .. }) = node { @@ -1146,18 +1149,41 @@ fn infer_placeholder_type( def_id: DefId, body_id: hir::BodyId, span: Span, + item_ident: Ident, ) -> Ty<'_> { let ty = tcx.typeck_tables_of(def_id).node_type(body_id.hir_id); - let mut diag = bad_placeholder_type(tcx, span); - if ty != tcx.types.err { - diag.span_suggestion( - span, - "replace `_` with the correct type", - ty.to_string(), - Applicability::MaybeIncorrect, - ); + + // If this came from a free `const` or `static mut?` item, + // then the user may have written e.g. `const A = 42;`. + // In this case, the parser has stashed a diagnostic for + // us to improve in typeck so we do that now. + match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) { + Some(mut err) => { + // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type. + // We are typeck and have the real type, so remove that and suggest the actual type. + err.suggestions.clear(); + err.span_suggestion( + span, + "provide a type for the item", + format!("{}: {}", item_ident, ty), + Applicability::MachineApplicable, + ) + .emit(); + } + None => { + let mut diag = bad_placeholder_type(tcx, span); + if ty != tcx.types.err { + diag.span_suggestion( + span, + "replace `_` with the correct type", + ty.to_string(), + Applicability::MaybeIncorrect, + ); + } + diag.emit(); + } } - diag.emit(); + ty } @@ -1181,15 +1207,15 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option match item.node { + Node::TraitItem(item) => match item.kind { TraitItemKind::Method(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id, substs) } TraitItemKind::Const(ref ty, body_id) => { body_id.and_then(|body_id| { - if let hir::TyKind::Infer = ty.node { - Some(infer_placeholder_type(tcx, def_id, body_id, ty.span)) + if let hir::TyKind::Infer = ty.kind { + Some(infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)) } else { None } @@ -1204,14 +1230,14 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option match item.node { + Node::ImplItem(item) => match item.kind { ImplItemKind::Method(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id, substs) } ImplItemKind::Const(ref ty, body_id) => { - if let hir::TyKind::Infer = ty.node { - infer_placeholder_type(tcx, def_id, body_id, ty.span) + if let hir::TyKind::Infer = ty.kind { + infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident) } else { icx.to_ty(ty) } @@ -1239,11 +1265,11 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option { - match item.node { + match item.kind { ItemKind::Static(ref ty, .., body_id) | ItemKind::Const(ref ty, body_id) => { - if let hir::TyKind::Infer = ty.node { - infer_placeholder_type(tcx, def_id, body_id, ty.span) + if let hir::TyKind::Infer = ty.kind { + infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident) } else { icx.to_ty(ty) } @@ -1299,13 +1325,13 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option match foreign_item.node { + Node::ForeignItem(foreign_item) => match foreign_item.kind { ForeignItemKind::Fn(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id, substs) @@ -1314,10 +1340,9 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option tcx.mk_foreign(def_id), }, - Node::Ctor(&ref def) | Node::Variant(&Spanned { - node: hir::VariantKind { data: ref def, .. }, - .. - }) => match *def { + Node::Ctor(&ref def) | Node::Variant( + hir::Variant { data: ref def, .. } + ) => match *def { VariantData::Unit(..) | VariantData::Struct(..) => { tcx.type_of(tcx.hir().get_parent_did(hir_id)) } @@ -1330,17 +1355,14 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option icx.to_ty(&field.ty), Node::Expr(&hir::Expr { - node: hir::ExprKind::Closure(.., gen), + kind: hir::ExprKind::Closure(.., gen), .. }) => { if gen.is_some() { return Some(tcx.typeck_tables_of(def_id).node_type(hir_id)); } - let substs = ty::ClosureSubsts { - substs: InternalSubsts::identity_for_item(tcx, def_id), - }; - + let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_closure(def_id, substs) } @@ -1348,27 +1370,23 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option { tcx.types.usize } - Node::Variant(&Spanned { - node: - VariantKind { - disr_expr: Some(ref e), - .. - }, + Node::Variant(Variant { + disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => { @@ -1378,22 +1396,22 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option { let path = match parent_node { Node::Ty(&hir::Ty { - node: hir::TyKind::Path(QPath::Resolved(_, ref path)), + kind: hir::TyKind::Path(QPath::Resolved(_, ref path)), .. }) | Node::Expr(&hir::Expr { - node: ExprKind::Path(QPath::Resolved(_, ref path)), + kind: ExprKind::Path(QPath::Resolved(_, ref path)), .. }) => { Some(&**path) } - Node::Expr(&hir::Expr { node: ExprKind::Struct(ref path, ..), .. }) => { + Node::Expr(&hir::Expr { kind: ExprKind::Struct(ref path, ..), .. }) => { if let QPath::Resolved(_, ref path) = **path { Some(&**path) } else { @@ -1490,9 +1508,29 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option match ¶m.kind { - hir::GenericParamKind::Type { default: Some(ref ty), .. } | - hir::GenericParamKind::Const { ref ty, .. } => { - icx.to_ty(ty) + hir::GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty), + hir::GenericParamKind::Const { ty: ref hir_ty, .. } => { + let ty = icx.to_ty(hir_ty); + if !tcx.features().const_compare_raw_pointers { + let err = match ty.peel_refs().kind { + ty::FnPtr(_) => Some("function pointers"), + ty::RawPtr(_) => Some("raw pointers"), + _ => None, + }; + if let Some(unsupported_type) = err { + feature_gate::emit_feature_err( + &tcx.sess.parse_sess, + sym::const_compare_raw_pointers, + hir_ty.span, + feature_gate::GateIssue::Language, + &format!( + "using {} as const generic parameters is unstable", + unsupported_type + ), + ); + }; + } + ty } x => { if !fail { @@ -1559,8 +1597,8 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { // Skipping binder is ok, since we only use this to find generic parameters and // their positions. for (idx, subst) in substs.iter().enumerate() { - if let UnpackedKind::Type(ty) = subst.unpack() { - if let ty::Param(p) = ty.sty { + if let GenericArgKind::Type(ty) = subst.unpack() { + if let ty::Param(p) = ty.kind { if index_map.insert(p, idx).is_some() { // There was already an entry for `p`, meaning a generic parameter // was used twice. @@ -1569,7 +1607,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { &format!( "defining opaque type use restricts opaque \ type by using the generic parameter `{}` twice", - p.name + p, ), ); return; @@ -1590,11 +1628,11 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { let indices = concrete_type .subst(self.tcx, substs) .walk() - .filter_map(|t| match &t.sty { + .filter_map(|t| match &t.kind { ty::Param(p) => Some(*index_map.get(p).unwrap()), _ => None, }).collect(); - let is_param = |ty: Ty<'_>| match ty.sty { + let is_param = |ty: Ty<'_>| match ty.kind { ty::Param(_) => true, _ => false, }; @@ -1606,7 +1644,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } else if let Some((prev_span, prev_ty, ref prev_indices)) = self.found { let mut ty = concrete_type.walk().fuse(); let mut p_ty = prev_ty.walk().fuse(); - let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.sty, &p.sty) { + let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.kind, &p.kind) { // Type parameters are equal to any other type parameter for the purpose of // concrete type equality, as it is possible to obtain the same type just // by passing matching parameters to a function. @@ -1696,9 +1734,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - let scope = tcx.hir() - .get_defining_scope(hir_id) - .expect("could not get defining scope"); + let scope = tcx.hir().get_defining_scope(hir_id); let mut locator = ConstraintLocator { def_id, tcx, @@ -1748,7 +1784,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { pub fn get_infer_ret_ty(output: &'_ hir::FunctionRetTy) -> Option<&hir::Ty> { if let hir::FunctionRetTy::Return(ref ty) = output { - if let hir::TyKind::Infer = ty.node { + if let hir::TyKind::Infer = ty.kind { return Some(&**ty) } } @@ -1765,15 +1801,15 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { match tcx.hir().get(hir_id) { TraitItem(hir::TraitItem { - node: TraitItemKind::Method(MethodSig { header, decl }, TraitMethod::Provided(_)), + kind: TraitItemKind::Method(MethodSig { header, decl }, TraitMethod::Provided(_)), .. }) | ImplItem(hir::ImplItem { - node: ImplItemKind::Method(MethodSig { header, decl }, _), + kind: ImplItemKind::Method(MethodSig { header, decl }, _), .. }) | Item(hir::Item { - node: ItemKind::Fn(decl, header, _, _), + kind: ItemKind::Fn(decl, header, _, _), .. }) => match get_infer_ret_ty(&decl.output) { Some(ty) => { @@ -1795,24 +1831,23 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { }, TraitItem(hir::TraitItem { - node: TraitItemKind::Method(MethodSig { header, decl }, _), + kind: TraitItemKind::Method(MethodSig { header, decl }, _), .. }) => { AstConv::ty_of_fn(&icx, header.unsafety, header.abi, decl) }, ForeignItem(&hir::ForeignItem { - node: ForeignItemKind::Fn(ref fn_decl, _, _), + kind: ForeignItemKind::Fn(ref fn_decl, _, _), .. }) => { let abi = tcx.hir().get_foreign_abi(hir_id); compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi) } - Ctor(data) | Variant(Spanned { - node: hir::VariantKind { data, .. }, - .. - }) if data.ctor_hir_id().is_some() => { + Ctor(data) | Variant( + hir::Variant { data, .. } + ) if data.ctor_hir_id().is_some() => { let ty = tcx.type_of(tcx.hir().get_parent_did(hir_id)); let inputs = data.fields() .iter() @@ -1827,7 +1862,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { } Expr(&hir::Expr { - node: hir::ExprKind::Closure(..), + kind: hir::ExprKind::Closure(..), .. }) => { // Closure signatures are not like other function @@ -1840,7 +1875,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { // the signature of a closure, you should use the // `closure_sig` method on the `ClosureSubsts`: // - // closure_substs.closure_sig(def_id, tcx) + // closure_substs.sig(def_id, tcx) // // or, inside of an inference context, you can use // @@ -1858,7 +1893,7 @@ fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { let icx = ItemCtxt::new(tcx, def_id); let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - match tcx.hir().expect_item(hir_id).node { + match tcx.hir().expect_item(hir_id).kind { hir::ItemKind::Impl(.., ref opt_trait_ref, _, _) => { opt_trait_ref.as_ref().map(|ast_trait_ref| { let selfty = tcx.type_of(def_id); @@ -1869,10 +1904,30 @@ fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { } } -fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> hir::ImplPolarity { +fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity { let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - match tcx.hir().expect_item(hir_id).node { - hir::ItemKind::Impl(_, polarity, ..) => polarity, + let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl); + let item = tcx.hir().expect_item(hir_id); + match &item.kind { + hir::ItemKind::Impl(_, hir::ImplPolarity::Negative, ..) => { + if is_rustc_reservation { + tcx.sess.span_err(item.span, "reservation impls can't be negative"); + } + ty::ImplPolarity::Negative + } + hir::ItemKind::Impl(_, hir::ImplPolarity::Positive, _, _, None, _, _) => { + if is_rustc_reservation { + tcx.sess.span_err(item.span, "reservation impls can't be inherent"); + } + ty::ImplPolarity::Positive + } + hir::ItemKind::Impl(_, hir::ImplPolarity::Positive, _, _, Some(_tr), _, _) => { + if is_rustc_reservation { + ty::ImplPolarity::Reservation + } else { + ty::ImplPolarity::Positive + } + } ref item => bug!("impl_polarity: {:?} not an impl", item), } } @@ -2015,7 +2070,7 @@ fn explicit_predicates_of( let ast_generics = match node { Node::TraitItem(item) => &item.generics, - Node::ImplItem(item) => match item.node { + Node::ImplItem(item) => match item.kind { ImplItemKind::OpaqueTy(ref bounds) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); let opaque_ty = tcx.mk_opaque(def_id, substs); @@ -2036,7 +2091,7 @@ fn explicit_predicates_of( }, Node::Item(item) => { - match item.node { + match item.kind { ItemKind::Impl(_, _, defaultness, ref generics, ..) => { if defaultness.is_default() { is_default_impl_trait = tcx.impl_trait_ref(def_id); @@ -2093,7 +2148,7 @@ fn explicit_predicates_of( } } - Node::ForeignItem(item) => match item.node { + Node::ForeignItem(item) => match item.kind { ForeignItemKind::Static(..) => NO_GENERICS, ForeignItemKind::Fn(_, _, ref generics) => generics, ForeignItemKind::Type => NO_GENERICS, @@ -2178,7 +2233,7 @@ fn explicit_predicates_of( // That way, `where Ty:` is not a complete noop (see #53696) and `Ty` // is still checked for WF. if bound_pred.bounds.is_empty() { - if let ty::Param(_) = ty.sty { + if let ty::Param(_) = ty.kind { // This is a `where T:`, which can be in the HIR from the // transformation that moves `?Sized` to `T`'s declaration. // We can skip the predicate because type parameters are @@ -2241,7 +2296,7 @@ fn explicit_predicates_of( if let Some((self_trait_ref, trait_items)) = is_trait { predicates.extend(trait_items.iter().flat_map(|trait_item_ref| { let trait_item = tcx.hir().trait_item(trait_item_ref.id); - let bounds = match trait_item.node { + let bounds = match trait_item.kind { hir::TraitItemKind::Type(ref bounds, _) => bounds, _ => return Vec::new().into_iter() }; @@ -2270,7 +2325,7 @@ fn explicit_predicates_of( // in trait checking. See `setup_constraining_predicates` // for details. if let Node::Item(&Item { - node: ItemKind::Impl(..), + kind: ItemKind::Impl(..), .. }) = node { @@ -2328,7 +2383,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( abi: abi::Abi, ) -> ty::PolyFnSig<'tcx> { let unsafety = if abi == abi::Abi::RustIntrinsic { - intrisic_operation_unsafety(&*tcx.item_name(def_id).as_str()) + intrinsic_operation_unsafety(&*tcx.item_name(def_id).as_str()) } else { hir::Unsafety::Unsafe }; @@ -2377,10 +2432,10 @@ fn is_foreign_item(tcx: TyCtxt<'_>, def_id: DefId) -> bool { fn static_mutability(tcx: TyCtxt<'_>, def_id: DefId) -> Option { match tcx.hir().get_if_local(def_id) { Some(Node::Item(&hir::Item { - node: hir::ItemKind::Static(_, mutbl, _), .. + kind: hir::ItemKind::Static(_, mutbl, _), .. })) | Some(Node::ForeignItem( &hir::ForeignItem { - node: hir::ForeignItemKind::Static(_, mutbl), .. + kind: hir::ForeignItemKind::Static(_, mutbl), .. })) => Some(mutbl), Some(_) => None, _ => bug!("static_mutability applied to non-local def-id {:?}", def_id), @@ -2525,6 +2580,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { let whitelist = tcx.target_features_whitelist(LOCAL_CRATE); let mut inline_span = None; + let mut link_ordinal_span = None; for attr in attrs.iter() { if attr.check_name(sym::cold) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD; @@ -2558,6 +2614,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; } else if attr.check_name(sym::thread_local) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL; + } else if attr.check_name(sym::track_caller) { + if tcx.fn_sig(id).abi() != abi::Abi::Rust { + struct_span_err!( + tcx.sess, + attr.span, + E0737, + "rust ABI is required to use `#[track_caller]`" + ).emit(); + } + codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; } else if attr.check_name(sym::export_name) { if let Some(s) = attr.value_str() { if s.as_str().contains("\0") { @@ -2606,6 +2672,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } } else if attr.check_name(sym::link_name) { codegen_fn_attrs.link_name = attr.value_str(); + } else if attr.check_name(sym::link_ordinal) { + link_ordinal_span = Some(attr.span); + if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) { + codegen_fn_attrs.link_ordinal = ordinal; + } } } @@ -2613,7 +2684,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { if attr.path != sym::inline { return ia; } - match attr.meta().map(|i| i.node) { + match attr.meta().map(|i| i.kind) { Some(MetaItemKind::Word) => { mark_used(attr); InlineAttr::Hint @@ -2654,7 +2725,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { return ia; } let err = |sp, s| span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s); - match attr.meta().map(|i| i.node) { + match attr.meta().map(|i| i.kind) { Some(MetaItemKind::Word) => { err(attr.span, "expected one argument"); ia @@ -2683,6 +2754,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { // purpose functions as they wouldn't have the right target features // enabled. For that reason we also forbid #[inline(always)] as it can't be // respected. + if codegen_fn_attrs.target_features.len() > 0 { if codegen_fn_attrs.inline == InlineAttr::Always { if let Some(span) = inline_span { @@ -2707,6 +2779,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { codegen_fn_attrs.export_name = Some(name); codegen_fn_attrs.link_name = Some(name); } + check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span); // Internal symbols to the standard library all have no_mangle semantics in // that they have defined symbol names present in the function name. This @@ -2717,3 +2790,48 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { codegen_fn_attrs } + +fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option { + use syntax::ast::{Lit, LitIntType, LitKind}; + let meta_item_list = attr.meta_item_list(); + let meta_item_list: Option<&[ast::NestedMetaItem]> = meta_item_list.as_ref().map(Vec::as_ref); + let sole_meta_list = match meta_item_list { + Some([item]) => item.literal(), + _ => None, + }; + if let Some(Lit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) = sole_meta_list { + if *ordinal <= std::usize::MAX as u128 { + Some(*ordinal as usize) + } else { + let msg = format!( + "ordinal value in `link_ordinal` is too large: `{}`", + &ordinal + ); + tcx.sess.struct_span_err(attr.span, &msg) + .note("the value may not exceed `std::usize::MAX`") + .emit(); + None + } + } else { + tcx.sess.struct_span_err(attr.span, "illegal ordinal format in `link_ordinal`") + .note("an unsuffixed integer value, e.g., `1`, is expected") + .emit(); + None + } +} + +fn check_link_name_xor_ordinal( + tcx: TyCtxt<'_>, + codegen_fn_attrs: &CodegenFnAttrs, + inline_span: Option, +) { + if codegen_fn_attrs.link_name.is_none() || codegen_fn_attrs.link_ordinal.is_none() { + return; + } + let msg = "cannot use `#[link_name]` with `#[link_ordinal]`"; + if let Some(span) = inline_span { + tcx.sess.span_err(span, msg); + } else { + tcx.sess.err(msg); + } +} diff --git a/src/librustc_typeck/constrained_generic_params.rs b/src/librustc_typeck/constrained_generic_params.rs index 79a04b9423a8e..31476eb731798 100644 --- a/src/librustc_typeck/constrained_generic_params.rs +++ b/src/librustc_typeck/constrained_generic_params.rs @@ -20,10 +20,10 @@ impl From for Parameter { } /// Returns the set of parameters constrained by the impl header. -pub fn parameters_for_impl<'tcx>(impl_self_ty: Ty<'tcx>, - impl_trait_ref: Option>) - -> FxHashSet -{ +pub fn parameters_for_impl<'tcx>( + impl_self_ty: Ty<'tcx>, + impl_trait_ref: Option>, +) -> FxHashSet { let vec = match impl_trait_ref { Some(tr) => parameters_for(&tr, false), None => parameters_for(&impl_self_ty, false), @@ -36,12 +36,10 @@ pub fn parameters_for_impl<'tcx>(impl_self_ty: Ty<'tcx>, /// uniquely determined by `t` (see RFC 447). If it is true, return the list /// of parameters whose values are needed in order to constrain `ty` - these /// differ, with the latter being a superset, in the presence of projections. -pub fn parameters_for<'tcx, T>(t: &T, - include_nonconstraining: bool) - -> Vec - where T: TypeFoldable<'tcx> -{ - +pub fn parameters_for<'tcx>( + t: &impl TypeFoldable<'tcx>, + include_nonconstraining: bool, +) -> Vec { let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining, @@ -57,7 +55,7 @@ struct ParameterCollector { impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.sty { + match t.kind { ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => { // projections are not injective return false; diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs index 90118a9f191d9..ef08e8d4f0b7a 100644 --- a/src/librustc_typeck/error_codes.rs +++ b/src/librustc_typeck/error_codes.rs @@ -1,6 +1,6 @@ // ignore-tidy-filelength -register_long_diagnostics! { +syntax::register_diagnostics! { E0023: r##" A pattern used to match against an enum variant must provide a sub-pattern for @@ -212,7 +212,7 @@ match string { E0033: r##" This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a pattern. Every trait defines a type, but because the -size of trait implementors isn't fixed, this type has no compile-time size. +size of trait implementers isn't fixed, this type has no compile-time size. Therefore, all accesses to trait types must be through pointers. If you encounter this error you should try to avoid dereferencing the pointer. @@ -1718,22 +1718,6 @@ Since we know for certain that `Wrapper` implements `Clone`, there's no reason to also specify it in a `where` clause. "##, -E0194: r##" -A type parameter was declared which shadows an existing one. An example of this -error: - -```compile_fail,E0194 -trait Foo { - fn do_something(&self) -> T; - fn do_something_else(&self, bar: T); -} -``` - -In this example, the trait `Foo` and the trait method `do_something_else` both -define a type parameter `T`. This is not allowed: if the method wishes to -define a type parameter, it must use a different name for it. -"##, - E0195: r##" Your method's lifetime parameters do not match the trait declaration. Erroneous code example: @@ -1889,13 +1873,14 @@ This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this differs from the behavior for `&T`, which is always `Copy`). "##, -/* E0205: r##" +#### Note: this error code is no longer emitted by the compiler. + An attempt to implement the `Copy` trait for an enum failed because one of the variants does not implement `Copy`. To fix this, you must implement `Copy` for the mentioned variant. Note that this may not be possible, as in the example of -```compile_fail,E0205 +```compile_fail,E0204 enum Foo { Bar(Vec), Baz, @@ -1908,7 +1893,7 @@ This fails because `Vec` does not implement `Copy` for any `T`. Here's another example that will fail: -```compile_fail,E0205 +```compile_fail,E0204 #[derive(Copy)] enum Foo<'a> { Bar(&'a mut bool), @@ -1919,7 +1904,6 @@ enum Foo<'a> { This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this differs from the behavior for `&T`, which is always `Copy`). "##, -*/ E0206: r##" You can only implement `Copy` for a struct or enum. Both of the following @@ -2142,8 +2126,9 @@ For information on the design of the orphan rules, see [RFC 1023]. [RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md "##, -/* E0211: r##" +#### Note: this error code is no longer emitted by the compiler. + You used a function or type which doesn't fit the requirements for where it was used. Erroneous code examples: @@ -2190,7 +2175,7 @@ extern "rust-intrinsic" { } ``` -The second case example is a bit particular : the main function must always +The second case example is a bit particular: the main function must always have this definition: ```compile_fail @@ -2222,7 +2207,6 @@ impl Foo { } ``` "##, - */ E0220: r##" You used an associated type which isn't defined in the trait. @@ -2441,6 +2425,87 @@ struct Bar { x: Foo } ``` "##, +E0307: r##" +This error indicates that the `self` parameter in a method has an invalid +"reciever type". + +Methods take a special first parameter, of which there are three variants: +`self`, `&self`, and `&mut self`. These are syntactic sugar for +`self: Self`, `self: &Self`, and `self: &mut Self` respectively. + +``` +# struct Foo; +trait Trait { + fn foo(&self); +// ^^^^^ `self` here is a reference to the receiver object +} + +impl Trait for Foo { + fn foo(&self) {} +// ^^^^^ the receiver type is `&Foo` +} +``` + +The type `Self` acts as an alias to the type of the current trait +implementer, or "receiver type". Besides the already mentioned `Self`, +`&Self` and `&mut Self` valid receiver types, the following are also valid: +`self: Box`, `self: Rc`, `self: Arc`, and `self: Pin

` +(where P is one of the previous types except `Self`). Note that `Self` can +also be the underlying implementing type, like `Foo` in the following +example: + +``` +# struct Foo; +# trait Trait { +# fn foo(&self); +# } +impl Trait for Foo { + fn foo(self: &Foo) {} +} +``` + +E0307 will be emitted by the compiler when using an invalid reciver type, +like in the following example: + +```compile_fail,E0307 +# struct Foo; +# struct Bar; +# trait Trait { +# fn foo(&self); +# } +impl Trait for Foo { + fn foo(self: &Bar) {} +} +``` + +The nightly feature [Arbintrary self types][AST] extends the accepted +set of receiver types to also include any type that can dereference to +`Self`: + +``` +#![feature(arbitrary_self_types)] + +struct Foo; +struct Bar; + +// Because you can dereference `Bar` into `Foo`... +impl std::ops::Deref for Bar { + type Target = Foo; + + fn deref(&self) -> &Foo { + &Foo + } +} + +impl Foo { + fn foo(self: Bar) {} +// ^^^^^^^^^ ...it can be used as the receiver type +} +``` + +[AST]: https://doc.rust-lang.org/unstable-book/language-features/arbitrary-self-types.html +"##, + E0321: r##" A cross-crate opt-out trait was implemented on something which wasn't a struct or enum type. Erroneous code example: @@ -2662,14 +2727,9 @@ impl CoerceUnsized> for MyType [`CoerceUnsized`]: https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html "##, -/* -// Associated consts can now be accessed through generic type parameters, and -// this error is no longer emitted. -// -// FIXME: consider whether to leave it in the error index, or remove it entirely -// as associated consts is not stabilized yet. - E0329: r##" +#### Note: this error code is no longer emitted by the compiler. + An attempt was made to access an associated constant through either a generic type parameter or `Self`. This is not supported yet. An example causing this error is shown below: @@ -2700,12 +2760,15 @@ trait Foo { struct MyStruct; +impl Foo for MyStruct { + const BAR: f64 = 0f64; +} + fn get_bar_good() -> f64 { ::BAR } ``` "##, -*/ E0366: r##" An attempt was made to implement `Drop` on a concrete specialization of a @@ -3545,6 +3608,43 @@ match r { ``` "##, +E0533: r##" +An item which isn't a unit struct, a variant, nor a constant has been used as a +match pattern. + +Erroneous code example: + +```compile_fail,E0533 +struct Tortoise; + +impl Tortoise { + fn turtle(&self) -> u32 { 0 } +} + +match 0u32 { + Tortoise::turtle => {} // Error! + _ => {} +} +if let Tortoise::turtle = 0u32 {} // Same error! +``` + +If you want to match against a value returned by a method, you need to bind the +value first: + +``` +struct Tortoise; + +impl Tortoise { + fn turtle(&self) -> u32 { 0 } +} + +match 0u32 { + x if x == Tortoise.turtle() => {} // Bound into `x` then we compare it! + _ => {} +} +``` +"##, + E0534: r##" The `inline` attribute was malformed. @@ -4767,7 +4867,6 @@ E0733: r##" Recursion in an `async fn` requires boxing. For example, this will not compile: ```edition2018,compile_fail,E0733 -#![feature(async_await)] async fn foo(n: usize) { if n > 0 { foo(n - 1).await; @@ -4779,12 +4878,11 @@ To achieve async recursion, the `async fn` needs to be desugared such that the `Future` is explicit in the return type: ```edition2018,compile_fail,E0720 -# #![feature(async_await)] use std::future::Future; -fn foo_desugered(n: usize) -> impl Future { +fn foo_desugared(n: usize) -> impl Future { async move { if n > 0 { - foo_desugered(n - 1).await; + foo_desugared(n - 1).await; } } } @@ -4793,7 +4891,6 @@ fn foo_desugered(n: usize) -> impl Future { Finally, the future is wrapped in a pinned box: ```edition2018 -# #![feature(async_await)] use std::future::Future; use std::pin::Pin; fn foo_recursive(n: usize) -> Pin>> { @@ -4809,9 +4906,75 @@ The `Box<...>` ensures that the result is of known size, and the pin is required to keep it in the same place in memory. "##, -} // (end of detailed error messages) +E0737: r##" +#[track_caller] requires functions to have the "Rust" ABI for implicitly +receiving caller location. See [RFC 2091] for details on this and other +restrictions. + +Erroneous code example: + +```compile_fail,E0737 +#![feature(track_caller)] + +#[track_caller] +extern "C" fn foo() {} +``` + +[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md +"##, + +E0738: r##" +#[track_caller] cannot be used in traits yet. This is due to limitations in the +compiler which are likely to be temporary. See [RFC 2091] for details on this +and other restrictions. + +Erroneous example with a trait method implementation: + +```compile_fail,E0738 +#![feature(track_caller)] + +trait Foo { + fn bar(&self); +} + +impl Foo for u64 { + #[track_caller] + fn bar(&self) {} +} +``` + +Erroneous example with a blanket trait method implementation: + +```compile_fail,E0738 +#![feature(track_caller)] + +trait Foo { + #[track_caller] + fn bar(&self) {} + fn baz(&self); +} +``` + +Erroneous example with a trait method declaration: + +```compile_fail,E0738 +#![feature(track_caller)] + +trait Foo { + fn bar(&self) {} + + #[track_caller] + fn baz(&self); +} +``` + +Note that while the compiler may be able to support the attribute in traits in +the future, [RFC 2091] prohibits their implementation without a follow-up RFC. + +[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md +"##, -register_diagnostics! { +; // E0035, merged into E0087/E0089 // E0036, merged into E0087/E0089 // E0068, @@ -4837,6 +5000,7 @@ register_diagnostics! { // E0188, // can not cast an immutable reference to a mutable pointer // E0189, // deprecated: can only cast a boxed pointer to a boxed object // E0190, // deprecated: can only cast a &-pointer to an &-object +// E0194, // merged into E0403 // E0196, // cannot determine a type for this closure E0203, // type parameter has more than one relaxed default bound, // and only one is supported @@ -4867,17 +5031,16 @@ register_diagnostics! { // E0245, // not a trait // E0246, // invalid recursive type // E0247, -// E0248, // value used as a type, now reported earlier during resolution as E0412 +// E0248, // value used as a type, now reported earlier during resolution + // as E0412 // E0249, - E0307, // invalid method `self` type // E0319, // trait impls for defaulted traits allowed just for structs/enums // E0372, // coherence not object safe E0377, // the trait `CoerceUnsized` may only be implemented for a coercion // between structures with the same definition // E0558, // replaced with a generic attribute input check - E0533, // `{}` does not name a unit variant, unit struct or a constant -// E0563, // cannot determine a type for this `impl Trait`: {} // removed in 6383de15 - E0564, // only named lifetimes are allowed in `impl Trait`, +// E0563, // cannot determine a type for this `impl Trait` removed in 6383de15 +// E0564, // only named lifetimes are allowed in `impl Trait`, // but `{}` was found in the type `{}` E0587, // type has conflicting packed and align representation hints E0588, // packed type cannot transitively contain a `[repr(align)]` type @@ -4885,12 +5048,12 @@ register_diagnostics! { // E0612, // merged into E0609 // E0613, // Removed (merged with E0609) E0627, // yield statement outside of generator literal - E0632, // cannot provide explicit type parameters when `impl Trait` is used in - // argument position. + E0632, // cannot provide explicit type parameters when `impl Trait` is used + // in argument position. E0634, // type has conflicting packed representaton hints E0640, // infer outlives requirements E0641, // cannot cast to/from a pointer with an unknown kind - E0645, // trait aliases not finished +// E0645, // trait aliases not finished E0719, // duplicate values for associated type binding E0722, // Malformed `#[optimize]` attribute E0724, // `#[ffi_returns_twice]` is only allowed in foreign functions diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs index fcfd9adef54df..ab660caa222ae 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -12,7 +12,7 @@ use crate::constrained_generic_params as cgp; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::def_id::DefId; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc::ty::query::Providers; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use std::collections::hash_map::Entry::{Occupied, Vacant}; @@ -54,7 +54,7 @@ pub fn impl_wf_check(tcx: TyCtxt<'_>) { // but it's one that we must perform earlier than the rest of // WfCheck. for &module in tcx.hir().krate().modules.keys() { - tcx.ensure().check_mod_impl_wf(tcx.hir().local_def_id_from_node_id(module)); + tcx.ensure().check_mod_impl_wf(tcx.hir().local_def_id(module)); } } @@ -78,7 +78,7 @@ struct ImplWfCheck<'tcx> { impl ItemLikeVisitor<'tcx> for ImplWfCheck<'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { - if let hir::ItemKind::Impl(.., ref impl_item_refs) = item.node { + if let hir::ItemKind::Impl(.., ref impl_item_refs) = item.kind { let impl_def_id = self.tcx.hir().local_def_id(item.hir_id); enforce_impl_params_are_constrained(self.tcx, impl_def_id, @@ -99,6 +99,15 @@ fn enforce_impl_params_are_constrained( ) { // Every lifetime used in an associated type must be constrained. let impl_self_ty = tcx.type_of(impl_def_id); + if impl_self_ty.references_error() { + // Don't complain about unconstrained type params when self ty isn't known due to errors. + // (#36836) + tcx.sess.delay_span_bug( + tcx.def_span(impl_def_id), + "potentially unconstrained type parameters weren't evaluated", + ); + return; + } let impl_generics = tcx.generics_of(impl_def_id); let impl_predicates = tcx.predicates_of(impl_def_id); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); @@ -188,7 +197,7 @@ fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_item_refs: &[hir::ImplI let mut seen_value_items = FxHashMap::default(); for impl_item_ref in impl_item_refs { let impl_item = tcx.hir().impl_item(impl_item_ref.id); - let seen_items = match impl_item.node { + let seen_items = match impl_item.kind { hir::ImplItemKind::TyAlias(_) => &mut seen_type_items, _ => &mut seen_value_items, }; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 9d9a9d9b559e4..9374113e1c950 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -65,11 +65,8 @@ This API is completely unstable and subject to change. #![feature(exhaustive_patterns)] #![feature(in_band_lifetimes)] #![feature(nll)] -#![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] #![feature(never_type)] -#![feature(inner_deref)] -#![feature(mem_take)] #![recursion_limit="256"] @@ -78,9 +75,7 @@ This API is completely unstable and subject to change. #[macro_use] extern crate rustc; -// N.B., this module needs to be declared first so diagnostics are -// registered before they are used. -mod error_codes; +pub mod error_codes; mod astconv; mod check; @@ -162,10 +157,10 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { let main_id = tcx.hir().as_local_hir_id(main_def_id).unwrap(); let main_span = tcx.def_span(main_def_id); let main_t = tcx.type_of(main_def_id); - match main_t.sty { + match main_t.kind { ty::FnDef(..) => { if let Some(Node::Item(it)) = tcx.hir().find(main_id) { - if let hir::ItemKind::Fn(.., ref generics, _) = it.node { + if let hir::ItemKind::Fn(.., ref generics, _) = it.kind { let mut error = false; if !generics.params.is_empty() { let msg = "`main` function is not allowed to have generic \ @@ -227,10 +222,10 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { let start_id = tcx.hir().as_local_hir_id(start_def_id).unwrap(); let start_span = tcx.def_span(start_def_id); let start_t = tcx.type_of(start_def_id); - match start_t.sty { + match start_t.kind { ty::FnDef(..) => { if let Some(Node::Item(it)) = tcx.hir().find(start_id) { - if let hir::ItemKind::Fn(.., ref generics, _) = it.node { + if let hir::ItemKind::Fn(.., ref generics, _) = it.kind { let mut error = false; if !generics.params.is_empty() { struct_span_err!(tcx.sess, generics.span, E0132, @@ -298,7 +293,7 @@ pub fn provide(providers: &mut Providers<'_>) { } pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> { - tcx.sess.profiler(|p| p.start_activity("type-check crate")); + let _prof_timer = tcx.prof.generic_activity("type_check_crate"); // this ensures that later parts of type checking can assume that items // have valid types and not error @@ -306,7 +301,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> { tcx.sess.track_errors(|| { time(tcx.sess, "type collecting", || { for &module in tcx.hir().krate().modules.keys() { - tcx.ensure().collect_mod_item_types(tcx.hir().local_def_id_from_node_id(module)); + tcx.ensure().collect_mod_item_types(tcx.hir().local_def_id(module)); } }); })?; @@ -341,7 +336,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> { time(tcx.sess, "item-types checking", || { for &module in tcx.hir().krate().modules.keys() { - tcx.ensure().check_mod_item_types(tcx.hir().local_def_id_from_node_id(module)); + tcx.ensure().check_mod_item_types(tcx.hir().local_def_id(module)); } }); @@ -350,8 +345,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> { check_unused::check_crate(tcx); check_for_entry_fn(tcx); - tcx.sess.profiler(|p| p.end_activity("type-check crate")); - if tcx.sess.err_count() == 0 { Ok(()) } else { @@ -389,5 +382,3 @@ pub fn hir_trait_to_predicates<'tcx>( bounds } - -__build_diagnostic_array! { librustc_typeck, DIAGNOSTICS } diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs index 6b288347ad006..433d04ffa64ff 100644 --- a/src/librustc_typeck/outlives/implicit_infer.rs +++ b/src/librustc_typeck/outlives/implicit_infer.rs @@ -1,9 +1,8 @@ use rustc::hir::{self, Node}; use rustc::hir::def_id::DefId; use rustc::hir::itemlikevisit::ItemLikeVisitor; -use rustc::ty::subst::{Kind, Subst, UnpackedKind}; +use rustc::ty::subst::{GenericArg, Subst, GenericArgKind}; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::fold::TypeFoldable; use rustc::util::nodemap::FxHashMap; use super::explicit::ExplicitPredicatesMap; @@ -67,7 +66,7 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> { }; let mut item_required_predicates = RequiredPredicates::default(); - match item.node { + match item.kind { hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) => { let adt_def = self.tcx.adt_def(item_did); @@ -124,7 +123,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( explicit_map: &mut ExplicitPredicatesMap<'tcx>, ) { for ty in field_ty.walk() { - match ty.sty { + match ty.kind { // The field is of type &'a T which means that we will have // a predicate requirement of T: 'a (T outlives 'a). // @@ -178,11 +177,11 @@ fn insert_required_predicates_to_be_wf<'tcx>( // let _: () = substs.region_at(0); check_explicit_predicates( tcx, - &def.did, + def.did, substs, required_predicates, explicit_map, - IgnoreSelfTy(false), + None, ); } @@ -208,11 +207,11 @@ fn insert_required_predicates_to_be_wf<'tcx>( .substs; check_explicit_predicates( tcx, - &ex_trait_ref.skip_binder().def_id, + ex_trait_ref.skip_binder().def_id, substs, required_predicates, explicit_map, - IgnoreSelfTy(true), + Some(tcx.types.self_param), ); } } @@ -223,11 +222,11 @@ fn insert_required_predicates_to_be_wf<'tcx>( debug!("Projection"); check_explicit_predicates( tcx, - &tcx.associated_item(obj.item_def_id).container.id(), + tcx.associated_item(obj.item_def_id).container.id(), obj.substs, required_predicates, explicit_map, - IgnoreSelfTy(false), + None, ); } @@ -236,9 +235,6 @@ fn insert_required_predicates_to_be_wf<'tcx>( } } -#[derive(Debug)] -pub struct IgnoreSelfTy(bool); - /// We also have to check the explicit predicates /// declared on the type. /// @@ -256,25 +252,25 @@ pub struct IgnoreSelfTy(bool); /// applying the substitution as above. pub fn check_explicit_predicates<'tcx>( tcx: TyCtxt<'tcx>, - def_id: &DefId, - substs: &[Kind<'tcx>], + def_id: DefId, + substs: &[GenericArg<'tcx>], required_predicates: &mut RequiredPredicates<'tcx>, explicit_map: &mut ExplicitPredicatesMap<'tcx>, - ignore_self_ty: IgnoreSelfTy, + ignored_self_ty: Option>, ) { debug!( "check_explicit_predicates(def_id={:?}, \ substs={:?}, \ explicit_map={:?}, \ required_predicates={:?}, \ - ignore_self_ty={:?})", + ignored_self_ty={:?})", def_id, substs, explicit_map, required_predicates, - ignore_self_ty, + ignored_self_ty, ); - let explicit_predicates = explicit_map.explicit_predicates_of(tcx, *def_id); + let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id); for outlives_predicate in explicit_predicates.iter() { debug!("outlives_predicate = {:?}", &outlives_predicate); @@ -313,9 +309,9 @@ pub fn check_explicit_predicates<'tcx>( // = X` binding from the object type (there must be such a // binding) and thus infer an outlives requirement that `X: // 'b`. - if ignore_self_ty.0 { - if let UnpackedKind::Type(ty) = outlives_predicate.0.unpack() { - if ty.has_self_ty() { + if let Some(self_ty) = ignored_self_ty { + if let GenericArgKind::Type(ty) = outlives_predicate.0.unpack() { + if ty.walk().any(|ty| ty == self_ty) { debug!("skipping self ty = {:?}", &ty); continue; } diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs index 6b8f6fccd40d7..cdb83eb328ac2 100644 --- a/src/librustc_typeck/outlives/mod.rs +++ b/src/librustc_typeck/outlives/mod.rs @@ -2,7 +2,7 @@ use hir::Node; use rustc::hir; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::ty::query::Providers; -use rustc::ty::subst::UnpackedKind; +use rustc::ty::subst::GenericArgKind; use rustc::ty::{self, CratePredicatesMap, TyCtxt}; use syntax::symbol::sym; @@ -30,7 +30,7 @@ fn inferred_outlives_of( .expect("expected local def-id"); match tcx.hir().get(id) { - Node::Item(item) => match item.node { + Node::Item(item) => match item.kind { hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..) => { let crate_map = tcx.inferred_outlives_crate(LOCAL_CRATE); @@ -100,17 +100,17 @@ fn inferred_outlives_crate( .iter() .filter_map( |ty::OutlivesPredicate(kind1, region2)| match kind1.unpack() { - UnpackedKind::Type(ty1) => { + GenericArgKind::Type(ty1) => { Some(ty::Predicate::TypeOutlives(ty::Binder::bind( ty::OutlivesPredicate(ty1, region2) ))) } - UnpackedKind::Lifetime(region1) => { + GenericArgKind::Lifetime(region1) => { Some(ty::Predicate::RegionOutlives( ty::Binder::bind(ty::OutlivesPredicate(region1, region2)) )) } - UnpackedKind::Const(_) => { + GenericArgKind::Const(_) => { // Generic consts don't impose any constraints. None } diff --git a/src/librustc_typeck/outlives/utils.rs b/src/librustc_typeck/outlives/utils.rs index 783890da639f4..d34605dc482a3 100644 --- a/src/librustc_typeck/outlives/utils.rs +++ b/src/librustc_typeck/outlives/utils.rs @@ -1,18 +1,19 @@ use rustc::ty::outlives::Component; -use rustc::ty::subst::{Kind, UnpackedKind}; +use rustc::ty::subst::{GenericArg, GenericArgKind}; use rustc::ty::{self, Region, RegionKind, Ty, TyCtxt}; use smallvec::smallvec; use std::collections::BTreeSet; /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred /// must be added to the struct header. -pub type RequiredPredicates<'tcx> = BTreeSet, ty::Region<'tcx>>>; +pub type RequiredPredicates<'tcx> = + BTreeSet, ty::Region<'tcx>>>; /// Given a requirement `T: 'a` or `'b: 'a`, deduce the /// outlives_component and add it to `required_predicates` pub fn insert_outlives_predicate<'tcx>( tcx: TyCtxt<'tcx>, - kind: Kind<'tcx>, + kind: GenericArg<'tcx>, outlived_region: Region<'tcx>, required_predicates: &mut RequiredPredicates<'tcx>, ) { @@ -23,7 +24,7 @@ pub fn insert_outlives_predicate<'tcx>( } match kind.unpack() { - UnpackedKind::Type(ty) => { + GenericArgKind::Type(ty) => { // `T: 'outlived_region` for some type `T` // But T could be a lot of things: // e.g., if `T = &'b u32`, then `'b: 'outlived_region` is @@ -112,14 +113,14 @@ pub fn insert_outlives_predicate<'tcx>( } } - UnpackedKind::Lifetime(r) => { + GenericArgKind::Lifetime(r) => { if !is_free_region(tcx, r) { return; } required_predicates.insert(ty::OutlivesPredicate(kind, outlived_region)); } - UnpackedKind::Const(_) => { + GenericArgKind::Const(_) => { // Generic consts don't impose any constraints. } } @@ -160,9 +161,14 @@ fn is_free_region(tcx: TyCtxt<'_>, region: Region<'_>) -> bool { // ignore it. We can't put it on the struct header anyway. RegionKind::ReLateBound(..) => false, + // This can appear in `where Self: ` bounds (#64855): + // + // struct Bar(::Type) where Self: ; + // struct Baz<'a>(&'a Self) where Self: ; + RegionKind::ReEmpty => false, + // These regions don't appear in types from type declarations: - RegionKind::ReEmpty - | RegionKind::ReErased + RegionKind::ReErased | RegionKind::ReClosureBound(..) | RegionKind::ReScope(..) | RegionKind::ReVar(..) diff --git a/src/librustc_typeck/structured_errors.rs b/src/librustc_typeck/structured_errors.rs index 3e3eab8cf4cfb..273a36edc56ff 100644 --- a/src/librustc_typeck/structured_errors.rs +++ b/src/librustc_typeck/structured_errors.rs @@ -48,7 +48,7 @@ impl<'tcx> StructuredDiagnostic<'tcx> for VariadicError<'tcx> { fn session(&self) -> &Session { self.sess } fn code(&self) -> DiagnosticId { - __diagnostic_used!(E0617); + syntax::diagnostic_used!(E0617); DiagnosticId::Error("E0617".to_owned()) } @@ -104,7 +104,7 @@ impl<'tcx> StructuredDiagnostic<'tcx> for SizedUnsizedCastError<'tcx> { fn session(&self) -> &Session { self.sess } fn code(&self) -> DiagnosticId { - __diagnostic_used!(E0607); + syntax::diagnostic_used!(E0607); DiagnosticId::Error("E0607".to_owned()) } diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index b75a0912657fa..4431abdaf50a0 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -4,7 +4,7 @@ //! We walk the set of items and, for each member, generate new constraints. use hir::def_id::DefId; -use rustc::ty::subst::{SubstsRef, UnpackedKind}; +use rustc::ty::subst::{SubstsRef, GenericArgKind}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; @@ -68,7 +68,7 @@ pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>) impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { - match item.node { + match item.kind { hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => { self.visit_node_helper(item.hir_id); @@ -82,8 +82,8 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { self.visit_node_helper(item.hir_id); for variant in &enum_def.variants { - if let hir::VariantData::Tuple(..) = variant.node.data { - self.visit_node_helper(variant.node.data.ctor_hir_id().unwrap()); + if let hir::VariantData::Tuple(..) = variant.data { + self.visit_node_helper(variant.data.ctor_hir_id().unwrap()); } } } @@ -94,7 +94,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { hir::ItemKind::ForeignMod(ref foreign_mod) => { for foreign_item in &foreign_mod.items { - if let hir::ForeignItemKind::Fn(..) = foreign_item.node { + if let hir::ForeignItemKind::Fn(..) = foreign_item.kind { self.visit_node_helper(foreign_item.hir_id); } } @@ -105,13 +105,13 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { } fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { - if let hir::TraitItemKind::Method(..) = trait_item.node { + if let hir::TraitItemKind::Method(..) = trait_item.kind { self.visit_node_helper(trait_item.hir_id); } } fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { - if let hir::ImplItemKind::Method(..) = impl_item.node { + if let hir::ImplItemKind::Method(..) = impl_item.kind { self.visit_node_helper(impl_item.hir_id); } } @@ -140,7 +140,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { let id = tcx.hir().as_local_hir_id(def_id).unwrap(); let inferred_start = self.terms_cx.inferred_starts[&id]; let current_item = &CurrentItem { inferred_start }; - match tcx.type_of(def_id).sty { + match tcx.type_of(def_id).kind { ty::Adt(def, _) => { // Not entirely obvious: constraints on structs/enums do not // affect the variance of their type parameters. See discussion @@ -232,13 +232,13 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { for k in substs { match k.unpack() { - UnpackedKind::Lifetime(lt) => { + GenericArgKind::Lifetime(lt) => { self.add_constraints_from_region(current, lt, variance_i) } - UnpackedKind::Type(ty) => { + GenericArgKind::Type(ty) => { self.add_constraints_from_ty(current, ty, variance_i) } - UnpackedKind::Const(_) => { + GenericArgKind::Const(_) => { // Consts impose no constraints. } } @@ -256,7 +256,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ty, variance); - match ty.sty { + match ty.kind { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never | ty::Foreign(..) => { // leaf type -- noop @@ -387,13 +387,13 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { variance_decl, variance_i); match k.unpack() { - UnpackedKind::Lifetime(lt) => { + GenericArgKind::Lifetime(lt) => { self.add_constraints_from_region(current, lt, variance_i) } - UnpackedKind::Type(ty) => { + GenericArgKind::Type(ty) => { self.add_constraints_from_ty(current, ty, variance_i) } - UnpackedKind::Const(_) => { + GenericArgKind::Const(_) => { // Consts impose no constraints. } } diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs index 343d7ea656fbb..745dbee5fd320 100644 --- a/src/librustc_typeck/variance/mod.rs +++ b/src/librustc_typeck/variance/mod.rs @@ -49,7 +49,7 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] { span_bug!(tcx.hir().span(id), "asked to compute variance for wrong kind of item") }; match tcx.hir().get(id) { - Node::Item(item) => match item.node { + Node::Item(item) => match item.kind { hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | @@ -58,19 +58,19 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] { _ => unsupported() }, - Node::TraitItem(item) => match item.node { + Node::TraitItem(item) => match item.kind { hir::TraitItemKind::Method(..) => {} _ => unsupported() }, - Node::ImplItem(item) => match item.node { + Node::ImplItem(item) => match item.kind { hir::ImplItemKind::Method(..) => {} _ => unsupported() }, - Node::ForeignItem(item) => match item.node { + Node::ForeignItem(item) => match item.kind { hir::ForeignItemKind::Fn(..) => {} _ => unsupported() diff --git a/src/librustc_typeck/variance/solve.rs b/src/librustc_typeck/variance/solve.rs index 1176c5ebb3d30..fbd476ef832c4 100644 --- a/src/librustc_typeck/variance/solve.rs +++ b/src/librustc_typeck/variance/solve.rs @@ -109,7 +109,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { self.enforce_const_invariance(generics, variances); // Functions are permitted to have unused generic parameters: make those invariant. - if let ty::FnDef(..) = tcx.type_of(def_id).sty { + if let ty::FnDef(..) = tcx.type_of(def_id).kind { for variance in variances.iter_mut() { if *variance == ty::Bivariant { *variance = ty::Invariant; diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index 7af7c79bb3c0d..863a0b267fddd 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -131,7 +131,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { debug!("add_inferreds for item {}", self.tcx.hir().node_to_string(item.hir_id)); - match item.node { + match item.kind { hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => { self.add_inferreds_for_item(item.hir_id); @@ -145,8 +145,8 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { self.add_inferreds_for_item(item.hir_id); for variant in &enum_def.variants { - if let hir::VariantData::Tuple(..) = variant.node.data { - self.add_inferreds_for_item(variant.node.data.ctor_hir_id().unwrap()); + if let hir::VariantData::Tuple(..) = variant.data { + self.add_inferreds_for_item(variant.data.ctor_hir_id().unwrap()); } } } @@ -157,7 +157,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { hir::ItemKind::ForeignMod(ref foreign_mod) => { for foreign_item in &foreign_mod.items { - if let hir::ForeignItemKind::Fn(..) = foreign_item.node { + if let hir::ForeignItemKind::Fn(..) = foreign_item.kind { self.add_inferreds_for_item(foreign_item.hir_id); } } @@ -168,13 +168,13 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { } fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { - if let hir::TraitItemKind::Method(..) = trait_item.node { + if let hir::TraitItemKind::Method(..) = trait_item.kind { self.add_inferreds_for_item(trait_item.hir_id); } } fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { - if let hir::ImplItemKind::Method(..) = impl_item.node { + if let hir::ImplItemKind::Method(..) = impl_item.kind { self.add_inferreds_for_item(impl_item.hir_id); } } diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 334dc74c6c8f7..e3de7fe20493e 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -11,6 +11,5 @@ path = "lib.rs" [dependencies] pulldown-cmark = { version = "0.5.3", default-features = false } minifier = "0.0.33" -rayon = { version = "0.2.0", package = "rustc-rayon" } +rayon = { version = "0.3.0", package = "rustc-rayon" } tempfile = "3" -parking_lot = "0.7" diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 5a4dc7be326d2..18a84cd0eeb76 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -119,7 +119,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { source: Span::empty(), name: None, attrs: Default::default(), - visibility: None, + visibility: Inherited, def_id: self.cx.next_def_id(param_env_def_id.krate), stability: None, deprecation: None, @@ -464,7 +464,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { // it is *not* required (i.e., '?Sized') let sized_trait = self.cx .tcx - .require_lang_item(lang_items::SizedTraitLangItem); + .require_lang_item(lang_items::SizedTraitLangItem, None); let mut replacer = RegionReplacer { vid_to_region: &vid_to_region, @@ -777,9 +777,9 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { fn is_fn_ty(&self, tcx: TyCtxt<'_>, ty: &Type) -> bool { match &ty { &&Type::ResolvedPath { ref did, .. } => { - *did == tcx.require_lang_item(lang_items::FnTraitLangItem) - || *did == tcx.require_lang_item(lang_items::FnMutTraitLangItem) - || *did == tcx.require_lang_item(lang_items::FnOnceTraitLangItem) + *did == tcx.require_lang_item(lang_items::FnTraitLangItem, None) + || *did == tcx.require_lang_item(lang_items::FnMutTraitLangItem, None) + || *did == tcx.require_lang_item(lang_items::FnOnceTraitLangItem, None) } _ => false, } diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 5c42d705bd579..afed11e7fab26 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -3,10 +3,9 @@ use rustc::traits; use rustc::ty::ToPredicate; use rustc::ty::subst::Subst; use rustc::infer::InferOk; +use rustc::hir::def_id::LOCAL_CRATE; use syntax_pos::DUMMY_SP; -use crate::core::DocAccessLevels; - use super::*; pub struct BlanketImplFinder<'a, 'tcx> { @@ -29,8 +28,8 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { debug!("get_blanket_impls({:?})", ty); let mut impls = Vec::new(); - for &trait_def_id in self.cx.all_traits.iter() { - if !self.cx.renderinfo.borrow().access_levels.is_doc_reachable(trait_def_id) || + for &trait_def_id in self.cx.tcx.all_traits(LOCAL_CRATE).iter() { + if !self.cx.renderinfo.borrow().access_levels.is_public(trait_def_id) || self.cx.generated_synthetics .borrow_mut() .get(&(ty, trait_def_id)) @@ -42,7 +41,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { trait_def_id, impl_def_id); let trait_ref = self.cx.tcx.impl_trait_ref(impl_def_id).unwrap(); let may_apply = self.cx.tcx.infer_ctxt().enter(|infcx| { - match trait_ref.self_ty().sty { + match trait_ref.self_ty().kind { ty::Param(_) => {}, _ => return false, } @@ -100,7 +99,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { source: self.cx.tcx.def_span(impl_def_id).clean(self.cx), name: None, attrs: Default::default(), - visibility: None, + visibility: Inherited, def_id: self.cx.next_def_id(impl_def_id.krate), stability: None, deprecation: None, diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index b9b3e621bb740..da3b52afadffb 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -68,9 +68,9 @@ impl Cfg { span: cfg.span }), }; - match cfg.node { + match cfg.kind { MetaItemKind::Word => Ok(Cfg::Cfg(name, None)), - MetaItemKind::NameValue(ref lit) => match lit.node { + MetaItemKind::NameValue(ref lit) => match lit.kind { LitKind::Str(value, _) => Ok(Cfg::Cfg(name, Some(value))), _ => Err(InvalidCfgError { // FIXME: if the main #[cfg] syntax decided to support non-string literals, @@ -81,10 +81,10 @@ impl Cfg { }, MetaItemKind::List(ref items) => { let mut sub_cfgs = items.iter().map(Cfg::parse_nested); - match &*name.as_str() { - "all" => sub_cfgs.fold(Ok(Cfg::True), |x, y| Ok(x? & y?)), - "any" => sub_cfgs.fold(Ok(Cfg::False), |x, y| Ok(x? | y?)), - "not" => if sub_cfgs.len() == 1 { + match name { + sym::all => sub_cfgs.fold(Ok(Cfg::True), |x, y| Ok(x? & y?)), + sym::any => sub_cfgs.fold(Ok(Cfg::False), |x, y| Ok(x? | y?)), + sym::not => if sub_cfgs.len() == 1 { Ok(!sub_cfgs.next().unwrap()?) } else { Err(InvalidCfgError { diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index 405144b444f09..580320a735bc0 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -3,7 +3,6 @@ use super::*; use syntax_pos::DUMMY_SP; use syntax::ast::*; use syntax::attr; -use syntax::source_map::dummy_spanned; use syntax::symbol::Symbol; use syntax::with_default_globals; @@ -18,7 +17,7 @@ fn name_value_cfg(name: &str, value: &str) -> Cfg { fn dummy_meta_item_word(name: &str) -> MetaItem { MetaItem { path: Path::from_ident(Ident::from_str(name)), - node: MetaItemKind::Word, + kind: MetaItemKind::Word, span: DUMMY_SP, } } @@ -27,7 +26,7 @@ macro_rules! dummy_meta_item_list { ($name:ident, [$($list:ident),* $(,)?]) => { MetaItem { path: Path::from_ident(Ident::from_str(stringify!($name))), - node: MetaItemKind::List(vec![ + kind: MetaItemKind::List(vec![ $( NestedMetaItem::MetaItem( dummy_meta_item_word(stringify!($list)), @@ -41,7 +40,7 @@ macro_rules! dummy_meta_item_list { ($name:ident, [$($list:expr),* $(,)?]) => { MetaItem { path: Path::from_ident(Ident::from_str(stringify!($name))), - node: MetaItemKind::List(vec![ + kind: MetaItemKind::List(vec![ $( NestedMetaItem::MetaItem($list), )* @@ -181,7 +180,8 @@ fn test_parse_ok() { let mi = attr::mk_name_value_item_str( Ident::from_str("all"), - dummy_spanned(Symbol::intern("done")) + Symbol::intern("done"), + DUMMY_SP, ); assert_eq!(Cfg::parse(&mi), Ok(name_value_cfg("all", "done"))); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 8463fbfbd200b..532c5f67bf3ba 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -14,12 +14,13 @@ use rustc_metadata::cstore::LoadedMacro; use rustc::ty; use rustc::util::nodemap::FxHashSet; -use crate::core::{DocContext, DocAccessLevels}; +use crate::core::DocContext; use crate::doctree; use crate::clean::{ self, GetDefId, ToSource, + TypeKind }; use super::Clean; @@ -107,15 +108,16 @@ pub fn try_inline( record_extern_fqn(cx, did, clean::TypeKind::Const); clean::ConstantItem(build_const(cx, did)) } - // FIXME: proc-macros don't propagate attributes or spans across crates, so they look empty - Res::Def(DefKind::Macro(MacroKind::Bang), did) => { + Res::Def(DefKind::Macro(kind), did) => { let mac = build_macro(cx, did, name); - if let clean::MacroItem(..) = mac { - record_extern_fqn(cx, did, clean::TypeKind::Macro); - mac - } else { - return None; - } + + let type_kind = match kind { + MacroKind::Bang => TypeKind::Macro, + MacroKind::Attr => TypeKind::Attr, + MacroKind::Derive => TypeKind::Derive + }; + record_extern_fqn(cx, did, type_kind); + mac } _ => return None, }; @@ -129,7 +131,7 @@ pub fn try_inline( name: Some(name.clean(cx)), attrs, inner, - visibility: Some(clean::Public), + visibility: clean::Public, stability: cx.tcx.lookup_stability(did).clean(cx), deprecation: cx.tcx.lookup_deprecation(did).clean(cx), def_id: did, @@ -163,10 +165,7 @@ pub fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> Attrs<'hir> { /// These names are used later on by HTML rendering to generate things like /// source links back to the original item. pub fn record_extern_fqn(cx: &DocContext<'_>, did: DefId, kind: clean::TypeKind) { - let mut crate_name = cx.tcx.crate_name(did.krate).to_string(); - if did.is_local() { - crate_name = cx.crate_name.clone().unwrap_or(crate_name); - } + let crate_name = cx.tcx.crate_name(did.krate).to_string(); let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| { // extern blocks have an empty name @@ -218,10 +217,11 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function { } else { hir::Constness::NotConst }; - + let asyncness = cx.tcx.asyncness(did); let predicates = cx.tcx.predicates_of(did); - let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); - let decl = (did, sig).clean(cx); + let (generics, decl) = clean::enter_impl_trait(cx, || { + ((cx.tcx.generics_of(did), &predicates).clean(cx), (did, sig).clean(cx)) + }); let (all_types, ret_types) = clean::get_all_types(&generics, &decl, cx); clean::Function { decl, @@ -230,7 +230,7 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function { unsafety: sig.unsafety(), abi: sig.abi(), constness, - asyncness: hir::IsAsync::NotAsync, + asyncness, }, all_types, ret_types, @@ -326,14 +326,14 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, attrs: Option>, // reachable in rustdoc generated documentation if !did.is_local() { if let Some(traitref) = associated_trait { - if !cx.renderinfo.borrow().access_levels.is_doc_reachable(traitref.def_id) { + if !cx.renderinfo.borrow().access_levels.is_public(traitref.def_id) { return } } } let for_ = if let Some(hir_id) = tcx.hir().as_local_hir_id(did) { - match tcx.hir().expect_item(hir_id).node { + match tcx.hir().expect_item(hir_id).kind { hir::ItemKind::Impl(.., ref t, _) => { t.clean(cx) } @@ -347,7 +347,7 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, attrs: Option>, // reachable in rustdoc generated documentation if !did.is_local() { if let Some(did) = for_.def_id() { - if !cx.renderinfo.borrow().access_levels.is_doc_reachable(did) { + if !cx.renderinfo.borrow().access_levels.is_public(did) { return } } @@ -355,7 +355,7 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, attrs: Option>, let predicates = tcx.explicit_predicates_of(did); let (trait_items, generics) = if let Some(hir_id) = tcx.hir().as_local_hir_id(did) { - match tcx.hir().expect_item(hir_id).node { + match tcx.hir().expect_item(hir_id).kind { hir::ItemKind::Impl(.., ref gen, _, _, ref item_ids) => { ( item_ids.iter() @@ -375,7 +375,9 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, attrs: Option>, None } }).collect::>(), - (tcx.generics_of(did), &predicates).clean(cx), + clean::enter_impl_trait(cx, || { + (tcx.generics_of(did), &predicates).clean(cx) + }), ) }; let polarity = tcx.impl_polarity(did); @@ -416,7 +418,7 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, attrs: Option>, source: tcx.def_span(did).clean(cx), name: None, attrs, - visibility: Some(clean::Inherited), + visibility: clean::Inherited, stability: tcx.lookup_stability(did).clean(cx), deprecation: tcx.lookup_deprecation(did).clean(cx), def_id: did, @@ -479,7 +481,7 @@ fn build_macro(cx: &DocContext<'_>, did: DefId, name: ast::Name) -> clean::ItemE let imported_from = cx.tcx.original_crate_name(did.krate); match cx.cstore.load_macro_untracked(did, cx.sess()) { LoadedMacro::MacroDef(def) => { - let matchers: hir::HirVec = if let ast::ItemKind::MacroDef(ref def) = def.node { + let matchers: hir::HirVec = if let ast::ItemKind::MacroDef(ref def) = def.kind { let tts: Vec<_> = def.stream().into_trees().collect(); tts.chunks(4).map(|arm| arm[0].span()).collect() } else { @@ -577,22 +579,18 @@ pub fn record_extern_trait(cx: &DocContext<'_>, did: DefId) { } { - let external_traits = cx.external_traits.lock(); - if external_traits.borrow().contains_key(&did) || + if cx.external_traits.borrow().contains_key(&did) || cx.active_extern_traits.borrow().contains(&did) { return; } } - cx.active_extern_traits.borrow_mut().push(did); + cx.active_extern_traits.borrow_mut().insert(did); debug!("record_extern_trait: {:?}", did); let trait_ = build_external_trait(cx, did); - { - let external_traits = cx.external_traits.lock(); - external_traits.borrow_mut().insert(did, trait_); - } - cx.active_extern_traits.borrow_mut().remove_item(&did); + cx.external_traits.borrow_mut().insert(did, trait_); + cx.active_extern_traits.borrow_mut().remove(&did); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d3accff5c2ce8..212a09ee6e634 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -9,7 +9,7 @@ mod simplify; mod auto_trait; mod blanket_impl; -use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use rustc_index::vec::{IndexVec, Idx}; use rustc_target::spec::abi::Abi; use rustc_typeck::hir_ty_to_ty; use rustc::infer::region_constraints::{RegionConstraintData, Constraint}; @@ -21,7 +21,7 @@ use rustc::hir; use rustc::hir::def::{CtorKind, DefKind, Res}; use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::hir::ptr::P; -use rustc::ty::subst::{InternalSubsts, SubstsRef, UnpackedKind}; +use rustc::ty::subst::{InternalSubsts, SubstsRef, GenericArgKind}; use rustc::ty::{self, DefIdTree, TyCtxt, Region, RegionVid, Ty, AdtKind}; use rustc::ty::fold::TypeFolder; use rustc::ty::layout::VariantIdx; @@ -29,7 +29,7 @@ use rustc::util::nodemap::{FxHashMap, FxHashSet}; use syntax::ast::{self, AttrStyle, Ident}; use syntax::attr; use syntax::ext::base::MacroKind; -use syntax::source_map::{dummy_spanned, Spanned}; +use syntax::source_map::DUMMY_SP; use syntax::symbol::{Symbol, kw, sym}; use syntax::symbol::InternedString; use syntax_pos::{self, Pos, FileName}; @@ -39,17 +39,14 @@ use std::fmt; use std::hash::{Hash, Hasher}; use std::default::Default; use std::{mem, slice, vec}; -use std::iter::{FromIterator, once}; +use std::iter::FromIterator; use std::rc::Rc; use std::cell::RefCell; use std::sync::Arc; use std::u32; -use parking_lot::ReentrantMutex; - -use crate::core::{self, DocContext}; +use crate::core::{self, DocContext, ImplTraitParam}; use crate::doctree; -use crate::visit_ast; use crate::html::render::{cache, ExternalLocation}; use crate::html::item_type::ItemType; @@ -134,92 +131,93 @@ pub struct Crate { pub primitives: Vec<(DefId, PrimitiveType, Attributes)>, // These are later on moved into `CACHEKEY`, leaving the map empty. // Only here so that they can be filtered through the rustdoc passes. - pub external_traits: Arc>>>, + pub external_traits: Rc>>, pub masked_crates: FxHashSet, -} - -impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { - fn clean(&self, cx: &DocContext<'_>) -> Crate { - use crate::visit_lib::LibEmbargoVisitor; - - { - let mut r = cx.renderinfo.borrow_mut(); - r.deref_trait_did = cx.tcx.lang_items().deref_trait(); - r.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait(); - r.owned_box_did = cx.tcx.lang_items().owned_box(); - } - - let mut externs = Vec::new(); - for &cnum in cx.tcx.crates().iter() { - externs.push((cnum, cnum.clean(cx))); - // Analyze doc-reachability for extern items - LibEmbargoVisitor::new(cx).visit_lib(cnum); - } - externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); - - // Clean the crate, translating the entire libsyntax AST to one that is - // understood by rustdoc. - let mut module = self.module.as_ref().unwrap().clean(cx); - let mut masked_crates = FxHashSet::default(); - - match module.inner { - ModuleItem(ref module) => { - for it in &module.items { - // `compiler_builtins` should be masked too, but we can't apply - // `#[doc(masked)]` to the injected `extern crate` because it's unstable. - if it.is_extern_crate() - && (it.attrs.has_doc_flag(sym::masked) - || self.cx.tcx.is_compiler_builtins(it.def_id.krate)) - { - masked_crates.insert(it.def_id.krate); - } + pub collapsed: bool, +} + +pub fn krate(mut cx: &mut DocContext<'_>) -> Crate { + use crate::visit_lib::LibEmbargoVisitor; + + let krate = cx.tcx.hir().krate(); + let module = crate::visit_ast::RustdocVisitor::new(&mut cx).visit(krate); + + let mut r = cx.renderinfo.get_mut(); + r.deref_trait_did = cx.tcx.lang_items().deref_trait(); + r.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait(); + r.owned_box_did = cx.tcx.lang_items().owned_box(); + + let mut externs = Vec::new(); + for &cnum in cx.tcx.crates().iter() { + externs.push((cnum, cnum.clean(cx))); + // Analyze doc-reachability for extern items + LibEmbargoVisitor::new(&mut cx).visit_lib(cnum); + } + externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); + + // Clean the crate, translating the entire libsyntax AST to one that is + // understood by rustdoc. + let mut module = module.clean(cx); + let mut masked_crates = FxHashSet::default(); + + match module.inner { + ModuleItem(ref module) => { + for it in &module.items { + // `compiler_builtins` should be masked too, but we can't apply + // `#[doc(masked)]` to the injected `extern crate` because it's unstable. + if it.is_extern_crate() + && (it.attrs.has_doc_flag(sym::masked) + || cx.tcx.is_compiler_builtins(it.def_id.krate)) + { + masked_crates.insert(it.def_id.krate); } } - _ => unreachable!(), } + _ => unreachable!(), + } - let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx); - { - let m = match module.inner { - ModuleItem(ref mut m) => m, - _ => unreachable!(), - }; - m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| { - Item { - source: Span::empty(), - name: Some(prim.to_url_str().to_string()), - attrs: attrs.clone(), - visibility: Some(Public), - stability: get_stability(cx, def_id), - deprecation: get_deprecation(cx, def_id), - def_id, - inner: PrimitiveItem(prim), - } - })); - m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| { - Item { - source: Span::empty(), - name: Some(kw.clone()), - attrs: attrs, - visibility: Some(Public), - stability: get_stability(cx, def_id), - deprecation: get_deprecation(cx, def_id), - def_id, - inner: KeywordItem(kw), - } - })); - } + let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx); + { + let m = match module.inner { + ModuleItem(ref mut m) => m, + _ => unreachable!(), + }; + m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| { + Item { + source: Span::empty(), + name: Some(prim.to_url_str().to_string()), + attrs: attrs.clone(), + visibility: Public, + stability: get_stability(cx, def_id), + deprecation: get_deprecation(cx, def_id), + def_id, + inner: PrimitiveItem(prim), + } + })); + m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| { + Item { + source: Span::empty(), + name: Some(kw.clone()), + attrs, + visibility: Public, + stability: get_stability(cx, def_id), + deprecation: get_deprecation(cx, def_id), + def_id, + inner: KeywordItem(kw), + } + })); + } - Crate { - name, - version: None, - src, - module: Some(module), - externs, - primitives, - external_traits: cx.external_traits.clone(), - masked_crates, - } + Crate { + name, + version: None, + src, + module: Some(module), + externs, + primitives, + external_traits: cx.external_traits.clone(), + masked_crates, + collapsed: false, } } @@ -277,7 +275,7 @@ impl Clean for CrateNum { let primitives = if root.is_local() { cx.tcx.hir().krate().module.item_ids.iter().filter_map(|&id| { let item = cx.tcx.hir().expect_item(id.id); - match item.node { + match item.kind { hir::ItemKind::Mod(_) => { as_primitive(Res::Def( DefKind::Mod, @@ -321,7 +319,7 @@ impl Clean for CrateNum { let keywords = if root.is_local() { cx.tcx.hir().krate().module.item_ids.iter().filter_map(|&id| { let item = cx.tcx.hir().expect_item(id.id); - match item.node { + match item.kind { hir::ItemKind::Mod(_) => { as_keyword(Res::Def( DefKind::Mod, @@ -363,7 +361,7 @@ pub struct Item { pub name: Option, pub attrs: Attributes, pub inner: ItemEnum, - pub visibility: Option, + pub visibility: Visibility, pub def_id: DefId, pub stability: Option, pub deprecation: Option, @@ -568,23 +566,6 @@ pub enum ItemEnum { } impl ItemEnum { - pub fn generics(&self) -> Option<&Generics> { - Some(match *self { - ItemEnum::StructItem(ref s) => &s.generics, - ItemEnum::EnumItem(ref e) => &e.generics, - ItemEnum::FunctionItem(ref f) => &f.generics, - ItemEnum::TypedefItem(ref t, _) => &t.generics, - ItemEnum::OpaqueTyItem(ref t, _) => &t.generics, - ItemEnum::TraitItem(ref t) => &t.generics, - ItemEnum::ImplItem(ref i) => &i.generics, - ItemEnum::TyMethodItem(ref i) => &i.generics, - ItemEnum::MethodItem(ref i) => &i.generics, - ItemEnum::ForeignFunctionItem(ref f) => &f.generics, - ItemEnum::TraitAliasItem(ref ta) => &ta.generics, - _ => return None, - }) - } - pub fn is_associated(&self) -> bool { match *self { ItemEnum::TypedefItem(_, _) | @@ -652,9 +633,9 @@ impl Clean for doctree::Module<'_> { attrs, source: whence.clean(cx), visibility: self.vis.clean(cx), - stability: self.stab.clean(cx), - deprecation: self.depr.clean(cx), - def_id: cx.tcx.hir().local_def_id_from_node_id(self.id), + stability: cx.stability(self.id).clean(cx), + deprecation: cx.deprecation(self.id).clean(cx), + def_id: cx.tcx.hir().local_def_id(self.id), inner: ModuleItem(Module { is_crate: self.is_crate, items, @@ -797,11 +778,11 @@ impl Attributes { fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> { use syntax::ast::NestedMetaItem::MetaItem; - if let ast::MetaItemKind::List(ref nmis) = mi.node { + if let ast::MetaItemKind::List(ref nmis) = mi.kind { if nmis.len() == 1 { if let MetaItem(ref cfg_mi) = nmis[0] { if cfg_mi.check_name(sym::cfg) { - if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.node { + if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind { if cfg_nmis.len() == 1 { if let MetaItem(ref content_mi) = cfg_nmis[0] { return Some(content_mi); @@ -926,8 +907,8 @@ impl Attributes { if attr.check_name(sym::enable) { if let Some(feat) = attr.value_str() { let meta = attr::mk_name_value_item_str( - Ident::with_empty_ctxt(sym::target_feature), - dummy_spanned(feat)); + Ident::with_dummy_span(sym::target_feature), feat, DUMMY_SP + ); if let Ok(feat_cfg) = Cfg::parse(&meta) { cfg &= feat_cfg; } @@ -1056,9 +1037,9 @@ pub enum GenericBound { impl GenericBound { fn maybe_sized(cx: &DocContext<'_>) -> GenericBound { - let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem); + let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None); let empty = cx.tcx.intern_substs(&[]); - let path = external_path(cx, &cx.tcx.item_name(did).as_str(), + let path = external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty); inline::record_extern_fqn(cx, did, TypeKind::Trait); GenericBound::TraitBound(PolyTrait { @@ -1117,33 +1098,33 @@ fn external_generic_args( substs: SubstsRef<'_>, ) -> GenericArgs { let mut skip_self = has_self; - let mut ty_sty = None; + let mut ty_kind = None; let args: Vec<_> = substs.iter().filter_map(|kind| match kind.unpack() { - UnpackedKind::Lifetime(lt) => { + GenericArgKind::Lifetime(lt) => { lt.clean(cx).and_then(|lt| Some(GenericArg::Lifetime(lt))) } - UnpackedKind::Type(_) if skip_self => { + GenericArgKind::Type(_) if skip_self => { skip_self = false; None } - UnpackedKind::Type(ty) => { - ty_sty = Some(&ty.sty); + GenericArgKind::Type(ty) => { + ty_kind = Some(&ty.kind); Some(GenericArg::Type(ty.clean(cx))) } - UnpackedKind::Const(ct) => Some(GenericArg::Const(ct.clean(cx))), + GenericArgKind::Const(ct) => Some(GenericArg::Const(ct.clean(cx))), }).collect(); match trait_did { // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C Some(did) if cx.tcx.lang_items().fn_trait_kind(did).is_some() => { - assert!(ty_sty.is_some()); - let inputs = match ty_sty { + assert!(ty_kind.is_some()); + let inputs = match ty_kind { Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(), _ => return GenericArgs::AngleBracketed { args, bindings }, }; let output = None; // FIXME(#20299) return type comes from a projection now - // match types[1].sty { + // match types[1].kind { // ty::Tuple(ref v) if v.is_empty() => None, // -> () // _ => Some(types[1].clean(cx)) // }; @@ -1157,13 +1138,13 @@ fn external_generic_args( // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar // from Fn<(A, B,), C> to Fn(A, B) -> C -fn external_path(cx: &DocContext<'_>, name: &str, trait_did: Option, has_self: bool, +fn external_path(cx: &DocContext<'_>, name: Symbol, trait_did: Option, has_self: bool, bindings: Vec, substs: SubstsRef<'_>) -> Path { Path { global: false, res: Res::Err, segments: vec![PathSegment { - name: name.to_string(), + name: name.as_str().to_string(), args: external_generic_args(cx, trait_did, has_self, bindings, substs) }], } @@ -1173,7 +1154,7 @@ impl<'a, 'tcx> Clean for (&'a ty::TraitRef<'tcx>, Vec fn clean(&self, cx: &DocContext<'_>) -> GenericBound { let (trait_ref, ref bounds) = *self; inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait); - let path = external_path(cx, &cx.tcx.item_name(trait_ref.def_id).as_str(), + let path = external_path(cx, cx.tcx.item_name(trait_ref.def_id), Some(trait_ref.def_id), true, bounds.clone(), trait_ref.substs); debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs); @@ -1181,9 +1162,9 @@ impl<'a, 'tcx> Clean for (&'a ty::TraitRef<'tcx>, Vec // collect any late bound regions let mut late_bounds = vec![]; for ty_s in trait_ref.input_types().skip(1) { - if let ty::Tuple(ts) = ty_s.sty { + if let ty::Tuple(ts) = ty_s.kind { for &ty_s in ts { - if let ty::Ref(ref reg, _, _) = ty_s.expect_ty().sty { + if let ty::Ref(ref reg, _, _) = ty_s.expect_ty().kind { if let &ty::RegionKind::ReLateBound(..) = *reg { debug!(" hit an ReLateBound {:?}", reg); if let Some(Lifetime(name)) = reg.clean(cx) { @@ -1536,9 +1517,7 @@ impl Clean for ty::GenericParamDef { ty::GenericParamDefKind::Lifetime => { (self.name.to_string(), GenericParamDefKind::Lifetime) } - ty::GenericParamDefKind::Type { has_default, .. } => { - cx.renderinfo.borrow_mut().external_param_names - .insert(self.def_id, self.name.clean(cx)); + ty::GenericParamDefKind::Type { has_default, synthetic, .. } => { let default = if has_default { Some(cx.tcx.type_of(self.def_id).clean(cx)) } else { @@ -1548,7 +1527,7 @@ impl Clean for ty::GenericParamDef { did: self.def_id, bounds: vec![], // These are filled in from the where-clauses. default, - synthetic: None, + synthetic, }) } ty::GenericParamDefKind::Const { .. } => { @@ -1591,7 +1570,7 @@ impl Clean for hir::GenericParam { did: cx.tcx.hir().local_def_id(self.hir_id), bounds: self.bounds.clean(cx), default: default.clean(cx), - synthetic: synthetic, + synthetic, }) } hir::GenericParamKind::Const { ref ty } => { @@ -1637,7 +1616,7 @@ impl Clean for hir::Generics { match param.kind { GenericParamDefKind::Lifetime => unreachable!(), GenericParamDefKind::Type { did, ref bounds, .. } => { - cx.impl_trait_bounds.borrow_mut().insert(did, bounds.clone()); + cx.impl_trait_bounds.borrow_mut().insert(did.into(), bounds.clone()); } GenericParamDefKind::Const { .. } => unreachable!(), } @@ -1689,26 +1668,123 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, &'a &'tcx ty::GenericPredicates<'tcx>) { fn clean(&self, cx: &DocContext<'_>) -> Generics { use self::WherePredicate as WP; + use std::collections::BTreeMap; let (gens, preds) = *self; + // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses, + // since `Clean for ty::Predicate` would consume them. + let mut impl_trait = BTreeMap::>::default(); + // 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.params.iter().filter_map(|param| match param.kind { - ty::GenericParamDefKind::Lifetime => None, - ty::GenericParamDefKind::Type { .. } => { - if param.name.as_symbol() == kw::SelfUpper { - assert_eq!(param.index, 0); - return None; + let stripped_typarams = gens.params.iter() + .filter_map(|param| match param.kind { + ty::GenericParamDefKind::Lifetime => None, + ty::GenericParamDefKind::Type { synthetic, .. } => { + if param.name.as_symbol() == kw::SelfUpper { + assert_eq!(param.index, 0); + return None; + } + if synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) { + impl_trait.insert(param.index.into(), vec![]); + return None; + } + Some(param.clean(cx)) + } + ty::GenericParamDefKind::Const { .. } => None, + }).collect::>(); + + // param index -> [(DefId of trait, associated type name, type)] + let mut impl_trait_proj = + FxHashMap::)>>::default(); + + let where_predicates = preds.predicates.iter() + .flat_map(|(p, _)| { + let mut projection = None; + let param_idx = (|| { + if let Some(trait_ref) = p.to_opt_poly_trait_ref() { + if let ty::Param(param) = trait_ref.self_ty().kind { + return Some(param.index); + } + } else if let Some(outlives) = p.to_opt_type_outlives() { + if let ty::Param(param) = outlives.skip_binder().0.kind { + return Some(param.index); + } + } else if let ty::Predicate::Projection(p) = p { + if let ty::Param(param) = p.skip_binder().projection_ty.self_ty().kind { + projection = Some(p); + return Some(param.index); + } + } + + None + })(); + + if let Some(param_idx) = param_idx { + if let Some(b) = impl_trait.get_mut(¶m_idx.into()) { + let p = p.clean(cx)?; + + b.extend( + p.get_bounds() + .into_iter() + .flatten() + .cloned() + .filter(|b| !b.is_sized_bound(cx)) + ); + + let proj = projection + .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty)); + if let Some(((_, trait_did, name), rhs)) = + proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs))) + { + impl_trait_proj + .entry(param_idx) + .or_default() + .push((trait_did, name.to_string(), rhs)); + } + + return None; + } } - Some(param.clean(cx)) + + Some(p) + }) + .collect::>(); + + for (param, mut bounds) in impl_trait { + // Move trait bounds to the front. + bounds.sort_by_key(|b| if let GenericBound::TraitBound(..) = b { + false + } else { + true + }); + + if let crate::core::ImplTraitParam::ParamIndex(idx) = param { + if let Some(proj) = impl_trait_proj.remove(&idx) { + for (trait_did, name, rhs) in proj { + simplify::merge_bounds( + cx, + &mut bounds, + trait_did, + &name, + &rhs.clean(cx), + ); + } + } + } else { + unreachable!(); } - ty::GenericParamDefKind::Const { .. } => None, - }).collect::>(); - let mut where_predicates = preds.predicates.iter() - .flat_map(|(p, _)| p.clean(cx)) + cx.impl_trait_bounds.borrow_mut().insert(param, bounds); + } + + // Now that `cx.impl_trait_bounds` is populated, we can process + // remaining predicates which could contain `impl Trait`. + let mut where_predicates = where_predicates + .into_iter() + .flat_map(|p| p.clean(cx)) .collect::>(); // Type parameters and have a Sized bound by default unless removed with @@ -1773,7 +1849,7 @@ fn get_real_types( cx: &DocContext<'_>, recurse: i32, ) -> FxHashSet { - let arg_s = arg.to_string(); + let arg_s = arg.print().to_string(); let mut res = FxHashSet::default(); if recurse >= 10 { // FIXME: remove this whole recurse thing when the recursion bug is fixed return res; @@ -1938,8 +2014,8 @@ impl Clean for doctree::Function<'_> { attrs: self.attrs.clean(cx), source: self.whence.clean(cx), visibility: self.vis.clean(cx), - stability: self.stab.clean(cx), - deprecation: self.depr.clean(cx), + stability: cx.stability(self.id).clean(cx), + deprecation: cx.deprecation(self.id).clean(cx), def_id: did, inner: FunctionItem(Function { decl, @@ -1956,6 +2032,7 @@ impl Clean for doctree::Function<'_> { pub struct FnDecl { pub inputs: Arguments, pub output: FunctionRetTy, + pub c_variadic: bool, pub attrs: Attributes, } @@ -2019,7 +2096,7 @@ impl<'a> Clean for (&'a [hir::Ty], hir::BodyId) { Arguments { values: self.0.iter().enumerate().map(|(i, ty)| { Argument { - name: name_from_pat(&body.arguments[i].pat), + name: name_from_pat(&body.params[i].pat), type_: ty.clean(cx), } }).collect() @@ -2034,6 +2111,7 @@ impl<'a, A: Copy> Clean for (&'a hir::FnDecl, A) FnDecl { inputs: (&self.0.inputs[..], self.1).clean(cx), output: self.0.output.clean(cx), + c_variadic: self.0.c_variadic, attrs: Attributes::default(), } } @@ -2051,6 +2129,7 @@ impl<'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { FnDecl { output: Return(sig.skip_binder().output().clean(cx)), attrs: Attributes::default(), + c_variadic: sig.skip_binder().c_variadic, inputs: Arguments { values: sig.skip_binder().inputs().iter().map(|t| { Argument { @@ -2134,12 +2213,12 @@ impl Clean for doctree::Trait<'_> { let is_spotlight = attrs.has_doc_flag(sym::spotlight); Item { name: Some(self.name.clean(cx)), - attrs: attrs, + attrs, source: self.whence.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id), visibility: self.vis.clean(cx), - stability: self.stab.clean(cx), - deprecation: self.depr.clean(cx), + stability: cx.stability(self.id).clean(cx), + deprecation: cx.deprecation(self.id).clean(cx), inner: TraitItem(Trait { auto: self.is_auto.clean(cx), unsafety: self.unsafety, @@ -2168,8 +2247,8 @@ impl Clean for doctree::TraitAlias<'_> { source: self.whence.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id), visibility: self.vis.clean(cx), - stability: self.stab.clean(cx), - deprecation: self.depr.clean(cx), + stability: cx.stability(self.id).clean(cx), + deprecation: cx.deprecation(self.id).clean(cx), inner: TraitAliasItem(TraitAlias { generics: self.generics.clean(cx), bounds: self.bounds.clean(cx), @@ -2204,7 +2283,7 @@ impl Clean for hir::PolyTraitRef { impl Clean for hir::TraitItem { fn clean(&self, cx: &DocContext<'_>) -> Item { - let inner = match self.node { + let inner = match self.kind { hir::TraitItemKind::Const(ref ty, default) => { AssocConstItem(ty.clean(cx), default.map(|e| print_const_expr(cx, e))) @@ -2235,7 +2314,7 @@ impl Clean for hir::TraitItem { attrs: self.attrs.clean(cx), source: self.span.clean(cx), def_id: local_did, - visibility: None, + visibility: Visibility::Inherited, stability: get_stability(cx, local_did), deprecation: get_deprecation(cx, local_did), inner, @@ -2245,7 +2324,7 @@ impl Clean for hir::TraitItem { impl Clean for hir::ImplItem { fn clean(&self, cx: &DocContext<'_>) -> Item { - let inner = match self.node { + let inner = match self.kind { hir::ImplItemKind::Const(ref ty, expr) => { AssocConstItem(ty.clean(cx), Some(print_const_expr(cx, expr))) @@ -2299,12 +2378,12 @@ impl Clean for ty::AssocItem { ty::ImplContainer(def_id) => { cx.tcx.type_of(def_id) } - ty::TraitContainer(_) => cx.tcx.mk_self_type() + ty::TraitContainer(_) => cx.tcx.types.self_param, }; let self_arg_ty = *sig.input(0).skip_binder(); if self_arg_ty == self_ty { decl.inputs.values[0].type_ = Generic(String::from("Self")); - } else if let ty::Ref(_, ty, _) = self_arg_ty.sty { + } else if let ty::Ref(_, ty, _) = self_arg_ty.kind { if ty == self_ty { match decl.inputs.values[0].type_ { BorrowedRef{ref mut type_, ..} => { @@ -2327,6 +2406,7 @@ impl Clean for ty::AssocItem { } else { hir::Constness::NotConst }; + let asyncness = cx.tcx.asyncness(self.def_id); let defaultness = match self.container { ty::ImplContainer(_) => Some(self.defaultness), ty::TraitContainer(_) => None, @@ -2338,7 +2418,7 @@ impl Clean for ty::AssocItem { unsafety: sig.unsafety(), abi: sig.abi(), constness, - asyncness: hir::IsAsync::NotAsync, + asyncness, }, defaultness, all_types, @@ -2420,7 +2500,7 @@ impl Clean for ty::AssocItem { let visibility = match self.container { ty::ImplContainer(_) => self.vis.clean(cx), - ty::TraitContainer(_) => None, + ty::TraitContainer(_) => Inherited, }; Item { @@ -2468,7 +2548,6 @@ pub enum Type { Slice(Box), Array(Box, String), Never, - CVarArgs, RawPointer(Mutability, Box), BorrowedRef { lifetime: Option, @@ -2506,7 +2585,6 @@ pub enum PrimitiveType { Reference, Fn, Never, - CVarArgs, } #[derive(Clone, Copy, Debug)] @@ -2609,6 +2687,21 @@ impl Type { _ => false, } } + + pub fn projection(&self) -> Option<(&Type, DefId, &str)> { + let (self_, trait_, name) = match self { + QPath { ref self_type, ref trait_, ref name } => { + (self_type, trait_, name) + } + _ => return None, + }; + let trait_did = match **trait_ { + ResolvedPath { did, .. } => did, + _ => return None, + }; + Some((&self_, trait_did, name)) + } + } impl GetDefId for Type { @@ -2695,7 +2788,6 @@ impl PrimitiveType { Reference => "reference", Fn => "fn", Never => "never", - CVarArgs => "...", } } @@ -2743,7 +2835,7 @@ impl Clean for hir::Ty { fn clean(&self, cx: &DocContext<'_>) -> Type { use rustc::hir::*; - match self.node { + match self.kind { TyKind::Never => Never, TyKind::Ptr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)), TyKind::Rptr(ref l, ref m) => { @@ -2752,7 +2844,7 @@ impl Clean for hir::Ty { } else { Some(l.clean(cx)) }; - BorrowedRef {lifetime: lifetime, mutability: m.mutbl.clean(cx), + BorrowedRef {lifetime, mutability: m.mutbl.clean(cx), type_: box m.ty.clean(cx)} } TyKind::Slice(ref ty) => Slice(box ty.clean(cx)), @@ -2776,7 +2868,7 @@ impl Clean for hir::Ty { TyKind::Tup(ref tys) => Tuple(tys.clean(cx)), TyKind::Def(item_id, _) => { let item = cx.tcx.hir().expect_item(item_id.id); - if let hir::ItemKind::OpaqueTy(ref ty) = item.node { + if let hir::ItemKind::OpaqueTy(ref ty) = item.kind { ImplTrait(ty.bounds.clean(cx)) } else { unreachable!() @@ -2787,7 +2879,7 @@ impl Clean for hir::Ty { if let Some(new_ty) = cx.ty_substs.borrow().get(&did).cloned() { return new_ty; } - if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did) { + if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did.into()) { return ImplTrait(bounds); } } @@ -2797,7 +2889,7 @@ impl Clean for hir::Ty { // Substitute private type aliases if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) { if !cx.renderinfo.borrow().access_levels.is_exported(def_id) { - alias = Some(&cx.tcx.hir().expect_item(hir_id).node); + alias = Some(&cx.tcx.hir().expect_item(hir_id).kind); } } }; @@ -2908,7 +3000,7 @@ impl Clean for hir::Ty { TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => { let mut res = Res::Err; let ty = hir_ty_to_ty(cx.tcx, self); - if let ty::Projection(proj) = ty.sty { + if let ty::Projection(proj) = ty.kind { res = Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id); } let trait_path = hir::Path { @@ -2939,8 +3031,7 @@ impl Clean for hir::Ty { } TyKind::BareFn(ref barefn) => BareFunction(box barefn.clean(cx)), TyKind::Infer | TyKind::Err => Infer, - TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.node), - TyKind::CVarArgs(_) => CVarArgs, + TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.kind), } } } @@ -2948,7 +3039,7 @@ impl Clean for hir::Ty { impl<'tcx> Clean for Ty<'tcx> { fn clean(&self, cx: &DocContext<'_>) -> Type { debug!("cleaning type: {:?}", self); - match self.sty { + match self.kind { ty::Never => Never, ty::Bool => Primitive(PrimitiveType::Bool), ty::Char => Primitive(PrimitiveType::Char), @@ -2998,8 +3089,7 @@ impl<'tcx> Clean for Ty<'tcx> { AdtKind::Enum => TypeKind::Enum, }; inline::record_extern_fqn(cx, did, kind); - let path = external_path(cx, &cx.tcx.item_name(did).as_str(), - None, false, vec![], substs); + let path = external_path(cx, cx.tcx.item_name(did), None, false, vec![], substs); ResolvedPath { path, param_names: None, @@ -3009,12 +3099,12 @@ impl<'tcx> Clean for Ty<'tcx> { } ty::Foreign(did) => { inline::record_extern_fqn(cx, did, TypeKind::Foreign); - let path = external_path(cx, &cx.tcx.item_name(did).as_str(), + let path = external_path(cx, cx.tcx.item_name(did), None, false, vec![], InternalSubsts::empty()); ResolvedPath { - path: path, + path, param_names: None, - did: did, + did, is_generic: false, } } @@ -3038,7 +3128,7 @@ impl<'tcx> Clean for Ty<'tcx> { reg.clean(cx).map(|b| param_names.push(GenericBound::Outlives(b))); for did in dids { let empty = cx.tcx.intern_substs(&[]); - let path = external_path(cx, &cx.tcx.item_name(did).as_str(), + let path = external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty); inline::record_extern_fqn(cx, did, TypeKind::Trait); let bound = GenericBound::TraitBound(PolyTrait { @@ -3063,7 +3153,7 @@ impl<'tcx> Clean for Ty<'tcx> { }); } - let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did), + let path = external_path(cx, cx.tcx.item_name(did), Some(did), false, bindings, substs); ResolvedPath { path, @@ -3078,7 +3168,13 @@ impl<'tcx> Clean for Ty<'tcx> { ty::Projection(ref data) => data.clean(cx), - ty::Param(ref p) => Generic(p.name.to_string()), + ty::Param(ref p) => { + if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&p.index.into()) { + ImplTrait(bounds) + } else { + Generic(p.name.to_string()) + } + } ty::Opaque(def_id, substs) => { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, @@ -3197,9 +3293,9 @@ pub enum Visibility { Restricted(DefId, Path), } -impl Clean> for hir::Visibility { - fn clean(&self, cx: &DocContext<'_>) -> Option { - Some(match self.node { +impl Clean for hir::Visibility { + fn clean(&self, cx: &DocContext<'_>) -> Visibility { + match self.node { hir::VisibilityKind::Public => Visibility::Public, hir::VisibilityKind::Inherited => Visibility::Inherited, hir::VisibilityKind::Crate(_) => Visibility::Crate, @@ -3208,13 +3304,13 @@ impl Clean> for hir::Visibility { let did = register_res(cx, path.res); Visibility::Restricted(did, path) } - }) + } } } -impl Clean> for ty::Visibility { - fn clean(&self, _: &DocContext<'_>) -> Option { - Some(if *self == ty::Visibility::Public { Public } else { Inherited }) +impl Clean for ty::Visibility { + fn clean(&self, _: &DocContext<'_>) -> Visibility { + if *self == ty::Visibility::Public { Public } else { Inherited } } } @@ -3242,8 +3338,8 @@ impl Clean for doctree::Struct<'_> { source: self.whence.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id), visibility: self.vis.clean(cx), - stability: self.stab.clean(cx), - deprecation: self.depr.clean(cx), + stability: cx.stability(self.id).clean(cx), + deprecation: cx.deprecation(self.id).clean(cx), inner: StructItem(Struct { struct_type: self.struct_type, generics: self.generics.clean(cx), @@ -3262,8 +3358,8 @@ impl Clean for doctree::Union<'_> { source: self.whence.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id), visibility: self.vis.clean(cx), - stability: self.stab.clean(cx), - deprecation: self.depr.clean(cx), + stability: cx.stability(self.id).clean(cx), + deprecation: cx.deprecation(self.id).clean(cx), inner: UnionItem(Union { struct_type: self.struct_type, generics: self.generics.clean(cx), @@ -3309,8 +3405,8 @@ impl Clean for doctree::Enum<'_> { source: self.whence.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id), visibility: self.vis.clean(cx), - stability: self.stab.clean(cx), - deprecation: self.depr.clean(cx), + stability: cx.stability(self.id).clean(cx), + deprecation: cx.deprecation(self.id).clean(cx), inner: EnumItem(Enum { variants: self.variants.iter().map(|v| v.clean(cx)).collect(), generics: self.generics.clean(cx), @@ -3331,9 +3427,9 @@ impl Clean for doctree::Variant<'_> { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - visibility: None, - stability: self.stab.clean(cx), - deprecation: self.depr.clean(cx), + visibility: Inherited, + stability: cx.stability(self.id).clean(cx), + deprecation: cx.deprecation(self.id).clean(cx), def_id: cx.tcx.hir().local_def_id(self.id), inner: VariantItem(Variant { kind: self.def.clean(cx), @@ -3374,7 +3470,7 @@ impl Clean for ty::VariantDef { name: Some(self.ident.clean(cx)), attrs: inline::load_attrs(cx, self.def_id).clean(cx), source: cx.tcx.def_span(self.def_id).clean(cx), - visibility: Some(Inherited), + visibility: Inherited, def_id: self.def_id, inner: VariantItem(Variant { kind }), stability: get_stability(cx, self.def_id), @@ -3477,16 +3573,6 @@ pub enum GenericArg { Const(Constant), } -impl fmt::Display for GenericArg { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - GenericArg::Lifetime(lt) => lt.fmt(f), - GenericArg::Type(ty) => ty.fmt(f), - GenericArg::Const(ct) => ct.fmt(f), - } - } -} - #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum GenericArgs { AngleBracketed { @@ -3637,8 +3723,8 @@ impl Clean for doctree::Typedef<'_> { source: self.whence.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id), visibility: self.vis.clean(cx), - stability: self.stab.clean(cx), - deprecation: self.depr.clean(cx), + stability: cx.stability(self.id).clean(cx), + deprecation: cx.deprecation(self.id).clean(cx), inner: TypedefItem(Typedef { type_: self.ty.clean(cx), generics: self.gen.clean(cx), @@ -3661,8 +3747,8 @@ impl Clean for doctree::OpaqueTy<'_> { source: self.whence.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id), visibility: self.vis.clean(cx), - stability: self.stab.clean(cx), - deprecation: self.depr.clean(cx), + stability: cx.stability(self.id).clean(cx), + deprecation: cx.deprecation(self.id).clean(cx), inner: OpaqueTyItem(OpaqueTy { bounds: self.opaque_ty.bounds.clean(cx), generics: self.opaque_ty.generics.clean(cx), @@ -3682,7 +3768,7 @@ pub struct BareFunctionDecl { impl Clean for hir::BareFnTy { fn clean(&self, cx: &DocContext<'_>) -> BareFunctionDecl { let (generic_params, decl) = enter_impl_trait(cx, || { - (self.generic_params.clean(cx), (&*self.decl, &self.arg_names[..]).clean(cx)) + (self.generic_params.clean(cx), (&*self.decl, &self.param_names[..]).clean(cx)) }); BareFunctionDecl { unsafety: self.unsafety, @@ -3712,8 +3798,8 @@ impl Clean for doctree::Static<'_> { source: self.whence.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id), visibility: self.vis.clean(cx), - stability: self.stab.clean(cx), - deprecation: self.depr.clean(cx), + stability: cx.stability(self.id).clean(cx), + deprecation: cx.deprecation(self.id).clean(cx), inner: StaticItem(Static { type_: self.type_.clean(cx), mutability: self.mutability.clean(cx), @@ -3737,8 +3823,8 @@ impl Clean for doctree::Constant<'_> { source: self.whence.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id), visibility: self.vis.clean(cx), - stability: self.stab.clean(cx), - deprecation: self.depr.clean(cx), + stability: cx.stability(self.id).clean(cx), + deprecation: cx.deprecation(self.id).clean(cx), inner: ConstantItem(Constant { type_: self.type_.clean(cx), expr: print_const_expr(cx, self.expr), @@ -3768,11 +3854,13 @@ pub enum ImplPolarity { Negative, } -impl Clean for hir::ImplPolarity { +impl Clean for ty::ImplPolarity { fn clean(&self, _: &DocContext<'_>) -> ImplPolarity { match self { - &hir::ImplPolarity::Positive => ImplPolarity::Positive, - &hir::ImplPolarity::Negative => ImplPolarity::Negative, + &ty::ImplPolarity::Positive | + // FIXME: do we want to do something else here? + &ty::ImplPolarity::Reservation => ImplPolarity::Positive, + &ty::ImplPolarity::Negative => ImplPolarity::Negative, } } } @@ -3804,6 +3892,7 @@ impl Clean> for doctree::Impl<'_> { let mut ret = Vec::new(); let trait_ = self.trait_.clean(cx); let items = self.items.iter().map(|ii| ii.clean(cx)).collect::>(); + let def_id = cx.tcx.hir().local_def_id(self.id); // If this impl block is an implementation of the Deref trait, then we // need to try inlining the target's inherent impl blocks as well. @@ -3822,10 +3911,10 @@ impl Clean> for doctree::Impl<'_> { name: None, attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id), + def_id, visibility: self.vis.clean(cx), - stability: self.stab.clean(cx), - deprecation: self.depr.clean(cx), + stability: cx.stability(self.id).clean(cx), + deprecation: cx.deprecation(self.id).clean(cx), inner: ImplItem(Impl { unsafety: self.unsafety, generics: self.generics.clean(cx), @@ -3833,7 +3922,7 @@ impl Clean> for doctree::Impl<'_> { trait_, for_: self.for_.clean(cx), items, - polarity: Some(self.polarity.clean(cx)), + polarity: Some(cx.tcx.impl_polarity(def_id).clean(cx)), synthetic: false, blanket_impl: None, }) @@ -3880,7 +3969,7 @@ fn build_deref_target_impls(cx: &DocContext<'_>, F32 => tcx.lang_items().f32_impl(), F64 => tcx.lang_items().f64_impl(), Char => tcx.lang_items().char_impl(), - Bool => None, + Bool => tcx.lang_items().bool_impl(), Str => tcx.lang_items().str_impl(), Slice => tcx.lang_items().slice_impl(), Array => tcx.lang_items().slice_impl(), @@ -3890,7 +3979,6 @@ fn build_deref_target_impls(cx: &DocContext<'_>, Reference => None, Fn => None, Never => None, - CVarArgs => tcx.lang_items().va_list(), }; if let Some(did) = did { if !did.is_local() { @@ -4063,8 +4151,8 @@ impl Clean for doctree::ForeignItem<'_> { source: self.whence.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id), visibility: self.vis.clean(cx), - stability: self.stab.clean(cx), - deprecation: self.depr.clean(cx), + stability: cx.stability(self.id).clean(cx), + deprecation: cx.deprecation(self.id).clean(cx), inner, } } @@ -4092,18 +4180,20 @@ fn name_from_pat(p: &hir::Pat) -> String { use rustc::hir::*; debug!("trying to get a name from pattern: {:?}", p); - match p.node { + match p.kind { PatKind::Wild => "_".to_string(), PatKind::Binding(_, _, ident, _) => ident.to_string(), PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p), PatKind::Struct(ref name, ref fields, etc) => { format!("{} {{ {}{} }}", qpath_to_string(name), - fields.iter().map(|&Spanned { node: ref fp, .. }| - format!("{}: {}", fp.ident, name_from_pat(&*fp.pat))) + fields.iter().map(|fp| format!("{}: {}", fp.ident, name_from_pat(&fp.pat))) .collect::>().join(", "), if etc { ", .." } else { "" } ) } + PatKind::Or(ref pats) => { + pats.iter().map(|p| name_from_pat(&**p)).collect::>().join(" | ") + } PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p)) .collect::>().join(", ")), PatKind::Box(ref p) => name_from_pat(&**p), @@ -4176,7 +4266,7 @@ fn resolve_type(cx: &DocContext<'_>, return Generic(kw::SelfUpper.to_string()); } Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => { - return Generic(format!("{:#}", path)); + return Generic(format!("{:#}", path.print())); } Res::SelfTy(..) | Res::Def(DefKind::TyParam, _) @@ -4184,7 +4274,7 @@ fn resolve_type(cx: &DocContext<'_>, _ => false, }; let did = register_res(&*cx, path.res); - ResolvedPath { path: path, param_names: None, did: did, is_generic: is_generic } + ResolvedPath { path, param_names: None, did, is_generic } } pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId { @@ -4245,9 +4335,9 @@ impl Clean for doctree::Macro<'_> { name: Some(name.clone()), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - visibility: Some(Public), - stability: self.stab.clean(cx), - deprecation: self.depr.clean(cx), + visibility: Public, + stability: cx.stability(self.hid).clean(cx), + deprecation: cx.deprecation(self.hid).clean(cx), def_id: self.def_id, inner: MacroItem(Macro { source: format!("macro_rules! {} {{\n{}}}", @@ -4273,9 +4363,9 @@ impl Clean for doctree::ProcMacro<'_> { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - visibility: Some(Public), - stability: self.stab.clean(cx), - deprecation: self.depr.clean(cx), + visibility: Public, + stability: cx.stability(self.id).clean(cx), + deprecation: cx.deprecation(self.id).clean(cx), def_id: cx.tcx.hir().local_def_id(self.id), inner: ProcMacroItem(ProcMacro { kind: self.kind, @@ -4394,24 +4484,6 @@ impl Clean for hir::TypeBindingKind { } } -pub fn def_id_to_path( - cx: &DocContext<'_>, - did: DefId, - name: Option -) -> Vec { - let crate_name = name.unwrap_or_else(|| cx.tcx.crate_name(did.krate).to_string()); - let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| { - // extern blocks have an empty name - let s = elem.data.to_string(); - if !s.is_empty() { - Some(s) - } else { - None - } - }); - once(crate_name).chain(relative).collect() -} - pub fn enter_impl_trait(cx: &DocContext<'_>, f: F) -> R where F: FnOnce() -> R, diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index e4fba73b8205a..853170542e083 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -35,7 +35,7 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { match ty { clean::Generic(s) => params.entry(s).or_default() .extend(bounds), - t => tybounds.push((t, ty_bounds(bounds))), + t => tybounds.push((t, bounds)), } } WP::RegionPredicate { lifetime, bounds } => { @@ -45,72 +45,30 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { } } - // Simplify the type parameter bounds on all the generics - let mut params = params.into_iter().map(|(k, v)| { - (k, ty_bounds(v)) - }).collect::>(); - // Look for equality predicates on associated types that can be merged into // general bound predicates equalities.retain(|&(ref lhs, ref rhs)| { - let (self_, trait_, name) = match *lhs { - clean::QPath { ref self_type, ref trait_, ref name } => { - (self_type, trait_, name) - } - _ => return true, - }; - let generic = match **self_ { - clean::Generic(ref s) => s, - _ => return true, + let (self_, trait_did, name) = if let Some(p) = lhs.projection() { + p + } else { + return true; }; - let trait_did = match **trait_ { - clean::ResolvedPath { did, .. } => did, + let generic = match self_ { + clean::Generic(s) => s, _ => return true, }; let bounds = match params.get_mut(generic) { Some(bound) => bound, None => return true, }; - !bounds.iter_mut().any(|b| { - let trait_ref = match *b { - clean::GenericBound::TraitBound(ref mut tr, _) => tr, - clean::GenericBound::Outlives(..) => return false, - }; - let (did, path) = match trait_ref.trait_ { - clean::ResolvedPath { did, ref mut path, ..} => (did, path), - _ => return false, - }; - // If this QPath's trait `trait_did` is the same as, or a supertrait - // of, the bound's trait `did` then we can keep going, otherwise - // this is just a plain old equality bound. - if !trait_is_same_or_supertrait(cx, did, trait_did) { - return false - } - let last = path.segments.last_mut().expect("segments were empty"); - match last.args { - PP::AngleBracketed { ref mut bindings, .. } => { - bindings.push(clean::TypeBinding { - name: name.clone(), - kind: clean::TypeBindingKind::Equality { - ty: rhs.clone(), - }, - }); - } - PP::Parenthesized { ref mut output, .. } => { - assert!(output.is_none()); - if *rhs != clean::Type::Tuple(Vec::new()) { - *output = Some(rhs.clone()); - } - } - }; - true - }) + + merge_bounds(cx, bounds, trait_did, name, rhs) }); // And finally, let's reassemble everything let mut clauses = Vec::new(); clauses.extend(lifetimes.into_iter().map(|(lt, bounds)| { - WP::RegionPredicate { lifetime: lt, bounds: bounds } + WP::RegionPredicate { lifetime: lt, bounds } })); clauses.extend(params.into_iter().map(|(k, v)| { WP::BoundPredicate { @@ -119,19 +77,62 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { } })); clauses.extend(tybounds.into_iter().map(|(ty, bounds)| { - WP::BoundPredicate { ty: ty, bounds: bounds } + WP::BoundPredicate { ty, bounds } })); clauses.extend(equalities.into_iter().map(|(lhs, rhs)| { - WP::EqPredicate { lhs: lhs, rhs: rhs } + WP::EqPredicate { lhs, rhs } })); clauses } +pub fn merge_bounds( + cx: &clean::DocContext<'_>, + bounds: &mut Vec, + trait_did: DefId, + name: &str, + rhs: &clean::Type, +) -> bool { + !bounds.iter_mut().any(|b| { + let trait_ref = match *b { + clean::GenericBound::TraitBound(ref mut tr, _) => tr, + clean::GenericBound::Outlives(..) => return false, + }; + let (did, path) = match trait_ref.trait_ { + clean::ResolvedPath { did, ref mut path, ..} => (did, path), + _ => return false, + }; + // If this QPath's trait `trait_did` is the same as, or a supertrait + // of, the bound's trait `did` then we can keep going, otherwise + // this is just a plain old equality bound. + if !trait_is_same_or_supertrait(cx, did, trait_did) { + return false + } + let last = path.segments.last_mut().expect("segments were empty"); + match last.args { + PP::AngleBracketed { ref mut bindings, .. } => { + bindings.push(clean::TypeBinding { + name: name.to_string(), + kind: clean::TypeBindingKind::Equality { + ty: rhs.clone(), + }, + }); + } + PP::Parenthesized { ref mut output, .. } => match output { + Some(o) => assert_eq!(o, rhs), + None => if *rhs != clean::Type::Tuple(Vec::new()) { + *output = Some(rhs.clone()); + } + } + }; + true + }) +} + pub fn ty_params(mut params: Vec) -> Vec { for param in &mut params { match param.kind { clean::GenericParamDefKind::Type { ref mut bounds, .. } => { - *bounds = ty_bounds(mem::take(bounds)); + *bounds = mem::take(bounds); } _ => panic!("expected only type parameters"), } @@ -139,19 +140,17 @@ pub fn ty_params(mut params: Vec) -> Vec) -> Vec { - bounds -} - fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId) -> bool { if child == trait_ { return true } let predicates = cx.tcx.super_predicates_of(child); + debug_assert!(cx.tcx.generics_of(child).has_self); + let self_ty = cx.tcx.types.self_param; predicates.predicates.iter().filter_map(|(pred, _)| { if let ty::Predicate::Trait(ref pred) = *pred { - if pred.skip_binder().trait_ref.self_ty().is_self() { + if pred.skip_binder().trait_ref.self_ty() == self_ty { Some(pred.def_id()) } else { None diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index db90bb4524dcf..1c0d1b3273731 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -6,9 +6,10 @@ use errors; use getopts; use rustc::lint::Level; use rustc::session; +use rustc::session::config::{CrateType, parse_crate_types_from_list}; use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs}; use rustc::session::config::{nightly_options, build_codegen_options, build_debugging_options, - get_cmd_lint_options, ExternEntry}; + get_cmd_lint_options, host_triple, ExternEntry}; use rustc::session::search_paths::SearchPath; use rustc_driver; use rustc_target::spec::TargetTriple; @@ -32,27 +33,33 @@ pub struct Options { pub input: PathBuf, /// The name of the crate being documented. pub crate_name: Option, + /// Whether or not this is a proc-macro crate + pub proc_macro_crate: bool, /// How to format errors and warnings. pub error_format: ErrorOutputType, /// Library search paths to hand to the compiler. pub libs: Vec, + /// Library search paths strings to hand to the compiler. + pub lib_strs: Vec, /// The list of external crates to link against. pub externs: Externs, + /// The list of external crates strings to link against. + pub extern_strs: Vec, /// List of `cfg` flags to hand to the compiler. Always includes `rustdoc`. pub cfgs: Vec, /// Codegen options to hand to the compiler. pub codegen_options: CodegenOptions, + /// Codegen options strings to hand to the compiler. + pub codegen_options_strs: Vec, /// Debugging (`-Z`) options to pass to the compiler. pub debugging_options: DebuggingOptions, /// The target used to compile the crate against. - pub target: Option, + pub target: TargetTriple, /// Edition used when reading the crate. Defaults to "2015". Also used by default when /// compiling doctests from the crate. pub edition: Edition, /// The path to the sysroot. Used during the compilation process. pub maybe_sysroot: Option, - /// Linker to use when building doctests. - pub linker: Option, /// Lint information passed over the command-line. pub lint_opts: Vec<(String, Level)>, /// Whether to ask rustc to describe the lints it knows. Practically speaking, this will not be @@ -70,6 +77,18 @@ pub struct Options { /// Optional path to persist the doctest executables to, defaults to a /// temporary directory if not set. pub persist_doctests: Option, + /// Runtool to run doctests with + pub runtool: Option, + /// Arguments to pass to the runtool + pub runtool_args: Vec, + /// Whether to allow ignoring doctests on a per-target basis + /// For example, using ignore-foo to ignore running the doctest on any target that + /// contains "foo" as a substring + pub enable_per_target_ignores: bool, + + /// The path to a rustc-like binary to build tests with. If not set, we + /// default to loading from $sysroot/bin/rustc. + pub test_builder: Option, // Options that affect the documentation process @@ -111,6 +130,7 @@ impl fmt::Debug for Options { f.debug_struct("Options") .field("input", &self.input) .field("crate_name", &self.crate_name) + .field("proc_macro_crate", &self.proc_macro_crate) .field("error_format", &self.error_format) .field("libs", &self.libs) .field("externs", &FmtExterns(&self.externs)) @@ -120,7 +140,6 @@ impl fmt::Debug for Options { .field("target", &self.target) .field("edition", &self.edition) .field("maybe_sysroot", &self.maybe_sysroot) - .field("linker", &self.linker) .field("lint_opts", &self.lint_opts) .field("describe_lints", &self.describe_lints) .field("lint_cap", &self.lint_cap) @@ -133,6 +152,9 @@ impl fmt::Debug for Options { .field("show_coverage", &self.show_coverage) .field("crate_version", &self.crate_version) .field("render_options", &self.render_options) + .field("runtool", &self.runtool) + .field("runtool_args", &self.runtool_args) + .field("enable-per-target-ignores", &self.enable_per_target_ignores) .finish() } } @@ -220,22 +242,22 @@ impl Options { println!("{:>20} - {}", pass.name, pass.description); } println!("\nDefault passes for rustdoc:"); - for &name in passes::DEFAULT_PASSES { - println!("{:>20}", name); + for pass in passes::DEFAULT_PASSES { + println!("{:>20}", pass.name); } println!("\nPasses run with `--document-private-items`:"); - for &name in passes::DEFAULT_PRIVATE_PASSES { - println!("{:>20}", name); + for pass in passes::DEFAULT_PRIVATE_PASSES { + println!("{:>20}", pass.name); } if nightly_options::is_nightly_build() { println!("\nPasses run with `--show-coverage`:"); - for &name in passes::DEFAULT_COVERAGE_PASSES { - println!("{:>20}", name); + for pass in passes::DEFAULT_COVERAGE_PASSES { + println!("{:>20}", pass.name); } println!("\nPasses run with `--show-coverage --document-private-items`:"); - for &name in passes::PRIVATE_COVERAGE_PASSES { - println!("{:>20}", name); + for pass in passes::PRIVATE_COVERAGE_PASSES { + println!("{:>20}", pass.name); } } @@ -321,11 +343,7 @@ impl Options { let output = matches.opt_str("o") .map(|s| PathBuf::from(&s)) .unwrap_or_else(|| PathBuf::from("doc")); - let mut cfgs = matches.opt_strs("cfg"); - cfgs.push("rustdoc".to_string()); - if should_test { - cfgs.push("doctest".to_string()); - } + let cfgs = matches.opt_strs("cfg"); let extension_css = matches.opt_str("e").map(|s| PathBuf::from(&s)); @@ -378,7 +396,7 @@ impl Options { &matches.opt_strs("html-after-content"), &matches.opt_strs("markdown-before-content"), &matches.opt_strs("markdown-after-content"), - &diag, &mut id_map, edition) { + &diag, &mut id_map, edition, &None) { Some(eh) => eh, None => return Err(3), }; @@ -407,7 +425,9 @@ impl Options { } } - let target = matches.opt_str("target").map(|target| { + let target = matches.opt_str("target").map_or( + TargetTriple::from_triple(host_triple()), + |target| { if target.ends_with(".json") { TargetTriple::TargetPath(PathBuf::from(target)) } else { @@ -431,11 +451,19 @@ impl Options { }; let manual_passes = matches.opt_strs("passes"); + let crate_types = match parse_crate_types_from_list(matches.opt_strs("crate-type")) { + Ok(types) => types, + Err(e) =>{ + diag.struct_err(&format!("unknown crate type: {}", e)).emit(); + return Err(1); + } + }; + let crate_name = matches.opt_str("crate-name"); + let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro); let playground_url = matches.opt_str("playground-url"); let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from); let display_warnings = matches.opt_present("display-warnings"); - 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").unwrap_or_default(); let enable_minification = !matches.opt_present("disable-minification"); @@ -448,22 +476,32 @@ impl Options { let generate_search_filter = !matches.opt_present("disable-per-crate-search"); let persist_doctests = matches.opt_str("persist-doctests").map(PathBuf::from); let generate_redirect_pages = matches.opt_present("generate-redirect-pages"); + let test_builder = matches.opt_str("test-builder").map(PathBuf::from); + let codegen_options_strs = matches.opt_strs("C"); + let lib_strs = matches.opt_strs("L"); + let extern_strs = matches.opt_strs("extern"); + let runtool = matches.opt_str("runtool"); + let runtool_args = matches.opt_strs("runtool-arg"); + let enable_per_target_ignores = matches.opt_present("enable-per-target-ignores"); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); Ok(Options { input, crate_name, + proc_macro_crate, error_format, libs, + lib_strs, externs, + extern_strs, cfgs, codegen_options, + codegen_options_strs, debugging_options, target, edition, maybe_sysroot, - linker, lint_opts, describe_lints, lint_cap, @@ -475,6 +513,10 @@ impl Options { show_coverage, crate_version, persist_doctests, + runtool, + runtool_args, + enable_per_target_ignores, + test_builder, render_options: RenderOptions { output, external_html, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index cc79f4ab09a51..00265caa965ea 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -13,26 +13,23 @@ use rustc_interface::interface; use rustc_driver::abort_on_err; use rustc_resolve as resolve; use rustc_metadata::cstore::CStore; -use rustc_target::spec::TargetTriple; use syntax::source_map; +use syntax::attr; use syntax::feature_gate::UnstableFeatures; use syntax::json::JsonEmitter; use syntax::symbol::sym; use errors; use errors::emitter::{Emitter, EmitterWriter}; -use parking_lot::ReentrantMutex; use std::cell::RefCell; use std::mem; use rustc_data_structures::sync::{self, Lrc}; -use std::sync::Arc; use std::rc::Rc; -use crate::visit_ast::RustdocVisitor; use crate::config::{Options as RustdocOptions, RenderOptions}; use crate::clean; -use crate::clean::{Clean, MAX_DEF_ID, AttributesExt}; +use crate::clean::{MAX_DEF_ID, AttributesExt}; use crate::html::render::RenderInfo; use crate::passes; @@ -45,17 +42,15 @@ pub type ExternalPaths = FxHashMap, clean::TypeKind)>; pub struct DocContext<'tcx> { pub tcx: TyCtxt<'tcx>, - pub resolver: Rc>>, - /// The stack of module NodeIds up till this point - pub crate_name: Option, + pub resolver: Rc>, pub cstore: Lrc, /// Later on moved into `html::render::CACHE_KEY` pub renderinfo: RefCell, /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY` - pub external_traits: Arc>>>, + pub external_traits: Rc>>, /// Used while populating `external_traits` to ensure we don't process the same trait twice at /// the same time. - pub active_extern_traits: RefCell>, + pub active_extern_traits: RefCell>, // The current set of type and lifetime substitutions, // for expanding type aliases at the HIR level: @@ -65,14 +60,13 @@ pub struct DocContext<'tcx> { pub lt_substs: RefCell>, /// Table `DefId` of const parameter -> substituted const pub ct_substs: RefCell>, - /// Table DefId of `impl Trait` in argument position -> bounds - pub impl_trait_bounds: RefCell>>, + /// Table synthetic type parameter for `impl Trait` in argument position -> bounds + pub impl_trait_bounds: RefCell>>, pub fake_def_ids: RefCell>, pub all_fake_def_ids: RefCell>, /// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`. // FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set. pub generated_synthetics: RefCell, DefId)>>, - pub all_traits: Vec, pub auto_traits: Vec, } @@ -83,9 +77,7 @@ impl<'tcx> DocContext<'tcx> { pub fn enter_resolver(&self, f: F) -> R where F: FnOnce(&mut resolve::Resolver<'_>) -> R { - let resolver = &*self.resolver; - let resolver = resolver.as_ref().unwrap(); - resolver.borrow_mut().access(f) + self.resolver.borrow_mut().access(f) } /// Call the closure with the given parameters set as @@ -167,15 +159,15 @@ impl<'tcx> DocContext<'tcx> { self.tcx.hir().as_local_hir_id(def_id) } } -} -pub trait DocAccessLevels { - fn is_doc_reachable(&self, did: DefId) -> bool; -} + pub fn stability(&self, id: HirId) -> Option { + self.tcx.hir().opt_local_def_id(id) + .and_then(|def_id| self.tcx.lookup_stability(def_id)).cloned() + } -impl DocAccessLevels for AccessLevels { - fn is_doc_reachable(&self, did: DefId) -> bool { - self.is_public(did) + pub fn deprecation(&self, id: HirId) -> Option { + self.tcx.hir().opt_local_def_id(id) + .and_then(|def_id| self.tcx.lookup_deprecation(def_id)) } } @@ -200,6 +192,8 @@ pub fn new_handler(error_format: ErrorOutputType, source_map.map(|cm| cm as _), short, sessopts.debugging_opts.teach, + sessopts.debugging_opts.terminal_width, + false, ).ui_testing(ui_testing) ) }, @@ -212,6 +206,7 @@ pub fn new_handler(error_format: ErrorOutputType, source_map, pretty, json_rendered, + false, ).ui_testing(ui_testing) ) }, @@ -229,16 +224,17 @@ pub fn new_handler(error_format: ErrorOutputType, ) } -pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOptions, Vec) { +pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOptions) { // Parse, resolve, and typecheck the given crate. let RustdocOptions { input, crate_name, + proc_macro_crate, error_format, libs, externs, - cfgs, + mut cfgs, codegen_options, debugging_options, target, @@ -254,6 +250,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt .. } = options; + // Add the rustdoc cfg into the doc build. + cfgs.push("rustdoc".to_string()); + let cpath = Some(input.clone()); let input = Input::File(input); @@ -299,12 +298,16 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt } }).collect(); - let host_triple = TargetTriple::from_triple(config::host_triple()); + let crate_types = if proc_macro_crate { + vec![config::CrateType::ProcMacro] + } else { + vec![config::CrateType::Rlib] + }; // plays with error output here! let sessopts = config::Options { maybe_sysroot, search_paths: libs, - crate_types: vec![config::CrateType::Rlib], + crate_types, lint_opts: if !display_warnings { lint_opts } else { @@ -313,7 +316,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt lint_cap: Some(lint_cap.unwrap_or_else(|| lint::Forbid)), cg: codegen_options, externs, - target_triple: target.unwrap_or(host_triple), + target_triple: target, // Ensure that rustdoc works even if rustc is feature-staged unstable_features: UnstableFeatures::Allow, actually_rustdoc: true, @@ -334,7 +337,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt file_loader: None, diagnostic_output: DiagnosticOutput::Default, stderr: None, - crate_name: crate_name.clone(), + crate_name, lint_caps, }; @@ -344,7 +347,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt // We need to hold on to the complete resolver, so we cause everything to be // cloned for the analysis passes to use. Suboptimal, but necessary in the // current architecture. - let resolver = abort_on_err(compiler.expansion(), sess).peek().1.clone(); + let resolver = abort_on_err(compiler.expansion(), sess).peek().1.borrow().clone(); if sess.has_errors() { sess.fatal("Compilation failed, aborting rustdoc"); @@ -370,11 +373,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let mut renderinfo = RenderInfo::default(); renderinfo.access_levels = access_levels; - let all_traits = tcx.all_traits(LOCAL_CRATE).to_vec(); - let ctxt = DocContext { + let mut ctxt = DocContext { tcx, resolver, - crate_name, cstore: compiler.cstore().clone(), external_traits: Default::default(), active_extern_traits: Default::default(), @@ -386,18 +387,13 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt fake_def_ids: Default::default(), all_fake_def_ids: Default::default(), generated_synthetics: Default::default(), - auto_traits: all_traits.iter().cloned().filter(|trait_def_id| { + auto_traits: tcx.all_traits(LOCAL_CRATE).iter().cloned().filter(|trait_def_id| { tcx.trait_is_auto(*trait_def_id) }).collect(), - all_traits, }; debug!("crate: {:?}", tcx.hir().krate()); - let mut krate = { - let mut v = RustdocVisitor::new(&ctxt); - v.visit(tcx.hir().krate()); - v.clean(&ctxt) - }; + let mut krate = clean::krate(&mut ctxt); fn report_deprecated_attr(name: &str, diag: &errors::Handler) { let mut msg = diag.struct_warn(&format!("the `#![doc({})]` attribute is \ @@ -438,8 +434,8 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt }, _ => continue, }; - for p in value.as_str().split_whitespace() { - sink.push(p.to_string()); + for name in value.as_str().split_whitespace() { + sink.push(name.to_string()); } } @@ -450,25 +446,46 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt } } - let mut passes: Vec = - passes::defaults(default_passes).iter().map(|p| p.to_string()).collect(); - passes.extend(manual_passes); + let passes = passes::defaults(default_passes).iter().chain(manual_passes.into_iter() + .flat_map(|name| { + if let Some(pass) = passes::find_pass(&name) { + Some(pass) + } else { + error!("unknown pass {}, skipping", name); + None + } + })); info!("Executing passes"); - for pass_name in &passes { - match passes::find_pass(pass_name).map(|p| p.pass) { - Some(pass) => { - debug!("running pass {}", pass_name); - krate = pass(krate, &ctxt); - } - None => error!("unknown pass {}, skipping", *pass_name), - } + for pass in passes { + debug!("running pass {}", pass.name); + krate = (pass.pass)(krate, &ctxt); } ctxt.sess().abort_if_errors(); - (krate, ctxt.renderinfo.into_inner(), render_options, passes) + (krate, ctxt.renderinfo.into_inner(), render_options) }) }) } + +/// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter +/// for `impl Trait` in argument position. +#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum ImplTraitParam { + DefId(DefId), + ParamIndex(u32), +} + +impl From for ImplTraitParam { + fn from(did: DefId) -> Self { + ImplTraitParam::DefId(did) + } +} + +impl From for ImplTraitParam { + fn from(idx: u32) -> Self { + ImplTraitParam::ParamIndex(idx) + } +} diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index ec60241a92d4e..6e453561f6da2 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -3,8 +3,7 @@ pub use self::StructType::*; use syntax::ast; -use syntax::ast::{Name, NodeId}; -use syntax::attr; +use syntax::ast::Name; use syntax::ext::base::MacroKind; use syntax_pos::{self, Span}; @@ -14,7 +13,7 @@ use rustc::hir::ptr::P; pub struct Module<'hir> { pub name: Option, - pub attrs: &'hir hir::HirVec, + pub attrs: &'hir [ast::Attribute], pub where_outer: Span, pub where_inner: Span, pub extern_crates: Vec>, @@ -24,15 +23,13 @@ pub struct Module<'hir> { pub enums: Vec>, pub fns: Vec>, pub mods: Vec>, - pub id: NodeId, + pub id: hir::HirId, pub typedefs: Vec>, pub opaque_tys: Vec>, pub statics: Vec>, pub constants: Vec>, pub traits: Vec>, pub vis: &'hir hir::Visibility, - pub stab: Option, - pub depr: Option, pub impls: Vec>, pub foreigns: Vec>, pub macros: Vec>, @@ -44,15 +41,13 @@ pub struct Module<'hir> { impl Module<'hir> { pub fn new( name: Option, - attrs: &'hir hir::HirVec, + attrs: &'hir [ast::Attribute], vis: &'hir hir::Visibility, ) -> Module<'hir> { Module { name : name, - id: ast::CRATE_NODE_ID, + id: hir::CRATE_HIR_ID, vis, - stab: None, - depr: None, where_outer: syntax_pos::DUMMY_SP, where_inner: syntax_pos::DUMMY_SP, attrs, @@ -90,37 +85,31 @@ pub enum StructType { pub struct Struct<'hir> { pub vis: &'hir hir::Visibility, - pub stab: Option, - pub depr: Option, pub id: hir::HirId, pub struct_type: StructType, pub name: Name, pub generics: &'hir hir::Generics, - pub attrs: &'hir hir::HirVec, + pub attrs: &'hir [ast::Attribute], pub fields: &'hir [hir::StructField], pub whence: Span, } pub struct Union<'hir> { pub vis: &'hir hir::Visibility, - pub stab: Option, - pub depr: Option, pub id: hir::HirId, pub struct_type: StructType, pub name: Name, pub generics: &'hir hir::Generics, - pub attrs: &'hir hir::HirVec, + pub attrs: &'hir [ast::Attribute], pub fields: &'hir [hir::StructField], pub whence: Span, } pub struct Enum<'hir> { pub vis: &'hir hir::Visibility, - pub stab: Option, - pub depr: Option, pub variants: Vec>, pub generics: &'hir hir::Generics, - pub attrs: &'hir hir::HirVec, + pub attrs: &'hir [ast::Attribute], pub id: hir::HirId, pub whence: Span, pub name: Name, @@ -129,21 +118,17 @@ pub struct Enum<'hir> { pub struct Variant<'hir> { pub name: Name, pub id: hir::HirId, - pub attrs: &'hir hir::HirVec, + pub attrs: &'hir [ast::Attribute], pub def: &'hir hir::VariantData, - pub stab: Option, - pub depr: Option, pub whence: Span, } pub struct Function<'hir> { pub decl: &'hir hir::FnDecl, - pub attrs: &'hir hir::HirVec, + pub attrs: &'hir [ast::Attribute], pub id: hir::HirId, pub name: Name, pub vis: &'hir hir::Visibility, - pub stab: Option, - pub depr: Option, pub header: hir::FnHeader, pub whence: Span, pub generics: &'hir hir::Generics, @@ -155,22 +140,18 @@ pub struct Typedef<'hir> { pub gen: &'hir hir::Generics, pub name: Name, pub id: hir::HirId, - pub attrs: &'hir hir::HirVec, + pub attrs: &'hir [ast::Attribute], pub whence: Span, pub vis: &'hir hir::Visibility, - pub stab: Option, - pub depr: Option, } pub struct OpaqueTy<'hir> { pub opaque_ty: &'hir hir::OpaqueTy, pub name: Name, pub id: hir::HirId, - pub attrs: &'hir hir::HirVec, + pub attrs: &'hir [ast::Attribute], pub whence: Span, pub vis: &'hir hir::Visibility, - pub stab: Option, - pub depr: Option, } #[derive(Debug)] @@ -179,10 +160,8 @@ pub struct Static<'hir> { pub mutability: hir::Mutability, pub expr: hir::BodyId, pub name: Name, - pub attrs: &'hir hir::HirVec, + pub attrs: &'hir [ast::Attribute], pub vis: &'hir hir::Visibility, - pub stab: Option, - pub depr: Option, pub id: hir::HirId, pub whence: Span, } @@ -191,10 +170,8 @@ pub struct Constant<'hir> { pub type_: &'hir P, pub expr: hir::BodyId, pub name: Name, - pub attrs: &'hir hir::HirVec, + pub attrs: &'hir [ast::Attribute], pub vis: &'hir hir::Visibility, - pub stab: Option, - pub depr: Option, pub id: hir::HirId, pub whence: Span, } @@ -205,25 +182,21 @@ pub struct Trait<'hir> { pub name: Name, pub items: Vec<&'hir hir::TraitItem>, pub generics: &'hir hir::Generics, - pub bounds: &'hir hir::HirVec, - pub attrs: &'hir hir::HirVec, + pub bounds: &'hir [hir::GenericBound], + pub attrs: &'hir [ast::Attribute], pub id: hir::HirId, pub whence: Span, pub vis: &'hir hir::Visibility, - pub stab: Option, - pub depr: Option, } pub struct TraitAlias<'hir> { pub name: Name, pub generics: &'hir hir::Generics, - pub bounds: &'hir hir::HirVec, - pub attrs: &'hir hir::HirVec, + pub bounds: &'hir [hir::GenericBound], + pub attrs: &'hir [ast::Attribute], pub id: hir::HirId, pub whence: Span, pub vis: &'hir hir::Visibility, - pub stab: Option, - pub depr: Option, } #[derive(Debug)] @@ -235,22 +208,18 @@ pub struct Impl<'hir> { pub trait_: &'hir Option, pub for_: &'hir P, pub items: Vec<&'hir hir::ImplItem>, - pub attrs: &'hir hir::HirVec, + pub attrs: &'hir [ast::Attribute], pub whence: Span, pub vis: &'hir hir::Visibility, - pub stab: Option, - pub depr: Option, pub id: hir::HirId, } pub struct ForeignItem<'hir> { pub vis: &'hir hir::Visibility, - pub stab: Option, - pub depr: Option, pub id: hir::HirId, pub name: Name, pub kind: &'hir hir::ForeignItemKind, - pub attrs: &'hir hir::HirVec, + pub attrs: &'hir [ast::Attribute], pub whence: Span, } @@ -258,12 +227,11 @@ pub struct ForeignItem<'hir> { // these imported macro_rules (which only have a DUMMY_NODE_ID). pub struct Macro<'hir> { pub name: Name, + pub hid: hir::HirId, pub def_id: hir::def_id::DefId, - pub attrs: &'hir hir::HirVec, + pub attrs: &'hir [ast::Attribute], pub whence: Span, pub matchers: hir::HirVec, - pub stab: Option, - pub depr: Option, pub imported_from: Option, } @@ -272,7 +240,7 @@ pub struct ExternCrate<'hir> { pub cnum: CrateNum, pub path: Option, pub vis: &'hir hir::Visibility, - pub attrs: &'hir hir::HirVec, + pub attrs: &'hir [ast::Attribute], pub whence: Span, } @@ -280,7 +248,7 @@ pub struct Import<'hir> { pub name: Name, pub id: hir::HirId, pub vis: &'hir hir::Visibility, - pub attrs: &'hir hir::HirVec, + pub attrs: &'hir [ast::Attribute], pub path: &'hir hir::Path, pub glob: bool, pub whence: Span, @@ -291,10 +259,8 @@ pub struct ProcMacro<'hir> { pub id: hir::HirId, pub kind: MacroKind, pub helpers: Vec, - pub attrs: &'hir hir::HirVec, + pub attrs: &'hir [ast::Attribute], pub whence: Span, - pub stab: Option, - pub depr: Option, } pub fn struct_type_from_def(vdata: &hir::VariantData) -> StructType { diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index d604ba11d4186..56f1191feed0b 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -4,9 +4,7 @@ use std::str; use errors; use crate::syntax::feature_gate::UnstableFeatures; use crate::syntax::edition::Edition; -use crate::html::markdown::{IdMap, ErrorCodes, Markdown}; - -use std::cell::RefCell; +use crate::html::markdown::{IdMap, ErrorCodes, Markdown, Playground}; #[derive(Clone, Debug)] pub struct ExternalHtml { @@ -24,37 +22,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], diag: &errors::Handler, - id_map: &mut IdMap, edition: Edition) + id_map: &mut IdMap, edition: Edition, playground: &Option) -> Option { let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); - load_external_files(in_header, diag) - .and_then(|ih| - load_external_files(before_content, diag) - .map(|bc| (ih, bc)) - ) - .and_then(|(ih, bc)| - load_external_files(md_before_content, diag) - .map(|m_bc| (ih, - format!("{}{}", bc, Markdown(&m_bc, &[], RefCell::new(id_map), - codes, edition)))) - ) - .and_then(|(ih, bc)| - load_external_files(after_content, diag) - .map(|ac| (ih, bc, ac)) - ) - .and_then(|(ih, bc, ac)| - load_external_files(md_after_content, diag) - .map(|m_ac| (ih, bc, - format!("{}{}", ac, Markdown(&m_ac, &[], RefCell::new(id_map), - codes, edition)))) - ) - .map(|(ih, bc, ac)| - ExternalHtml { - in_header: ih, - before_content: bc, - after_content: ac, - } - ) + let ih = load_external_files(in_header, diag)?; + let bc = load_external_files(before_content, diag)?; + let m_bc = load_external_files(md_before_content, diag)?; + let bc = format!("{}{}", bc, Markdown(&m_bc, &[], id_map, + codes, edition, playground).to_string()); + let ac = load_external_files(after_content, diag)?; + let m_ac = load_external_files(md_after_content, diag)?; + let ac = format!("{}{}", ac, Markdown(&m_ac, &[], id_map, + codes, edition, playground).to_string()); + Some(ExternalHtml { + in_header: ih, + before_content: bc, + after_content: ac, + }) } } diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index cfa22bc27b758..5482239c7ce28 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -105,12 +105,12 @@ pub trait DocFolder : Sized { c.module = c.module.take().and_then(|module| self.fold_item(module)); { - let guard = c.external_traits.lock(); - let traits = guard.replace(Default::default()); - guard.borrow_mut().extend(traits.into_iter().map(|(k, mut v)| { + let mut guard = c.external_traits.borrow_mut(); + let external_traits = std::mem::replace(&mut *guard, Default::default()); + *guard = external_traits.into_iter().map(|(k, mut v)| { v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect(); (k, v) - })); + }).collect(); } c } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 9e5cc03b83123..4cde868201eef 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -6,6 +6,7 @@ //! them in the future to instead emit any format desired. use std::borrow::Cow; +use std::cell::Cell; use std::fmt; use rustc::hir::def_id::DefId; @@ -14,38 +15,98 @@ use rustc_target::spec::abi::Abi; use rustc::hir; use crate::clean::{self, PrimitiveType}; -use crate::core::DocAccessLevels; use crate::html::item_type::ItemType; -use crate::html::render::{self, cache, CURRENT_LOCATION_KEY}; - -/// Helper to render an optional visibility with a space after it (if the -/// visibility is preset) -#[derive(Copy, Clone)] -pub struct VisSpace<'a>(pub &'a Option); -/// Similarly to VisSpace, this structure is used to render a function style with a -/// space after it. -#[derive(Copy, Clone)] -pub struct UnsafetySpace(pub hir::Unsafety); -/// Similarly to VisSpace, this structure is used to render a function constness -/// with a space after it. -#[derive(Copy, Clone)] -pub struct ConstnessSpace(pub hir::Constness); -/// Similarly to VisSpace, this structure is used to render a function asyncness -/// with a space after it. -#[derive(Copy, Clone)] -pub struct AsyncSpace(pub hir::IsAsync); -/// Similar to VisSpace, but used for mutability -#[derive(Copy, Clone)] -pub struct MutableSpace(pub clean::Mutability); -/// Similar to VisSpace, but used for mutability -#[derive(Copy, Clone)] -pub struct RawMutableSpace(pub clean::Mutability); -/// Wrapper struct for emitting type parameter bounds. -pub struct GenericBounds<'a>(pub &'a [clean::GenericBound]); -/// Wrapper struct for emitting a comma-separated list of items -pub struct CommaSep<'a, T>(pub &'a [T]); -pub struct AbiSpace(pub Abi); -pub struct DefaultSpace(pub bool); +use crate::html::render::{self, cache, CURRENT_DEPTH}; + +pub trait Print { + fn print(self, buffer: &mut Buffer); +} + +impl Print for F + where F: FnOnce(&mut Buffer), +{ + fn print(self, buffer: &mut Buffer) { + (self)(buffer) + } +} + +impl Print for String { + fn print(self, buffer: &mut Buffer) { + buffer.write_str(&self); + } +} + +impl Print for &'_ str { + fn print(self, buffer: &mut Buffer) { + buffer.write_str(self); + } +} + +#[derive(Debug, Clone)] +pub struct Buffer { + for_html: bool, + buffer: String, +} + +impl Buffer { + crate fn empty_from(v: &Buffer) -> Buffer { + Buffer { + for_html: v.for_html, + buffer: String::new(), + } + } + + crate fn html() -> Buffer { + Buffer { + for_html: true, + buffer: String::new(), + } + } + + crate fn is_empty(&self) -> bool { + self.buffer.is_empty() + } + + crate fn into_inner(self) -> String { + self.buffer + } + + crate fn insert_str(&mut self, idx: usize, s: &str) { + self.buffer.insert_str(idx, s); + } + + crate fn push_str(&mut self, s: &str) { + self.buffer.push_str(s); + } + + // Intended for consumption by write! and writeln! (std::fmt) but without + // the fmt::Result return type imposed by fmt::Write (and avoiding the trait + // import). + crate fn write_str(&mut self, s: &str) { + self.buffer.push_str(s); + } + + // Intended for consumption by write! and writeln! (std::fmt) but without + // the fmt::Result return type imposed by fmt::Write (and avoiding the trait + // import). + crate fn write_fmt(&mut self, v: fmt::Arguments<'_>) { + use fmt::Write; + self.buffer.write_fmt(v).unwrap(); + } + + crate fn to_display(mut self, t: T) -> String { + t.print(&mut self); + self.into_inner() + } + + crate fn from_display(&mut self, t: T) { + if self.for_html { + write!(self, "{}", t); + } else { + write!(self, "{:#}", t); + } + } +} /// Wrapper struct for properly emitting a function or method declaration. pub struct Function<'a> { @@ -72,107 +133,89 @@ pub struct WhereClause<'a>{ pub end_newline: bool, } -pub struct HRef<'a> { - pub did: DefId, - pub text: &'a str, -} - -impl<'a> VisSpace<'a> { - pub fn get(self) -> &'a Option { - let VisSpace(v) = self; v - } -} - -impl UnsafetySpace { - pub fn get(&self) -> hir::Unsafety { - let UnsafetySpace(v) = *self; v - } -} - -impl ConstnessSpace { - pub fn get(&self) -> hir::Constness { - let ConstnessSpace(v) = *self; v - } -} - -impl<'a, T: fmt::Display> fmt::Display for CommaSep<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for (i, item) in self.0.iter().enumerate() { +fn comma_sep(items: impl Iterator) -> impl fmt::Display { + display_fn(move |f| { + for (i, item) in items.enumerate() { if i != 0 { write!(f, ", ")?; } - fmt::Display::fmt(item, f)?; + fmt::Display::fmt(&item, f)?; } Ok(()) - } + }) } -impl<'a> fmt::Display for GenericBounds<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +crate fn print_generic_bounds(bounds: &[clean::GenericBound]) -> impl fmt::Display + '_ { + display_fn(move |f| { let mut bounds_dup = FxHashSet::default(); - let &GenericBounds(bounds) = self; - for (i, bound) in bounds.iter().filter(|b| bounds_dup.insert(b.to_string())).enumerate() { + for (i, bound) in bounds.iter().filter(|b| { + bounds_dup.insert(b.print().to_string()) + }).enumerate() { if i > 0 { f.write_str(" + ")?; } - fmt::Display::fmt(bound, f)?; + fmt::Display::fmt(&bound.print(), f)?; } Ok(()) - } + }) } -impl fmt::Display for clean::GenericParamDef { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.kind { - clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name), - clean::GenericParamDefKind::Type { ref bounds, ref default, .. } => { - f.write_str(&self.name)?; +impl clean::GenericParamDef { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + match self.kind { + clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name), + clean::GenericParamDefKind::Type { ref bounds, ref default, .. } => { + f.write_str(&self.name)?; - if !bounds.is_empty() { - if f.alternate() { - write!(f, ": {:#}", GenericBounds(bounds))?; - } else { - write!(f, ": {}", GenericBounds(bounds))?; + if !bounds.is_empty() { + if f.alternate() { + write!(f, ": {:#}", print_generic_bounds(bounds))?; + } else { + write!(f, ": {}", print_generic_bounds(bounds))?; + } + } + + if let Some(ref ty) = default { + if f.alternate() { + write!(f, " = {:#}", ty.print())?; + } else { + write!(f, " = {}", ty.print())?; + } } + + Ok(()) } + clean::GenericParamDefKind::Const { ref ty, .. } => { + f.write_str("const ")?; + f.write_str(&self.name)?; - if let Some(ref ty) = default { if f.alternate() { - write!(f, " = {:#}", ty)?; + write!(f, ": {:#}", ty.print()) } else { - write!(f, " = {}", ty)?; + write!(f, ": {}", ty.print()) } } - - Ok(()) } - clean::GenericParamDefKind::Const { ref ty, .. } => { - f.write_str("const ")?; - f.write_str(&self.name)?; - - if f.alternate() { - write!(f, ": {:#}", ty) - } else { - write!(f, ": {}", ty) - } - } - } + }) } } -impl fmt::Display for clean::Generics { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let real_params = self.params - .iter() - .filter(|p| !p.is_synthetic_type_param()) - .collect::>(); - if real_params.is_empty() { - return Ok(()); - } - if f.alternate() { - write!(f, "<{:#}>", CommaSep(&real_params)) - } else { - write!(f, "<{}>", CommaSep(&real_params)) - } +impl clean::Generics { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + let real_params = self.params + .iter() + .filter(|p| !p.is_synthetic_type_param()) + .collect::>(); + if real_params.is_empty() { + return Ok(()); + } + if f.alternate() { + write!(f, "<{:#}>", comma_sep(real_params.iter().map(|g| g.print()))) + } else { + write!(f, "<{}>", comma_sep(real_params.iter().map(|g| g.print()))) + } + }) } } @@ -203,24 +246,26 @@ impl<'a> fmt::Display for WhereClause<'a> { &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => { let bounds = bounds; if f.alternate() { - clause.push_str(&format!("{:#}: {:#}", ty, GenericBounds(bounds))); + clause.push_str(&format!("{:#}: {:#}", + ty.print(), print_generic_bounds(bounds))); } else { - clause.push_str(&format!("{}: {}", ty, GenericBounds(bounds))); + clause.push_str(&format!("{}: {}", + ty.print(), print_generic_bounds(bounds))); } } &clean::WherePredicate::RegionPredicate { ref lifetime, ref bounds } => { clause.push_str(&format!("{}: {}", - lifetime, - bounds.iter() - .map(|b| b.to_string()) - .collect::>() - .join(" + "))); + lifetime.print(), + bounds.iter() + .map(|b| b.print().to_string()) + .collect::>() + .join(" + "))); } &clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => { if f.alternate() { - clause.push_str(&format!("{:#} == {:#}", lhs, rhs)); + clause.push_str(&format!("{:#} == {:#}", lhs.print(), rhs.print())); } else { - clause.push_str(&format!("{} == {}", lhs, rhs)); + clause.push_str(&format!("{} == {}", lhs.print(), rhs.print())); } } } @@ -252,172 +297,183 @@ impl<'a> fmt::Display for WhereClause<'a> { } } -impl fmt::Display for clean::Lifetime { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.get_ref())?; - Ok(()) +impl clean::Lifetime { + crate fn print(&self) -> &str { + self.get_ref() } } -impl fmt::Display for clean::Constant { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.expr, f) +impl clean::Constant { + crate fn print(&self) -> &str { + &self.expr } } -impl fmt::Display for clean::PolyTrait { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if !self.generic_params.is_empty() { +impl clean::PolyTrait { + fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + if !self.generic_params.is_empty() { + if f.alternate() { + write!(f, "for<{:#}> ", + comma_sep(self.generic_params.iter().map(|g| g.print())))?; + } else { + write!(f, "for<{}> ", + comma_sep(self.generic_params.iter().map(|g| g.print())))?; + } + } if f.alternate() { - write!(f, "for<{:#}> ", CommaSep(&self.generic_params))?; + write!(f, "{:#}", self.trait_.print()) } else { - write!(f, "for<{}> ", CommaSep(&self.generic_params))?; + write!(f, "{}", self.trait_.print()) } - } - if f.alternate() { - write!(f, "{:#}", self.trait_) - } else { - write!(f, "{}", self.trait_) - } + }) } } -impl fmt::Display for clean::GenericBound { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - clean::GenericBound::Outlives(ref lt) => { - write!(f, "{}", *lt) - } - clean::GenericBound::TraitBound(ref ty, modifier) => { - let modifier_str = match modifier { - hir::TraitBoundModifier::None => "", - hir::TraitBoundModifier::Maybe => "?", - }; - if f.alternate() { - write!(f, "{}{:#}", modifier_str, *ty) - } else { - write!(f, "{}{}", modifier_str, *ty) +impl clean::GenericBound { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + match self { + clean::GenericBound::Outlives(lt) => { + write!(f, "{}", lt.print()) + } + clean::GenericBound::TraitBound(ty, modifier) => { + let modifier_str = match modifier { + hir::TraitBoundModifier::None => "", + hir::TraitBoundModifier::Maybe => "?", + }; + if f.alternate() { + write!(f, "{}{:#}", modifier_str, ty.print()) + } else { + write!(f, "{}{}", modifier_str, ty.print()) + } } } - } + }) } } -impl fmt::Display for clean::GenericArgs { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - clean::GenericArgs::AngleBracketed { ref args, ref bindings } => { - if !args.is_empty() || !bindings.is_empty() { - if f.alternate() { - f.write_str("<")?; - } else { - f.write_str("<")?; - } - let mut comma = false; - for arg in args { - if comma { - f.write_str(", ")?; +impl clean::GenericArgs { + fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + match *self { + clean::GenericArgs::AngleBracketed { ref args, ref bindings } => { + if !args.is_empty() || !bindings.is_empty() { + if f.alternate() { + f.write_str("<")?; + } else { + f.write_str("<")?; + } + let mut comma = false; + for arg in args { + if comma { + f.write_str(", ")?; + } + comma = true; + if f.alternate() { + write!(f, "{:#}", arg.print())?; + } else { + write!(f, "{}", arg.print())?; + } + } + for binding in bindings { + if comma { + f.write_str(", ")?; + } + comma = true; + if f.alternate() { + write!(f, "{:#}", binding.print())?; + } else { + write!(f, "{}", binding.print())?; + } } - comma = true; if f.alternate() { - write!(f, "{:#}", *arg)?; + f.write_str(">")?; } else { - write!(f, "{}", *arg)?; + f.write_str(">")?; } } - for binding in bindings { + } + clean::GenericArgs::Parenthesized { ref inputs, ref output } => { + f.write_str("(")?; + let mut comma = false; + for ty in inputs { if comma { f.write_str(", ")?; } comma = true; if f.alternate() { - write!(f, "{:#}", *binding)?; + write!(f, "{:#}", ty.print())?; } else { - write!(f, "{}", *binding)?; + write!(f, "{}", ty.print())?; } } - if f.alternate() { - f.write_str(">")?; - } else { - f.write_str(">")?; - } - } - } - clean::GenericArgs::Parenthesized { ref inputs, ref output } => { - f.write_str("(")?; - let mut comma = false; - for ty in inputs { - if comma { - f.write_str(", ")?; - } - comma = true; - if f.alternate() { - write!(f, "{:#}", *ty)?; - } else { - write!(f, "{}", *ty)?; - } - } - f.write_str(")")?; - if let Some(ref ty) = *output { - if f.alternate() { - write!(f, " -> {:#}", ty)?; - } else { - write!(f, " -> {}", ty)?; + f.write_str(")")?; + if let Some(ref ty) = *output { + if f.alternate() { + write!(f, " -> {:#}", ty.print())?; + } else { + write!(f, " -> {}", ty.print())?; + } } } } - } - Ok(()) + Ok(()) + }) } } -impl fmt::Display for clean::PathSegment { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.name)?; - if f.alternate() { - write!(f, "{:#}", self.args) - } else { - write!(f, "{}", self.args) - } +impl clean::PathSegment { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + f.write_str(&self.name)?; + if f.alternate() { + write!(f, "{:#}", self.args.print()) + } else { + write!(f, "{}", self.args.print()) + } + }) } } -impl fmt::Display for clean::Path { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.global { - f.write_str("::")? - } - - for (i, seg) in self.segments.iter().enumerate() { - if i > 0 { +impl clean::Path { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + if self.global { f.write_str("::")? } - if f.alternate() { - write!(f, "{:#}", seg)?; - } else { - write!(f, "{}", seg)?; + + for (i, seg) in self.segments.iter().enumerate() { + if i > 0 { + f.write_str("::")? + } + if f.alternate() { + write!(f, "{:#}", seg.print())?; + } else { + write!(f, "{}", seg.print())?; + } } - } - Ok(()) + Ok(()) + }) } } pub fn href(did: DefId) -> Option<(String, ItemType, Vec)> { let cache = cache(); - if !did.is_local() && !cache.access_levels.is_doc_reachable(did) { + if !did.is_local() && !cache.access_levels.is_public(did) { return None } - let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone()); + let depth = CURRENT_DEPTH.with(|l| l.get()); let (fqp, shortty, mut url) = match cache.paths.get(&did) { Some(&(ref fqp, shortty)) => { - (fqp, shortty, "../".repeat(loc.len())) + (fqp, shortty, "../".repeat(depth)) } None => { let &(ref fqp, shortty) = cache.external_paths.get(&did)?; (fqp, shortty, match cache.extern_locations[&did.krate] { (.., render::Remote(ref s)) => s.to_string(), - (.., render::Local) => "../".repeat(loc.len()), + (.., render::Local) => "../".repeat(depth), (.., render::Unknown) => return None, }) } @@ -432,7 +488,7 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec)> { url.push_str("/index.html"); } _ => { - url.push_str(shortty.css_class()); + url.push_str(shortty.as_str()); url.push_str("."); url.push_str(fqp.last().unwrap()); url.push_str(".html"); @@ -453,21 +509,20 @@ fn resolved_path(w: &mut fmt::Formatter<'_>, did: DefId, path: &clean::Path, } } if w.alternate() { - write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.args)?; + write!(w, "{}{:#}", &last.name, last.args.print())?; } else { let path = if use_absolute { - match href(did) { - Some((_, _, fqp)) => { - format!("{}::{}", - fqp[..fqp.len() - 1].join("::"), - HRef::new(did, fqp.last().unwrap())) - } - None => HRef::new(did, &last.name).to_string(), + if let Some((_, _, fqp)) = href(did) { + format!("{}::{}", + fqp[..fqp.len() - 1].join("::"), + anchor(did, fqp.last().unwrap())) + } else { + last.name.to_string() } } else { - HRef::new(did, &last.name).to_string() + anchor(did, &last.name).to_string() }; - write!(w, "{}{}", path, last.args)?; + write!(w, "{}{}", path, last.args.print())?; } Ok(()) } @@ -480,7 +535,7 @@ fn primitive_link(f: &mut fmt::Formatter<'_>, if !f.alternate() { match m.primitive_locations.get(&prim) { Some(&def_id) if def_id.is_local() => { - let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len()); + let len = CURRENT_DEPTH.with(|s| s.get()); let len = if len == 0 {0} else {len - 1}; write!(f, "", "../".repeat(len), @@ -493,7 +548,7 @@ fn primitive_link(f: &mut fmt::Formatter<'_>, Some((cname, s.to_string())) } (ref cname, _, render::Local) => { - let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len()); + let len = CURRENT_DEPTH.with(|s| s.get()); Some((cname, "../".repeat(len))) } (.., render::Unknown) => None, @@ -517,38 +572,30 @@ fn primitive_link(f: &mut fmt::Formatter<'_>, } /// Helper to render type parameters -fn tybounds(w: &mut fmt::Formatter<'_>, - param_names: &Option>) -> fmt::Result { - match *param_names { - Some(ref params) => { - for param in params { - write!(w, " + ")?; - fmt::Display::fmt(param, w)?; +fn tybounds(param_names: &Option>) -> impl fmt::Display + '_ { + display_fn(move |f| { + match *param_names { + Some(ref params) => { + for param in params { + write!(f, " + ")?; + fmt::Display::fmt(¶m.print(), f)?; + } + Ok(()) } - Ok(()) + None => Ok(()) } - None => Ok(()) - } + }) } -impl<'a> HRef<'a> { - pub fn new(did: DefId, text: &'a str) -> HRef<'a> { - HRef { did: did, text: text } - } -} - -impl<'a> fmt::Display for HRef<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match href(self.did) { - Some((url, shortty, fqp)) => if !f.alternate() { - write!(f, "{}", - shortty, url, shortty, fqp.join("::"), self.text) - } else { - write!(f, "{}", self.text) - }, - _ => write!(f, "{}", self.text), +pub fn anchor(did: DefId, text: &str) -> impl fmt::Display + '_ { + display_fn(move |f| { + if let Some((url, short_ty, fqp)) = href(did) { + write!(f, r#"{}"#, + short_ty, url, short_ty, fqp.join("::"), text) + } else { + write!(f, "{}", text) } - } + }) } fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> fmt::Result { @@ -562,21 +609,22 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> } // Paths like `T::Output` and `Self::Output` should be rendered with all segments. resolved_path(f, did, path, is_generic, use_absolute)?; - tybounds(f, param_names) + fmt::Display::fmt(&tybounds(param_names), f) } clean::Infer => write!(f, "_"), clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()), clean::BareFunction(ref decl) => { if f.alternate() { write!(f, "{}{:#}fn{:#}{:#}", - UnsafetySpace(decl.unsafety), - AbiSpace(decl.abi), - CommaSep(&decl.generic_params), - decl.decl) + decl.unsafety.print_with_space(), + print_abi_with_space(decl.abi), + decl.print_generic_params(), + decl.decl.print()) } else { - write!(f, "{}{}", UnsafetySpace(decl.unsafety), AbiSpace(decl.abi))?; + write!(f, "{}{}", + decl.unsafety.print_with_space(), print_abi_with_space(decl.abi))?; primitive_link(f, PrimitiveType::Fn, "fn")?; - write!(f, "{}{}", CommaSep(&decl.generic_params), decl.decl) + write!(f, "{}{}", decl.print_generic_params(), decl.decl.print()) } } clean::Tuple(ref typs) => { @@ -585,52 +633,57 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> &[ref one] => { primitive_link(f, PrimitiveType::Tuple, "(")?; // Carry `f.alternate()` into this display w/o branching manually. - fmt::Display::fmt(one, f)?; + fmt::Display::fmt(&one.print(), f)?; primitive_link(f, PrimitiveType::Tuple, ",)") } many => { primitive_link(f, PrimitiveType::Tuple, "(")?; - fmt::Display::fmt(&CommaSep(many), f)?; + for (i, item) in many.iter().enumerate() { + if i != 0 { write!(f, ", ")?; } + fmt::Display::fmt(&item.print(), f)?; + } primitive_link(f, PrimitiveType::Tuple, ")") } } } clean::Slice(ref t) => { primitive_link(f, PrimitiveType::Slice, "[")?; - fmt::Display::fmt(t, f)?; + fmt::Display::fmt(&t.print(), f)?; primitive_link(f, PrimitiveType::Slice, "]") } clean::Array(ref t, ref n) => { primitive_link(f, PrimitiveType::Array, "[")?; - fmt::Display::fmt(t, f)?; + fmt::Display::fmt(&t.print(), f)?; primitive_link(f, PrimitiveType::Array, &format!("; {}]", n)) } clean::Never => primitive_link(f, PrimitiveType::Never, "!"), - clean::CVarArgs => primitive_link(f, PrimitiveType::CVarArgs, "..."), clean::RawPointer(m, ref t) => { + let m = match m { + clean::Immutable => "const", + clean::Mutable => "mut", + }; match **t { clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => { if f.alternate() { primitive_link(f, clean::PrimitiveType::RawPointer, - &format!("*{}{:#}", RawMutableSpace(m), t)) + &format!("*{} {:#}", m, t.print())) } else { primitive_link(f, clean::PrimitiveType::RawPointer, - &format!("*{}{}", RawMutableSpace(m), t)) + &format!("*{} {}", m, t.print())) } } _ => { - primitive_link(f, clean::PrimitiveType::RawPointer, - &format!("*{}", RawMutableSpace(m)))?; - fmt::Display::fmt(t, f) + primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m))?; + fmt::Display::fmt(&t.print(), f) } } } clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => { - let lt = match *l { - Some(ref l) => format!("{} ", *l), - _ => String::new(), + let lt = match l { + Some(l) => format!("{} ", l.print()), + _ => String::new() }; - let m = MutableSpace(mutability); + let m = mutability.print_with_space(); let amp = if f.alternate() { "&".to_string() } else { @@ -642,19 +695,19 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> clean::Generic(_) => { if f.alternate() { primitive_link(f, PrimitiveType::Slice, - &format!("{}{}{}[{:#}]", amp, lt, m, **bt)) + &format!("{}{}{}[{:#}]", amp, lt, m, bt.print())) } else { primitive_link(f, PrimitiveType::Slice, - &format!("{}{}{}[{}]", amp, lt, m, **bt)) + &format!("{}{}{}[{}]", amp, lt, m, bt.print())) } } _ => { primitive_link(f, PrimitiveType::Slice, &format!("{}{}{}[", amp, lt, m))?; if f.alternate() { - write!(f, "{:#}", **bt)?; + write!(f, "{:#}", bt.print())?; } else { - write!(f, "{}", **bt)?; + write!(f, "{}", bt.print())?; } primitive_link(f, PrimitiveType::Slice, "]") } @@ -678,9 +731,9 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> } clean::ImplTrait(ref bounds) => { if f.alternate() { - write!(f, "impl {:#}", GenericBounds(bounds)) + write!(f, "impl {:#}", print_generic_bounds(bounds)) } else { - write!(f, "impl {}", GenericBounds(bounds)) + write!(f, "impl {}", print_generic_bounds(bounds)) } } clean::QPath { ref name, ref self_type, ref trait_ } => { @@ -692,15 +745,15 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> }; if f.alternate() { if should_show_cast { - write!(f, "<{:#} as {:#}>::", self_type, trait_)? + write!(f, "<{:#} as {:#}>::", self_type.print(), trait_.print())? } else { - write!(f, "{:#}::", self_type)? + write!(f, "{:#}::", self_type.print())? } } else { if should_show_cast { - write!(f, "<{} as {}>::", self_type, trait_)? + write!(f, "<{} as {}>::", self_type.print(), trait_.print())? } else { - write!(f, "{}::", self_type)? + write!(f, "{}::", self_type.print())? } }; match *trait_ { @@ -740,339 +793,404 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> } } -impl fmt::Display for clean::Type { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_type(self, f, false) +impl clean::Type { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + fmt_type(self, f, false) + }) } } -fn fmt_impl(i: &clean::Impl, - f: &mut fmt::Formatter<'_>, - link_trait: bool, - use_absolute: bool) -> fmt::Result { - if f.alternate() { - write!(f, "impl{:#} ", i.generics)?; - } else { - write!(f, "impl{} ", i.generics)?; +impl clean::Impl { + crate fn print(&self) -> impl fmt::Display + '_ { + self.print_inner(true, false) } - if let Some(ref ty) = i.trait_ { - if i.polarity == Some(clean::ImplPolarity::Negative) { - write!(f, "!")?; - } + fn print_inner( + &self, + link_trait: bool, + use_absolute: bool, + ) -> impl fmt::Display + '_ { + display_fn(move |f| { + if f.alternate() { + write!(f, "impl{:#} ", self.generics.print())?; + } else { + write!(f, "impl{} ", self.generics.print())?; + } - if link_trait { - fmt::Display::fmt(ty, f)?; - } else { - match *ty { - clean::ResolvedPath { param_names: None, ref path, is_generic: false, .. } => { - let last = path.segments.last().unwrap(); - fmt::Display::fmt(&last.name, f)?; - fmt::Display::fmt(&last.args, f)?; + if let Some(ref ty) = self.trait_ { + if self.polarity == Some(clean::ImplPolarity::Negative) { + write!(f, "!")?; } - _ => unreachable!(), - } - } - write!(f, " for ")?; - } - if let Some(ref ty) = i.blanket_impl { - fmt_type(ty, f, use_absolute)?; - } else { - fmt_type(&i.for_, f, use_absolute)?; - } + if link_trait { + fmt::Display::fmt(&ty.print(), f)?; + } else { + match ty { + clean::ResolvedPath { param_names: None, path, is_generic: false, .. } => { + let last = path.segments.last().unwrap(); + fmt::Display::fmt(&last.name, f)?; + fmt::Display::fmt(&last.args.print(), f)?; + } + _ => unreachable!(), + } + } + write!(f, " for ")?; + } - fmt::Display::fmt(&WhereClause { gens: &i.generics, indent: 0, end_newline: true }, f)?; - Ok(()) -} + if let Some(ref ty) = self.blanket_impl { + fmt_type(ty, f, use_absolute)?; + } else { + fmt_type(&self.for_, f, use_absolute)?; + } -impl fmt::Display for clean::Impl { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_impl(self, f, true, false) + fmt::Display::fmt(&WhereClause { + gens: &self.generics, + indent: 0, + end_newline: true, + }, f)?; + Ok(()) + }) } } // The difference from above is that trait is not hyperlinked. pub fn fmt_impl_for_trait_page(i: &clean::Impl, - f: &mut fmt::Formatter<'_>, - use_absolute: bool) -> fmt::Result { - fmt_impl(i, f, false, use_absolute) + f: &mut Buffer, + use_absolute: bool) { + f.from_display(i.print_inner(false, use_absolute)) } -impl fmt::Display for clean::Arguments { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for (i, input) in self.values.iter().enumerate() { - if !input.name.is_empty() { - write!(f, "{}: ", input.name)?; - } - if f.alternate() { - write!(f, "{:#}", input.type_)?; - } else { - write!(f, "{}", input.type_)?; +impl clean::Arguments { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + for (i, input) in self.values.iter().enumerate() { + if !input.name.is_empty() { + write!(f, "{}: ", input.name)?; + } + if f.alternate() { + write!(f, "{:#}", input.type_.print())?; + } else { + write!(f, "{}", input.type_.print())?; + } + if i + 1 < self.values.len() { write!(f, ", ")?; } } - if i + 1 < self.values.len() { write!(f, ", ")?; } - } - Ok(()) + Ok(()) + }) } } -impl fmt::Display for clean::FunctionRetTy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - clean::Return(clean::Tuple(ref tys)) if tys.is_empty() => Ok(()), - clean::Return(ref ty) if f.alternate() => write!(f, " -> {:#}", ty), - clean::Return(ref ty) => write!(f, " -> {}", ty), - clean::DefaultReturn => Ok(()), - } +impl clean::FunctionRetTy { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + match self { + clean::Return(clean::Tuple(tys)) if tys.is_empty() => Ok(()), + clean::Return(ty) if f.alternate() => write!(f, " -> {:#}", ty.print()), + clean::Return(ty) => write!(f, " -> {}", ty.print()), + clean::DefaultReturn => Ok(()), + } + }) } } -impl fmt::Display for clean::FnDecl { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if f.alternate() { - write!(f, "({args:#}){arrow:#}", args = self.inputs, arrow = self.output) - } else { - write!(f, "({args}){arrow}", args = self.inputs, arrow = self.output) - } +impl clean::BareFunctionDecl { + fn print_generic_params(&self) -> impl fmt::Display + '_ { + comma_sep(self.generic_params.iter().map(|g| g.print())) } } -impl<'a> fmt::Display for Function<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let &Function { decl, header_len, indent, asyncness } = self; - let amp = if f.alternate() { "&" } else { "&" }; - let mut args = String::new(); - let mut args_plain = String::new(); - for (i, input) in decl.inputs.values.iter().enumerate() { - if i == 0 { - args.push_str("
"); +impl clean::FnDecl { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + let ellipsis = if self.c_variadic { ", ..." } else { "" }; + if f.alternate() { + write!(f, + "({args:#}{ellipsis}){arrow:#}", + args = self.inputs.print(), ellipsis = ellipsis, arrow = self.output.print()) + } else { + write!(f, + "({args}{ellipsis}){arrow}", + args = self.inputs.print(), ellipsis = ellipsis, arrow = self.output.print()) } + }) + } +} + - if let Some(selfty) = input.to_self() { - match selfty { - clean::SelfValue => { - args.push_str("self"); - args_plain.push_str("self"); +impl Function<'_> { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + let &Function { decl, header_len, indent, asyncness } = self; + let amp = if f.alternate() { "&" } else { "&" }; + let mut args = String::new(); + let mut args_plain = String::new(); + for (i, input) in decl.inputs.values.iter().enumerate() { + if i == 0 { + args.push_str("
"); + } + + if let Some(selfty) = input.to_self() { + match selfty { + clean::SelfValue => { + args.push_str("self"); + args_plain.push_str("self"); + } + clean::SelfBorrowed(Some(ref lt), mtbl) => { + args.push_str( + &format!("{}{} {}self", amp, lt.print(), mtbl.print_with_space())); + args_plain.push_str( + &format!("&{} {}self", lt.print(), mtbl.print_with_space())); + } + clean::SelfBorrowed(None, mtbl) => { + args.push_str(&format!("{}{}self", amp, mtbl.print_with_space())); + args_plain.push_str(&format!("&{}self", mtbl.print_with_space())); + } + clean::SelfExplicit(ref typ) => { + if f.alternate() { + args.push_str(&format!("self: {:#}", typ.print())); + } else { + args.push_str(&format!("self: {}", typ.print())); + } + args_plain.push_str(&format!("self: {:#}", typ.print())); + } } - clean::SelfBorrowed(Some(ref lt), mtbl) => { - args.push_str(&format!("{}{} {}self", amp, *lt, MutableSpace(mtbl))); - args_plain.push_str(&format!("&{} {}self", *lt, MutableSpace(mtbl))); + } else { + if i > 0 { + args.push_str("
"); + args_plain.push_str(" "); } - clean::SelfBorrowed(None, mtbl) => { - args.push_str(&format!("{}{}self", amp, MutableSpace(mtbl))); - args_plain.push_str(&format!("&{}self", MutableSpace(mtbl))); + if !input.name.is_empty() { + args.push_str(&format!("{}: ", input.name)); + args_plain.push_str(&format!("{}: ", input.name)); } - clean::SelfExplicit(ref typ) => { - if f.alternate() { - args.push_str(&format!("self: {:#}", *typ)); - } else { - args.push_str(&format!("self: {}", *typ)); - } - args_plain.push_str(&format!("self: {:#}", *typ)); + + if f.alternate() { + args.push_str(&format!("{:#}", input.type_.print())); + } else { + args.push_str(&input.type_.print().to_string()); } + args_plain.push_str(&format!("{:#}", input.type_.print())); } - } else { - if i > 0 { - args.push_str("
"); - args_plain.push_str(" "); - } - if !input.name.is_empty() { - args.push_str(&format!("{}: ", input.name)); - args_plain.push_str(&format!("{}: ", input.name)); + if i + 1 < decl.inputs.values.len() { + args.push(','); + args_plain.push(','); } - - if f.alternate() { - args.push_str(&format!("{:#}", input.type_)); - } else { - args.push_str(&input.type_.to_string()); - } - args_plain.push_str(&format!("{:#}", input.type_)); - } - if i + 1 < decl.inputs.values.len() { - args.push(','); - args_plain.push(','); } - } - let args_plain = format!("({})", args_plain); + let mut args_plain = format!("({})", args_plain); - let output = if let hir::IsAsync::Async = asyncness { - Cow::Owned(decl.sugared_async_return_type()) - } else { - Cow::Borrowed(&decl.output) - }; + if decl.c_variadic { + args.push_str(",
..."); + args_plain.push_str(", ..."); + } - let arrow_plain = format!("{:#}", &output); - let arrow = if f.alternate() { - format!("{:#}", &output) - } else { - output.to_string() - }; + let output = if let hir::IsAsync::Async = asyncness { + Cow::Owned(decl.sugared_async_return_type()) + } else { + Cow::Borrowed(&decl.output) + }; - let declaration_len = header_len + args_plain.len() + arrow_plain.len(); - let output = if declaration_len > 80 { - let full_pad = format!("
{}", " ".repeat(indent + 4)); - let close_pad = format!("
{}", " ".repeat(indent)); - format!("({args}{close}){arrow}", - args = args.replace("
", &full_pad), - close = close_pad, - arrow = arrow) - } else { - format!("({args}){arrow}", args = args.replace("
", ""), arrow = arrow) - }; + let arrow_plain = format!("{:#}", &output.print()); + let arrow = if f.alternate() { + format!("{:#}", &output.print()) + } else { + output.print().to_string() + }; - if f.alternate() { - write!(f, "{}", output.replace("
", "\n")) - } else { - write!(f, "{}", output) - } + let declaration_len = header_len + args_plain.len() + arrow_plain.len(); + let output = if declaration_len > 80 { + let full_pad = format!("
{}", " ".repeat(indent + 4)); + let close_pad = format!("
{}", " ".repeat(indent)); + format!("({args}{close}){arrow}", + args = args.replace("
", &full_pad), + close = close_pad, + arrow = arrow) + } else { + format!("({args}){arrow}", args = args.replace("
", ""), arrow = arrow) + }; + + if f.alternate() { + write!(f, "{}", output.replace("
", "\n")) + } else { + write!(f, "{}", output) + } + }) } } -impl<'a> fmt::Display for VisSpace<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self.get() { - 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 ")?; +impl clean::Visibility { + crate fn print_with_space(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + match *self { + clean::Public => f.write_str("pub "), + clean::Inherited => Ok(()), + clean::Visibility::Crate => write!(f, "pub(crate) "), + 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(") ") } - resolved_path(f, did, path, true, false)?; - f.write_str(") ") } - } + }) } } -impl fmt::Display for UnsafetySpace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.get() { - hir::Unsafety::Unsafe => write!(f, "unsafe "), - hir::Unsafety::Normal => Ok(()) +crate trait PrintWithSpace { + fn print_with_space(&self) -> &str; +} + +impl PrintWithSpace for hir::Unsafety { + fn print_with_space(&self) -> &str { + match self { + hir::Unsafety::Unsafe => "unsafe ", + hir::Unsafety::Normal => "" } } } -impl fmt::Display for ConstnessSpace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.get() { - hir::Constness::Const => write!(f, "const "), - hir::Constness::NotConst => Ok(()) +impl PrintWithSpace for hir::Constness { + fn print_with_space(&self) -> &str { + match self { + hir::Constness::Const => "const ", + hir::Constness::NotConst => "" } } } -impl fmt::Display for AsyncSpace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 { - hir::IsAsync::Async => write!(f, "async "), - hir::IsAsync::NotAsync => Ok(()), +impl PrintWithSpace for hir::IsAsync { + fn print_with_space(&self) -> &str { + match self { + hir::IsAsync::Async => "async ", + hir::IsAsync::NotAsync => "", } } } -impl fmt::Display for clean::Import { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - clean::Import::Simple(ref name, ref src) => { - if *name == src.path.last_name() { - write!(f, "use {};", *src) - } else { - write!(f, "use {} as {};", *src, *name) +impl clean::Import { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + match *self { + clean::Import::Simple(ref name, ref src) => { + if *name == src.path.last_name() { + write!(f, "use {};", src.print()) + } else { + write!(f, "use {} as {};", src.print(), *name) + } } - } - clean::Import::Glob(ref src) => { - if src.path.segments.is_empty() { - write!(f, "use *;") - } else { - write!(f, "use {}::*;", *src) + clean::Import::Glob(ref src) => { + if src.path.segments.is_empty() { + write!(f, "use *;") + } else { + write!(f, "use {}::*;", src.print()) + } } } - } + }) } } -impl fmt::Display for clean::ImportSource { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.did { - Some(did) => resolved_path(f, did, &self.path, true, false), - _ => { - for (i, seg) in self.path.segments.iter().enumerate() { - if i > 0 { - write!(f, "::")? +impl clean::ImportSource { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + match self.did { + Some(did) => resolved_path(f, did, &self.path, true, false), + _ => { + for (i, seg) in self.path.segments.iter().enumerate() { + if i > 0 { + write!(f, "::")? + } + write!(f, "{}", seg.name)?; } - write!(f, "{}", seg.name)?; + Ok(()) } - Ok(()) } - } + }) } } -impl fmt::Display for clean::TypeBinding { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.name)?; - match self.kind { - clean::TypeBindingKind::Equality { ref ty } => { - if f.alternate() { - write!(f, " = {:#}", ty)?; - } else { - write!(f, " = {}", ty)?; - } - } - clean::TypeBindingKind::Constraint { ref bounds } => { - if !bounds.is_empty() { +impl clean::TypeBinding { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + f.write_str(&self.name)?; + match self.kind { + clean::TypeBindingKind::Equality { ref ty } => { if f.alternate() { - write!(f, ": {:#}", GenericBounds(bounds))?; + write!(f, " = {:#}", ty.print())?; } else { - write!(f, ": {}", GenericBounds(bounds))?; + write!(f, " = {}", ty.print())?; + } + } + clean::TypeBindingKind::Constraint { ref bounds } => { + if !bounds.is_empty() { + if f.alternate() { + write!(f, ": {:#}", print_generic_bounds(bounds))?; + } else { + write!(f, ": {}", print_generic_bounds(bounds))?; + } } } } - } - Ok(()) - } -} - -impl fmt::Display for MutableSpace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - MutableSpace(clean::Immutable) => Ok(()), - MutableSpace(clean::Mutable) => write!(f, "mut "), - } + Ok(()) + }) } } -impl fmt::Display for RawMutableSpace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - RawMutableSpace(clean::Immutable) => write!(f, "const "), - RawMutableSpace(clean::Mutable) => write!(f, "mut "), +impl clean::Mutability { + crate fn print_with_space(&self) -> &str { + match self { + clean::Immutable => "", + clean::Mutable => "mut ", } } } -impl fmt::Display for AbiSpace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +crate fn print_abi_with_space(abi: Abi) -> impl fmt::Display { + display_fn(move |f| { let quot = if f.alternate() { "\"" } else { """ }; - match self.0 { + match abi { Abi::Rust => Ok(()), abi => write!(f, "extern {0}{1}{0} ", quot, abi.name()), } + }) +} + +crate fn print_default_space<'a>(v: bool) -> &'a str { + if v { + "default " + } else { + "" } } -impl fmt::Display for DefaultSpace { +impl clean::GenericArg { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + match self { + clean::GenericArg::Lifetime(lt) => fmt::Display::fmt(<.print(), f), + clean::GenericArg::Type(ty) => fmt::Display::fmt(&ty.print(), f), + clean::GenericArg::Const(ct) => fmt::Display::fmt(&ct.print(), f), + } + }) + } +} + +crate fn display_fn( + f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result, +) -> impl fmt::Display { + WithFormatter(Cell::new(Some(f))) +} + +struct WithFormatter(Cell>); + +impl fmt::Display for WithFormatter + where F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.0 { - write!(f, "default ") - } else { - Ok(()) - } + (self.0.take()).unwrap()(f) } } diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index cf51a4eb5a5be..5fb9afd6c49a0 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -46,14 +46,6 @@ pub enum ItemType { } -#[derive(Copy, Eq, PartialEq, Clone)] -pub enum NameSpace { - Type, - Value, - Macro, - Keyword, -} - impl<'a> From<&'a clean::Item> for ItemType { fn from(item: &'a clean::Item) -> ItemType { let inner = match item.inner { @@ -120,7 +112,7 @@ impl From for ItemType { } impl ItemType { - pub fn css_class(&self) -> &'static str { + pub fn as_str(&self) -> &'static str { match *self { ItemType::Module => "mod", ItemType::ExternCrate => "externcrate", @@ -151,7 +143,7 @@ impl ItemType { } } - pub fn name_space(&self) -> NameSpace { + pub fn name_space(&self) -> &'static str { match *self { ItemType::Struct | ItemType::Union | @@ -163,7 +155,7 @@ impl ItemType { ItemType::AssocType | ItemType::OpaqueTy | ItemType::TraitAlias | - ItemType::ForeignType => NameSpace::Type, + ItemType::ForeignType => NAMESPACE_TYPE, ItemType::ExternCrate | ItemType::Import | @@ -175,20 +167,20 @@ impl ItemType { ItemType::StructField | ItemType::Variant | ItemType::Constant | - ItemType::AssocConst => NameSpace::Value, + ItemType::AssocConst => NAMESPACE_VALUE, ItemType::Macro | ItemType::ProcAttribute | - ItemType::ProcDerive => NameSpace::Macro, + ItemType::ProcDerive => NAMESPACE_MACRO, - ItemType::Keyword => NameSpace::Keyword, + ItemType::Keyword => NAMESPACE_KEYWORD, } } } impl fmt::Display for ItemType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.css_class().fmt(f) + write!(f, "{}", self.as_str()) } } @@ -196,20 +188,3 @@ pub const NAMESPACE_TYPE: &'static str = "t"; pub const NAMESPACE_VALUE: &'static str = "v"; pub const NAMESPACE_MACRO: &'static str = "m"; pub const NAMESPACE_KEYWORD: &'static str = "k"; - -impl NameSpace { - pub fn to_static_str(&self) -> &'static str { - match *self { - NameSpace::Type => NAMESPACE_TYPE, - NameSpace::Value => NAMESPACE_VALUE, - NameSpace::Macro => NAMESPACE_MACRO, - NameSpace::Keyword => NAMESPACE_KEYWORD, - } - } -} - -impl fmt::Display for NameSpace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.to_static_str().fmt(f) - } -} diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index ae0bd1aafa8f1..6414241727a72 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -1,9 +1,8 @@ -use std::fmt; -use std::io; use std::path::PathBuf; use crate::externalfiles::ExternalHtml; -use crate::html::render::SlashChecker; +use crate::html::render::ensure_trailing_slash; +use crate::html::format::{Buffer, Print}; #[derive(Clone)] pub struct Layout { @@ -11,6 +10,12 @@ pub struct Layout { pub favicon: String, pub external_html: ExternalHtml, pub krate: String, + /// The given user css file which allow to customize the generated + /// documentation theme. + pub css_file_extension: Option, + /// If false, the `select` element to have search filtering by crates on rendered docs + /// won't be generated. + pub generate_search_filter: bool, } pub struct Page<'a> { @@ -25,19 +30,15 @@ pub struct Page<'a> { pub static_extra_scripts: &'a [&'a str], } -pub fn render( - dst: &mut dyn io::Write, +pub fn render( layout: &Layout, page: &Page<'_>, - sidebar: &S, - t: &T, - css_file_extension: bool, + sidebar: S, + t: T, themes: &[PathBuf], - generate_search_filter: bool, -) -> io::Result<()> { +) -> String { let static_root_path = page.static_root_path.unwrap_or(page.root_path); - write!(dst, -"\ + format!("\ \ \ \ @@ -164,7 +165,7 @@ pub fn render( \ \ ", - css_extension = if css_file_extension { + css_extension = if layout.css_file_extension.is_some() { format!("", @@ -173,13 +174,13 @@ pub fn render( } else { String::new() }, - content = *t, + content = Buffer::html().to_display(t), static_root_path = static_root_path, root_path = page.root_path, css_class = page.css_class, logo = { let p = format!("{}{}", page.root_path, layout.krate); - let p = SlashChecker(&p); + let p = ensure_trailing_slash(&p); if layout.logo.is_empty() { format!("\

\ @@ -207,7 +208,7 @@ pub fn render( in_header = layout.external_html.in_header, before_content = layout.external_html.before_content, after_content = layout.external_html.after_content, - sidebar = *sidebar, + sidebar = Buffer::html().to_display(sidebar), krate = layout.krate, themes = themes.iter() .filter_map(|t| t.file_stem()) @@ -228,7 +229,7 @@ pub fn render( root_path=page.root_path, extra_script=e) }).collect::(), - filter_crates=if generate_search_filter { + filter_crates=if layout.generate_search_filter { "" @@ -238,9 +239,9 @@ pub fn render( ) } -pub fn redirect(dst: &mut dyn io::Write, url: &str) -> io::Result<()> { +pub fn redirect(url: &str) -> String { // ", - self.settings.iter() - .map(|(id, text, enabled)| { - format!("
\ - \ -
{}
\ -
", id, if *enabled { " checked" } else { "" }, text) - }) - .collect::(), - self.root_path, - self.suffix) - } + settings.iter() + .map(|(id, text, enabled)| { + format!("
\ + \ +
{}
\ +
", id, if *enabled { " checked" } else { "" }, text) + }) + .collect::(), + root_path, + suffix) } impl Context { @@ -2059,31 +1274,6 @@ impl Context { "../".repeat(self.current.len()) } - /// Recurse in the directory structure and change the "root path" to make - /// sure it always points to the top (relatively). - fn recurse(&mut self, s: String, f: F) -> T where - F: FnOnce(&mut Context) -> T, - { - if s.is_empty() { - panic!("Unexpected empty destination: {:?}", self.current); - } - let prev = self.dst.clone(); - self.dst.push(&s); - self.current.push(s); - - info!("Recursing into {}", self.dst.display()); - - let ret = f(self); - - info!("Recursed; leaving {}", self.dst.display()); - - // Go back to where we were at - self.dst = prev; - self.current.pop().unwrap(); - - ret - } - /// Main method for rendering a crate. /// /// This currently isn't parallelized, but it'd be pretty easy to add @@ -2128,7 +1318,7 @@ impl Context { extra_scripts: &[], static_extra_scripts: &[], }; - let sidebar = if let Some(ref version) = cache().crate_version { + let sidebar = if let Some(ref version) = self.cache.crate_version { format!("

Crate {}

\
\

Version {}

\ @@ -2138,18 +1328,12 @@ impl Context { } else { String::new() }; - let mut v = Vec::new(); - try_err!(layout::render(&mut v, &self.shared.layout, - &page, &sidebar, &all, - self.shared.css_file_extension.is_some(), - &self.shared.themes, - self.shared.generate_search_filter), - &final_file); - self.shared.fs.write(&final_file, &v)?; + let v = layout::render(&self.shared.layout, + &page, sidebar, |buf: &mut Buffer| all.print(buf), + &self.shared.themes); + self.shared.fs.write(&final_file, v.as_bytes())?; // Generating settings page. - let settings = Settings::new(self.shared.static_root_path.as_deref().unwrap_or("./"), - &self.shared.resource_suffix); page.title = "Rustdoc settings"; page.description = "Settings of Rustdoc"; page.root_path = "./"; @@ -2157,28 +1341,25 @@ impl Context { let mut themes = self.shared.themes.clone(); let sidebar = "

Settings

"; themes.push(PathBuf::from("settings.css")); - let layout = self.shared.layout.clone(); - let mut v = Vec::new(); - try_err!(layout::render(&mut v, &layout, - &page, &sidebar, &settings, - self.shared.css_file_extension.is_some(), - &themes, - self.shared.generate_search_filter), - &settings_file); - self.shared.fs.write(&settings_file, &v)?; + let v = layout::render( + &self.shared.layout, + &page, sidebar, settings( + self.shared.static_root_path.as_deref().unwrap_or("./"), + &self.shared.resource_suffix + ), + &themes); + self.shared.fs.write(&settings_file, v.as_bytes())?; Ok(()) } fn render_item(&self, - writer: &mut dyn io::Write, it: &clean::Item, - pushname: bool) - -> io::Result<()> { + pushname: bool) -> String { // A little unfortunate that this is done like this, but it sure // does make formatting *a lot* nicer. - CURRENT_LOCATION_KEY.with(|slot| { - *slot.borrow_mut() = self.current.clone(); + CURRENT_DEPTH.with(|slot| { + slot.set(self.current.len()); }); let mut title = if it.is_primitive() || it.is_keyword() { @@ -2194,7 +1375,7 @@ impl Context { title.push_str(it.name.as_ref().unwrap()); } title.push_str(" - Rust"); - let tyname = it.type_().css_class(); + let tyname = it.type_(); let desc = if it.is_crate() { format!("API documentation for the Rust `{}` crate.", self.shared.layout.krate) @@ -2204,7 +1385,7 @@ impl Context { }; let keywords = make_item_keywords(it); let page = layout::Page { - css_class: tyname, + css_class: tyname.as_str(), root_path: &self.root_path(), static_root_path: self.shared.static_root_path.as_deref(), title: &title, @@ -2221,24 +1402,23 @@ impl Context { } if !self.render_redirect_pages { - layout::render(writer, &self.shared.layout, &page, - &Sidebar{ cx: self, item: it }, - &Item{ cx: self, item: it }, - self.shared.css_file_extension.is_some(), - &self.shared.themes, - self.shared.generate_search_filter)?; + layout::render(&self.shared.layout, &page, + |buf: &mut _| print_sidebar(self, it, buf), + |buf: &mut _| print_item(self, it, buf), + &self.shared.themes) } else { let mut url = self.root_path(); - if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) { + if let Some(&(ref names, ty)) = self.cache.paths.get(&it.def_id) { for name in &names[..names.len() - 1] { url.push_str(name); url.push_str("/"); } url.push_str(&item_path(ty, names.last().unwrap())); - layout::redirect(writer, &url)?; + layout::redirect(&url) + } else { + String::new() } } - Ok(()) } /// Non-parallelized version of rendering an item. This will take the input @@ -2264,45 +1444,49 @@ impl Context { // modules are special because they add a namespace. We also need to // recurse into the items of the module as well. let name = item.name.as_ref().unwrap().to_string(); - let mut item = Some(item); - let scx = self.shared.clone(); - self.recurse(name, |this| { - let item = item.take().unwrap(); - - let mut buf = Vec::new(); - this.render_item(&mut buf, &item, false).unwrap(); - // buf will be empty if the module is stripped and there is no redirect for it - if !buf.is_empty() { - this.shared.ensure_dir(&this.dst)?; - let joint_dst = this.dst.join("index.html"); - scx.fs.write(&joint_dst, buf)?; - } + let scx = &self.shared; + if name.is_empty() { + panic!("Unexpected empty destination: {:?}", self.current); + } + let prev = self.dst.clone(); + self.dst.push(&name); + self.current.push(name); - let m = match item.inner { - clean::StrippedItem(box clean::ModuleItem(m)) | - clean::ModuleItem(m) => m, - _ => unreachable!() - }; + info!("Recursing into {}", self.dst.display()); - // Render sidebar-items.js used throughout this module. - if !this.render_redirect_pages { - let items = this.build_sidebar_items(&m); - let js_dst = this.dst.join("sidebar-items.js"); - let mut v = Vec::new(); - try_err!(write!(&mut v, "initSidebarItems({});", - as_json(&items)), &js_dst); - scx.fs.write(&js_dst, &v)?; - } + let buf = self.render_item(&item, false); + // buf will be empty if the module is stripped and there is no redirect for it + if !buf.is_empty() { + self.shared.ensure_dir(&self.dst)?; + let joint_dst = self.dst.join("index.html"); + scx.fs.write(&joint_dst, buf.as_bytes())?; + } - for item in m.items { - f(this, item); - } + let m = match item.inner { + clean::StrippedItem(box clean::ModuleItem(m)) | + clean::ModuleItem(m) => m, + _ => unreachable!() + }; + + // Render sidebar-items.js used throughout this module. + if !self.render_redirect_pages { + let items = self.build_sidebar_items(&m); + let js_dst = self.dst.join("sidebar-items.js"); + let v = format!("initSidebarItems({});", as_json(&items)); + scx.fs.write(&js_dst, &v)?; + } + + for item in m.items { + f(self, item); + } - Ok(()) - })?; + info!("Recursed; leaving {}", self.dst.display()); + + // Go back to where we were at + self.dst = prev; + self.current.pop().unwrap(); } else if item.name.is_some() { - let mut buf = Vec::new(); - self.render_item(&mut buf, &item, true).unwrap(); + let buf = self.render_item(&item, true); // buf will be empty if the item is stripped and there is no redirect for it if !buf.is_empty() { let name = item.name.as_ref().unwrap(); @@ -2310,7 +1494,7 @@ impl Context { let file_name = &item_path(item_type, name); self.shared.ensure_dir(&self.dst)?; let joint_dst = self.dst.join(file_name); - self.shared.fs.write(&joint_dst, buf)?; + self.shared.fs.write(&joint_dst, buf.as_bytes())?; if !self.render_redirect_pages { all.append(full_path(self, &item), &item_type); @@ -2320,18 +1504,16 @@ impl Context { // URL for the page. let redir_name = format!("{}.{}.html", name, item_type.name_space()); let redir_dst = self.dst.join(redir_name); - let mut v = Vec::new(); - try_err!(layout::redirect(&mut v, file_name), &redir_dst); - self.shared.fs.write(&redir_dst, &v)?; + let v = layout::redirect(file_name); + self.shared.fs.write(&redir_dst, v.as_bytes())?; } // If the item is a macro, redirect from the old macro URL (with !) // to the new one (without). if item_type == ItemType::Macro { let redir_name = format!("{}.{}!.html", item_type, name); let redir_dst = self.dst.join(redir_name); - let mut v = Vec::new(); - try_err!(layout::redirect(&mut v, file_name), &redir_dst); - self.shared.fs.write(&redir_dst, &v)?; + let v = layout::redirect(file_name); + self.shared.fs.write(&redir_dst, v.as_bytes())?; } } } @@ -2344,7 +1526,7 @@ impl Context { for item in &m.items { if item.is_stripped() { continue } - let short = item.type_().css_class(); + let short = item.type_(); let myname = match item.name { None => continue, Some(ref s) => s.to_string(), @@ -2363,7 +1545,7 @@ impl Context { } } -impl<'a> Item<'a> { +impl Context { /// Generates a url appropriate for an `href` attribute back to the source of /// this item. /// @@ -2373,26 +1555,25 @@ impl<'a> Item<'a> { /// If `None` is returned, then a source link couldn't be generated. This /// may happen, for example, with externally inlined items where the source /// of their crate documentation isn't known. - fn src_href(&self) -> Option { - let mut root = self.cx.root_path(); + fn src_href(&self, item: &clean::Item) -> Option { + let mut root = self.root_path(); - let cache = cache(); let mut path = String::new(); // We can safely ignore macros from other libraries - let file = match self.item.source.filename { + let file = match item.source.filename { FileName::Real(ref path) => path, _ => return None, }; - let (krate, path) = if self.item.def_id.is_local() { - if let Some(path) = self.cx.shared.local_sources.get(file) { - (&self.cx.shared.layout.krate, path) + let (krate, path) = if item.def_id.is_local() { + if let Some(path) = self.shared.local_sources.get(file) { + (&self.shared.layout.krate, path) } else { return None; } } else { - let (krate, src_root) = match *cache.extern_locations.get(&self.item.def_id.krate)? { + let (krate, src_root) = match *self.cache.extern_locations.get(&item.def_id.krate)? { (ref name, ref src, Local) => (name, src), (ref name, ref src, Remote(ref s)) => { root = s.to_string(); @@ -2401,7 +1582,7 @@ impl<'a> Item<'a> { (_, _, Unknown) => return None, }; - clean_srcpath(&src_root, file, false, |component| { + sources::clean_path(&src_root, file, false, |component| { path.push_str(&component.to_string_lossy()); path.push('/'); }); @@ -2412,10 +1593,10 @@ impl<'a> Item<'a> { (krate, &path) }; - let lines = if self.item.source.loline == self.item.source.hiline { - self.item.source.loline.to_string() + let lines = if item.source.loline == item.source.hiline { + item.source.loline.to_string() } else { - format!("{}-{}", self.item.source.loline, self.item.source.hiline) + format!("{}-{}", item.source.loline, item.source.hiline) }; Some(format!("{root}src/{krate}/{path}#{lines}", root = Escape(&root), @@ -2425,122 +1606,121 @@ impl<'a> Item<'a> { } } -fn wrap_into_docblock(w: &mut fmt::Formatter<'_>, - f: F) -> fmt::Result -where F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result { - write!(w, "
")?; - f(w)?; +fn wrap_into_docblock(w: &mut Buffer, f: F) + where F: FnOnce(&mut Buffer) +{ + write!(w, "
"); + f(w); write!(w, "
") } -impl<'a> fmt::Display for Item<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - debug_assert!(!self.item.is_stripped()); - // Write the breadcrumb trail header for the top - write!(fmt, "

")?; - if let Some(version) = self.item.stable_since() { - write!(fmt, "{0}", - version)?; - } - write!(fmt, - "\ - \ - []\ - \ - ")?; - - // Write `src` tag - // - // When this item is part of a `pub use` in a downstream crate, the - // [src] link in the downstream documentation will actually come back to - // this page, and this link will be auto-clicked. The `id` attribute is - // used to find the link to auto-click. - if self.cx.shared.include_sources && !self.item.is_primitive() { - if let Some(l) = self.src_href() { - write!(fmt, "[src]", - l, "goto source code")?; - } - } +fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer) { + debug_assert!(!item.is_stripped()); + // Write the breadcrumb trail header for the top + write!(buf, "

"); + if let Some(version) = item.stable_since() { + write!(buf, "{0}", + version); + } + write!(buf, + "\ + \ + []\ + \ + "); - write!(fmt, "")?; // out-of-band - write!(fmt, "")?; - match self.item.inner { - clean::ModuleItem(ref m) => if m.is_crate { - write!(fmt, "Crate ")?; - } else { - write!(fmt, "Module ")?; - }, - clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => write!(fmt, "Function ")?, - clean::TraitItem(..) => write!(fmt, "Trait ")?, - clean::StructItem(..) => write!(fmt, "Struct ")?, - clean::UnionItem(..) => write!(fmt, "Union ")?, - clean::EnumItem(..) => write!(fmt, "Enum ")?, - clean::TypedefItem(..) => write!(fmt, "Type Definition ")?, - clean::MacroItem(..) => write!(fmt, "Macro ")?, - clean::ProcMacroItem(ref mac) => match mac.kind { - MacroKind::Bang => write!(fmt, "Macro ")?, - MacroKind::Attr => write!(fmt, "Attribute Macro ")?, - MacroKind::Derive => write!(fmt, "Derive Macro ")?, - } - clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?, - clean::StaticItem(..) | clean::ForeignStaticItem(..) => write!(fmt, "Static ")?, - clean::ConstantItem(..) => write!(fmt, "Constant ")?, - clean::ForeignTypeItem => write!(fmt, "Foreign Type ")?, - clean::KeywordItem(..) => write!(fmt, "Keyword ")?, - clean::OpaqueTyItem(..) => write!(fmt, "Opaque Type ")?, - clean::TraitAliasItem(..) => write!(fmt, "Trait Alias ")?, - _ => { - // We don't generate pages for any other type. - unreachable!(); - } + // Write `src` tag + // + // When this item is part of a `pub use` in a downstream crate, the + // [src] link in the downstream documentation will actually come back to + // this page, and this link will be auto-clicked. The `id` attribute is + // used to find the link to auto-click. + if cx.shared.include_sources && !item.is_primitive() { + if let Some(l) = cx.src_href(item) { + write!(buf, "[src]", + l, "goto source code"); + } + } + + write!(buf, ""); // out-of-band + write!(buf, ""); + let name = match item.inner { + clean::ModuleItem(ref m) => if m.is_crate { + "Crate " + } else { + "Module " + }, + clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => "Function ", + clean::TraitItem(..) => "Trait ", + clean::StructItem(..) => "Struct ", + clean::UnionItem(..) => "Union ", + clean::EnumItem(..) => "Enum ", + clean::TypedefItem(..) => "Type Definition ", + clean::MacroItem(..) => "Macro ", + clean::ProcMacroItem(ref mac) => match mac.kind { + MacroKind::Bang => "Macro ", + MacroKind::Attr => "Attribute Macro ", + MacroKind::Derive => "Derive Macro ", + } + clean::PrimitiveItem(..) => "Primitive Type ", + clean::StaticItem(..) | clean::ForeignStaticItem(..) => "Static ", + clean::ConstantItem(..) => "Constant ", + clean::ForeignTypeItem => "Foreign Type ", + clean::KeywordItem(..) => "Keyword ", + clean::OpaqueTyItem(..) => "Opaque Type ", + clean::TraitAliasItem(..) => "Trait Alias ", + _ => { + // We don't generate pages for any other type. + unreachable!(); } - if !self.item.is_primitive() && !self.item.is_keyword() { - let cur = &self.cx.current; - let amt = if self.item.is_mod() { cur.len() - 1 } else { cur.len() }; - for (i, component) in cur.iter().enumerate().take(amt) { - write!(fmt, "{}::", - "../".repeat(cur.len() - i - 1), - component)?; - } + }; + buf.write_str(name); + if !item.is_primitive() && !item.is_keyword() { + let cur = &cx.current; + let amt = if item.is_mod() { cur.len() - 1 } else { cur.len() }; + for (i, component) in cur.iter().enumerate().take(amt) { + write!(buf, "{}::", + "../".repeat(cur.len() - i - 1), + component); } - write!(fmt, "{}", - self.item.type_(), self.item.name.as_ref().unwrap())?; - - write!(fmt, "

")?; // in-band - - match self.item.inner { - clean::ModuleItem(ref m) => - item_module(fmt, self.cx, self.item, &m.items), - clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => - item_function(fmt, self.cx, self.item, f), - clean::TraitItem(ref t) => item_trait(fmt, self.cx, self.item, t), - clean::StructItem(ref s) => item_struct(fmt, self.cx, self.item, s), - clean::UnionItem(ref s) => item_union(fmt, self.cx, self.item, s), - clean::EnumItem(ref e) => item_enum(fmt, self.cx, self.item, e), - clean::TypedefItem(ref t, _) => item_typedef(fmt, self.cx, self.item, t), - clean::MacroItem(ref m) => item_macro(fmt, self.cx, self.item, m), - clean::ProcMacroItem(ref m) => item_proc_macro(fmt, self.cx, self.item, m), - clean::PrimitiveItem(ref p) => item_primitive(fmt, self.cx, self.item, p), - clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => - item_static(fmt, self.cx, self.item, i), - clean::ConstantItem(ref c) => item_constant(fmt, self.cx, self.item, c), - clean::ForeignTypeItem => item_foreign_type(fmt, self.cx, self.item), - clean::KeywordItem(ref k) => item_keyword(fmt, self.cx, self.item, k), - clean::OpaqueTyItem(ref e, _) => item_opaque_ty(fmt, self.cx, self.item, e), - clean::TraitAliasItem(ref ta) => item_trait_alias(fmt, self.cx, self.item, ta), - _ => { - // We don't generate pages for any other type. - unreachable!(); - } + } + write!(buf, "{}", + item.type_(), item.name.as_ref().unwrap()); + + write!(buf, ""); // in-band + + match item.inner { + clean::ModuleItem(ref m) => + item_module(buf, cx, item, &m.items), + clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => + item_function(buf, cx, item, f), + clean::TraitItem(ref t) => item_trait(buf, cx, item, t), + clean::StructItem(ref s) => item_struct(buf, cx, item, s), + clean::UnionItem(ref s) => item_union(buf, cx, item, s), + clean::EnumItem(ref e) => item_enum(buf, cx, item, e), + clean::TypedefItem(ref t, _) => item_typedef(buf, cx, item, t), + clean::MacroItem(ref m) => item_macro(buf, cx, item, m), + clean::ProcMacroItem(ref m) => item_proc_macro(buf, cx, item, m), + clean::PrimitiveItem(_) => item_primitive(buf, cx, item), + clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => + item_static(buf, cx, item, i), + clean::ConstantItem(ref c) => item_constant(buf, cx, item, c), + clean::ForeignTypeItem => item_foreign_type(buf, cx, item), + clean::KeywordItem(_) => item_keyword(buf, cx, item), + clean::OpaqueTyItem(ref e, _) => item_opaque_ty(buf, cx, item, e), + clean::TraitAliasItem(ref ta) => item_trait_alias(buf, cx, item, ta), + _ => { + // We don't generate pages for any other type. + unreachable!(); } } } fn item_path(ty: ItemType, name: &str) -> String { match ty { - ItemType::Module => format!("{}index.html", SlashChecker(name)), - _ => format!("{}.{}.html", ty.css_class(), name), + ItemType::Module => format!("{}index.html", ensure_trailing_slash(name)), + _ => format!("{}.{}.html", ty, name), } } @@ -2551,63 +1731,74 @@ fn full_path(cx: &Context, item: &clean::Item) -> String { s } -fn shorter(s: Option<&str>) -> String { - match s { - Some(s) => s.lines() - .skip_while(|s| s.chars().all(|c| c.is_whitespace())) - .take_while(|line|{ - (*line).chars().any(|chr|{ - !chr.is_whitespace() - }) - }).collect::>().join("\n"), - None => String::new() - } -} - #[inline] fn plain_summary_line(s: Option<&str>) -> String { - let line = shorter(s).replace("\n", " "); - markdown::plain_summary_line_full(&line[..], false) -} - -#[inline] -fn plain_summary_line_short(s: Option<&str>) -> String { - let line = shorter(s).replace("\n", " "); - markdown::plain_summary_line_full(&line[..], true) + let s = s.unwrap_or(""); + // This essentially gets the first paragraph of text in one line. + let mut line = s.lines() + .skip_while(|line| line.chars().all(|c| c.is_whitespace())) + .take_while(|line| line.chars().any(|c| !c.is_whitespace())) + .fold(String::new(), |mut acc, line| { + acc.push_str(line); + acc.push(' '); + acc + }); + // remove final whitespace + line.pop(); + markdown::plain_summary_line(&line[..]) +} + +fn shorten(s: String) -> String { + if s.chars().count() > 60 { + let mut len = 0; + let mut ret = s.split_whitespace() + .take_while(|p| { + // + 1 for the added character after the word. + len += p.chars().count() + 1; + len < 60 + }) + .collect::>() + .join(" "); + ret.push('…'); + ret + } else { + s + } } -fn document(w: &mut fmt::Formatter<'_>, cx: &Context, item: &clean::Item) -> fmt::Result { +fn document(w: &mut Buffer, cx: &Context, item: &clean::Item) { if let Some(ref name) = item.name { info!("Documenting {}", name); } - document_stability(w, cx, item, false)?; - document_full(w, item, cx, "", false)?; - Ok(()) + document_stability(w, cx, item, false); + document_full(w, item, cx, "", false); } /// Render md_text as markdown. -fn render_markdown(w: &mut fmt::Formatter<'_>, - cx: &Context, - md_text: &str, - links: Vec<(String, String)>, - prefix: &str, - is_hidden: bool) - -> fmt::Result { +fn render_markdown( + w: &mut Buffer, + cx: &Context, + md_text: &str, + links: Vec<(String, String)>, + prefix: &str, + is_hidden: bool, +) { let mut ids = cx.id_map.borrow_mut(); write!(w, "
{}{}
", if is_hidden { " hidden" } else { "" }, prefix, - Markdown(md_text, &links, RefCell::new(&mut ids), - cx.codes, cx.edition)) + Markdown(md_text, &links, &mut ids, + cx.shared.codes, cx.shared.edition, &cx.shared.playground).to_string()) } fn document_short( - w: &mut fmt::Formatter<'_>, + w: &mut Buffer, cx: &Context, item: &clean::Item, link: AssocItemLink<'_>, - prefix: &str, is_hidden: bool -) -> fmt::Result { + prefix: &str, + is_hidden: bool, +) { if let Some(s) = item.doc_value() { let markdown = if s.contains('\n') { format!("{} [Read more]({})", @@ -2615,46 +1806,41 @@ fn document_short( } else { plain_summary_line(Some(s)) }; - render_markdown(w, cx, &markdown, item.links(), prefix, is_hidden)?; + render_markdown(w, cx, &markdown, item.links(), prefix, is_hidden); } else if !prefix.is_empty() { write!(w, "
{}
", if is_hidden { " hidden" } else { "" }, - prefix)?; + prefix); } - Ok(()) } -fn document_full(w: &mut fmt::Formatter<'_>, item: &clean::Item, - cx: &Context, prefix: &str, is_hidden: bool) -> fmt::Result { +fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context, prefix: &str, is_hidden: bool) { if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) { debug!("Doc block: =====\n{}\n=====", s); - render_markdown(w, cx, &*s, item.links(), prefix, is_hidden)?; + render_markdown(w, cx, &*s, item.links(), prefix, is_hidden); } else if !prefix.is_empty() { write!(w, "
{}
", if is_hidden { " hidden" } else { "" }, - prefix)?; + prefix); } - Ok(()) } -fn document_stability(w: &mut fmt::Formatter<'_>, cx: &Context, item: &clean::Item, - is_hidden: bool) -> fmt::Result { +fn document_stability(w: &mut Buffer, cx: &Context, item: &clean::Item, is_hidden: bool) { let stabilities = short_stability(item, cx); if !stabilities.is_empty() { - write!(w, "
", if is_hidden { " hidden" } else { "" })?; + write!(w, "
", if is_hidden { " hidden" } else { "" }); for stability in stabilities { - write!(w, "{}", stability)?; + write!(w, "{}", stability); } - write!(w, "
")?; + write!(w, "
"); } - Ok(()) } fn document_non_exhaustive_header(item: &clean::Item) -> &str { if item.is_non_exhaustive() { " (Non-exhaustive)" } else { "" } } -fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fmt::Result { +fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) { if item.is_non_exhaustive() { write!(w, "
", { if item.is_struct() { @@ -2666,31 +1852,29 @@ fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fm } else { "type" } - })?; + }); if item.is_struct() { write!(w, "Non-exhaustive structs could have additional fields added in future. \ Therefore, non-exhaustive structs cannot be constructed in external crates \ using the traditional Struct {{ .. }} syntax; cannot be \ matched against without a wildcard ..; and \ - struct update syntax will not work.")?; + struct update syntax will not work."); } else if item.is_enum() { write!(w, "Non-exhaustive enums could have additional variants added in future. \ Therefore, when matching against variants of non-exhaustive enums, an \ - extra wildcard arm must be added to account for any future variants.")?; + extra wildcard arm must be added to account for any future variants."); } else if item.is_variant() { write!(w, "Non-exhaustive enum variants could have additional fields added in future. \ Therefore, non-exhaustive enum variants cannot be constructed in external \ - crates and cannot be matched against.")?; + crates and cannot be matched against."); } else { write!(w, "This type will require a wildcard arm in any match statements or \ - constructors.")?; + constructors."); } - write!(w, "
")?; + write!(w, "
"); } - - Ok(()) } fn name_key(name: &str) -> (&str, u64, usize) { @@ -2714,9 +1898,8 @@ fn name_key(name: &str) -> (&str, u64, usize) { } } -fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context, - item: &clean::Item, items: &[clean::Item]) -> fmt::Result { - document(w, cx, item)?; +fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean::Item]) { + document(w, cx, item); let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::>(); @@ -2807,38 +1990,38 @@ fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context, curty = myty; } else if myty != curty { if curty.is_some() { - write!(w, "")?; + write!(w, ""); } curty = myty; let (short, name) = item_ty_to_strs(&myty.unwrap()); write!(w, "

\ {name}

\n", - id = cx.derive_id(short.to_owned()), name = name)?; + id = cx.derive_id(short.to_owned()), name = name); } match myitem.inner { clean::ExternCrateItem(ref name, ref src) => { - use crate::html::format::HRef; + use crate::html::format::anchor; match *src { Some(ref src) => { write!(w, "")?; + write!(w, ""); } clean::ImportItem(ref import) => { write!(w, "", - VisSpace(&myitem.visibility), *import)?; + myitem.visibility.print_with_space(), import.print()); } _ => { @@ -2868,7 +2051,7 @@ fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context, ", name = *myitem.name.as_ref().unwrap(), stab_tags = stability_tags(myitem), - docs = MarkdownSummaryLine(doc_value, &myitem.links()), + docs = MarkdownSummaryLine(doc_value, &myitem.links()).to_string(), class = myitem.type_(), add = add, stab = stab.unwrap_or_else(|| String::new()), @@ -2883,15 +2066,14 @@ fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context, }) .collect::>() .join(" "), - )?; + ); } } } if curty.is_some() { - write!(w, "
{}extern crate {} as {};", - VisSpace(&myitem.visibility), - HRef::new(myitem.def_id, src), - name)? + myitem.visibility.print_with_space(), + anchor(myitem.def_id, src), + name) } None => { write!(w, "
{}extern crate {};", - VisSpace(&myitem.visibility), - HRef::new(myitem.def_id, name))? + myitem.visibility.print_with_space(), + anchor(myitem.def_id, name)) } } - write!(w, "
{}{}
")?; + write!(w, ""); } - Ok(()) } /// Render the stability and deprecation tags that are displayed in the item's summary at the @@ -2941,7 +2123,7 @@ fn stability_tags(item: &clean::Item) -> String { /// documentation. fn short_stability(item: &clean::Item, cx: &Context) -> Vec { let mut stability = vec![]; - let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); + let error_codes = cx.shared.codes; if let Some(Deprecation { note, since }) = &item.deprecation() { // We display deprecation messages for #[deprecated] and #[rustc_deprecated] @@ -2963,8 +2145,9 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { if let Some(note) = note { let mut ids = cx.id_map.borrow_mut(); - let html = MarkdownHtml(¬e, RefCell::new(&mut ids), error_codes, cx.edition); - message.push_str(&format!(": {}", html)); + let html = MarkdownHtml( + ¬e, &mut ids, error_codes, cx.shared.edition, &cx.shared.playground); + message.push_str(&format!(": {}", html.to_string())); } stability.push(format!("
{}
", message)); } @@ -3012,7 +2195,13 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { message = format!( "
{}{}
", message, - MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes, cx.edition) + MarkdownHtml( + &unstable_reason, + &mut ids, + error_codes, + cx.shared.edition, + &cx.shared.playground, + ).to_string() ); } @@ -3034,67 +2223,64 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { stability } -fn item_constant(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, - c: &clean::Constant) -> fmt::Result { - write!(w, "
")?;
-    render_attributes(w, it, false)?;
+fn item_constant(w: &mut Buffer, cx: &Context, it: &clean::Item, c: &clean::Constant) {
+    write!(w, "
");
+    render_attributes(w, it, false);
     write!(w, "{vis}const \
                {name}: {typ}
", - vis = VisSpace(&it.visibility), + vis = it.visibility.print_with_space(), name = it.name.as_ref().unwrap(), - typ = c.type_)?; + typ = c.type_.print()); document(w, cx, it) } -fn item_static(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, - s: &clean::Static) -> fmt::Result { - write!(w, "
")?;
-    render_attributes(w, it, false)?;
+fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static) {
+    write!(w, "
");
+    render_attributes(w, it, false);
     write!(w, "{vis}static {mutability}\
                {name}: {typ}
", - vis = VisSpace(&it.visibility), - mutability = MutableSpace(s.mutability), + vis = it.visibility.print_with_space(), + mutability = s.mutability.print_with_space(), name = it.name.as_ref().unwrap(), - typ = s.type_)?; + typ = s.type_.print()); document(w, cx, it) } -fn item_function(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, - f: &clean::Function) -> fmt::Result { +fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Function) { let header_len = format!( "{}{}{}{}{:#}fn {}{:#}", - VisSpace(&it.visibility), - ConstnessSpace(f.header.constness), - UnsafetySpace(f.header.unsafety), - AsyncSpace(f.header.asyncness), - AbiSpace(f.header.abi), + it.visibility.print_with_space(), + f.header.constness.print_with_space(), + f.header.unsafety.print_with_space(), + f.header.asyncness.print_with_space(), + print_abi_with_space(f.header.abi), it.name.as_ref().unwrap(), - f.generics + f.generics.print() ).len(); - write!(w, "{}
", render_spotlight_traits(it)?)?;
-    render_attributes(w, it, false)?;
+    write!(w, "{}
", render_spotlight_traits(it));
+    render_attributes(w, it, false);
     write!(w,
            "{vis}{constness}{unsafety}{asyncness}{abi}fn \
            {name}{generics}{decl}{where_clause}
", - vis = VisSpace(&it.visibility), - constness = ConstnessSpace(f.header.constness), - unsafety = UnsafetySpace(f.header.unsafety), - asyncness = AsyncSpace(f.header.asyncness), - abi = AbiSpace(f.header.abi), + vis = it.visibility.print_with_space(), + constness = f.header.constness.print_with_space(), + unsafety = f.header.unsafety.print_with_space(), + asyncness = f.header.asyncness.print_with_space(), + abi = print_abi_with_space(f.header.abi), name = it.name.as_ref().unwrap(), - generics = f.generics, + generics = f.generics.print(), where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true }, decl = Function { decl: &f.decl, header_len, indent: 0, asyncness: f.header.asyncness, - })?; + }.print()); document(w, cx, it) } -fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter<'_>, - implementor_dups: &FxHashMap<&str, (DefId, bool)>) -> fmt::Result { +fn render_implementor(cx: &Context, implementor: &Impl, w: &mut Buffer, + implementor_dups: &FxHashMap<&str, (DefId, bool)>) { // If there's already another implementor that has the same abbridged name, use the // full path, for example in `std::iter::ExactSizeIterator` let use_absolute = match implementor.inner_impl().for_ { @@ -3106,20 +2292,18 @@ fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter<' _ => false, }; render_impl(w, cx, implementor, AssocItemLink::Anchor(None), RenderMode::Normal, - implementor.impl_item.stable_since(), false, Some(use_absolute), false, false)?; - Ok(()) + implementor.impl_item.stable_since(), false, Some(use_absolute), false, false); } -fn render_impls(cx: &Context, w: &mut fmt::Formatter<'_>, +fn render_impls(cx: &Context, w: &mut Buffer, traits: &[&&Impl], - containing_item: &clean::Item) -> fmt::Result { + containing_item: &clean::Item) { for i in traits { let did = i.trait_did().unwrap(); let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods); render_impl(w, cx, i, assoc_link, - RenderMode::Normal, containing_item.stable_since(), true, None, false, true)?; + RenderMode::Normal, containing_item.stable_since(), true, None, false, true); } - Ok(()) } fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool) -> String { @@ -3132,26 +2316,26 @@ fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool) -> String { if i > 0 { bounds.push_str(" + "); } - bounds.push_str(&(*p).to_string()); + bounds.push_str(&p.print().to_string()); } } bounds } fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl) -> Ordering { - let lhs = format!("{}", lhs.inner_impl()); - let rhs = format!("{}", rhs.inner_impl()); + let lhs = format!("{}", lhs.inner_impl().print()); + let rhs = format!("{}", rhs.inner_impl().print()); // lhs and rhs are formatted as HTML, which may be unnecessary name_key(&lhs).cmp(&name_key(&rhs)) } fn item_trait( - w: &mut fmt::Formatter<'_>, + w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, -) -> fmt::Result { +) { let bounds = bounds(&t.bounds, false); let types = t.items.iter().filter(|m| m.is_associated_type()).collect::>(); let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::>(); @@ -3160,152 +2344,148 @@ fn item_trait( // Output the trait definition wrap_into_docblock(w, |w| { - write!(w, "
")?;
-        render_attributes(w, it, true)?;
+        write!(w, "
");
+        render_attributes(w, it, true);
         write!(w, "{}{}{}trait {}{}{}",
-               VisSpace(&it.visibility),
-               UnsafetySpace(t.unsafety),
+               it.visibility.print_with_space(),
+               t.unsafety.print_with_space(),
                if t.is_auto { "auto " } else { "" },
                it.name.as_ref().unwrap(),
-               t.generics,
-               bounds)?;
+               t.generics.print(),
+               bounds);
 
         if !t.generics.where_predicates.is_empty() {
-            write!(w, "{}", WhereClause { gens: &t.generics, indent: 0, end_newline: true })?;
+            write!(w, "{}", WhereClause { gens: &t.generics, indent: 0, end_newline: true });
         } else {
-            write!(w, " ")?;
+            write!(w, " ");
         }
 
         if t.items.is_empty() {
-            write!(w, "{{ }}")?;
+            write!(w, "{{ }}");
         } else {
             // FIXME: we should be using a derived_id for the Anchors here
-            write!(w, "{{\n")?;
+            write!(w, "{{\n");
             for t in &types {
-                render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?;
-                write!(w, ";\n")?;
+                render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait);
+                write!(w, ";\n");
             }
             if !types.is_empty() && !consts.is_empty() {
-                w.write_str("\n")?;
+                w.write_str("\n");
             }
             for t in &consts {
-                render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?;
-                write!(w, ";\n")?;
+                render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait);
+                write!(w, ";\n");
             }
             if !consts.is_empty() && !required.is_empty() {
-                w.write_str("\n")?;
+                w.write_str("\n");
             }
             for (pos, m) in required.iter().enumerate() {
-                render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?;
-                write!(w, ";\n")?;
+                render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait);
+                write!(w, ";\n");
 
                 if pos < required.len() - 1 {
-                   write!(w, "
")?; + write!(w, "
"); } } if !required.is_empty() && !provided.is_empty() { - w.write_str("\n")?; + w.write_str("\n"); } for (pos, m) in provided.iter().enumerate() { - render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?; + render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait); match m.inner { clean::MethodItem(ref inner) if !inner.generics.where_predicates.is_empty() => { - write!(w, ",\n {{ ... }}\n")?; + write!(w, ",\n {{ ... }}\n"); }, _ => { - write!(w, " {{ ... }}\n")?; + write!(w, " {{ ... }}\n"); }, } if pos < provided.len() - 1 { - write!(w, "
")?; + write!(w, "
"); } } - write!(w, "}}")?; + write!(w, "}}"); } write!(w, "
") - })?; + }); // Trait documentation - document(w, cx, it)?; + document(w, cx, it); fn write_small_section_header( - w: &mut fmt::Formatter<'_>, + w: &mut Buffer, id: &str, title: &str, extra_content: &str, - ) -> fmt::Result { + ) { write!(w, "

\ {1}\

{2}", id, title, extra_content) } - fn write_loading_content(w: &mut fmt::Formatter<'_>, extra_content: &str) -> fmt::Result { + fn write_loading_content(w: &mut Buffer, extra_content: &str) { write!(w, "{}Loading content...", extra_content) } - fn trait_item(w: &mut fmt::Formatter<'_>, cx: &Context, m: &clean::Item, t: &clean::Item) - -> fmt::Result { + fn trait_item(w: &mut Buffer, cx: &Context, m: &clean::Item, t: &clean::Item) { let name = m.name.as_ref().unwrap(); let item_type = m.type_(); let id = cx.derive_id(format!("{}.{}", item_type, name)); let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

{extra}", - extra = render_spotlight_traits(m)?, + extra = render_spotlight_traits(m), id = id, - ns_id = ns_id)?; - render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl)?; - write!(w, "")?; - render_stability_since(w, m, t)?; - write!(w, "

")?; - document(w, cx, m)?; - Ok(()) + ns_id = ns_id); + render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl); + write!(w, ""); + render_stability_since(w, m, t); + write!(w, ""); + document(w, cx, m); } if !types.is_empty() { write_small_section_header(w, "associated-types", "Associated Types", - "
")?; + "
"); for t in &types { - trait_item(w, cx, *t, it)?; + trait_item(w, cx, *t, it); } - write_loading_content(w, "
")?; + write_loading_content(w, "
"); } if !consts.is_empty() { write_small_section_header(w, "associated-const", "Associated Constants", - "
")?; + "
"); for t in &consts { - trait_item(w, cx, *t, it)?; + trait_item(w, cx, *t, it); } - write_loading_content(w, "
")?; + write_loading_content(w, "
"); } // Output the documentation for each function individually if !required.is_empty() { write_small_section_header(w, "required-methods", "Required methods", - "
")?; + "
"); for m in &required { - trait_item(w, cx, *m, it)?; + trait_item(w, cx, *m, it); } - write_loading_content(w, "
")?; + write_loading_content(w, "
"); } if !provided.is_empty() { write_small_section_header(w, "provided-methods", "Provided methods", - "
")?; + "
"); for m in &provided { - trait_item(w, cx, *m, it)?; + trait_item(w, cx, *m, it); } - write_loading_content(w, "
")?; + write_loading_content(w, "
"); } // If there are methods directly on this trait object, render them here. - render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)?; - - let cache = cache(); + render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All); let mut synthetic_types = Vec::new(); - if let Some(implementors) = cache.implementors.get(&it.def_id) { + if let Some(implementors) = cx.cache.implementors.get(&it.def_id) { // The DefId is for the first Type found with that name. The bool is // if any Types with the same name but different DefId have been found. let mut implementor_dups: FxHashMap<&str, (DefId, bool)> = FxHashMap::default(); @@ -3328,7 +2508,7 @@ fn item_trait( let (local, foreign) = implementors.iter() .partition::, _>(|i| i.inner_impl().for_.def_id() - .map_or(true, |d| cache.paths.contains_key(&d))); + .map_or(true, |d| cx.cache.paths.contains_key(&d))); let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) = local.iter() @@ -3338,7 +2518,7 @@ fn item_trait( concrete.sort_by(compare_impl); if !foreign.is_empty() { - write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", "")?; + write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", ""); for implementor in foreign { let assoc_link = AssocItemLink::GotoSource( @@ -3347,44 +2527,44 @@ fn item_trait( ); render_impl(w, cx, &implementor, assoc_link, RenderMode::Normal, implementor.impl_item.stable_since(), false, - None, true, false)?; + None, true, false); } - write_loading_content(w, "")?; + write_loading_content(w, ""); } write_small_section_header(w, "implementors", "Implementors", - "
")?; + "
"); for implementor in concrete { - render_implementor(cx, implementor, w, &implementor_dups)?; + render_implementor(cx, implementor, w, &implementor_dups); } - write_loading_content(w, "
")?; + write_loading_content(w, "
"); if t.auto { write_small_section_header(w, "synthetic-implementors", "Auto implementors", - "
")?; + "
"); for implementor in synthetic { synthetic_types.extend( collect_paths_for_type(implementor.inner_impl().for_.clone()) ); - render_implementor(cx, implementor, w, &implementor_dups)?; + render_implementor(cx, implementor, w, &implementor_dups); } - write_loading_content(w, "
")?; + write_loading_content(w, "
"); } } else { // even without any implementations to write in, we still want the heading and list, so the // implementors javascript file pulled in below has somewhere to write the impls into write_small_section_header(w, "implementors", "Implementors", - "
")?; - write_loading_content(w, "
")?; + "
"); + write_loading_content(w, "
"); if t.auto { write_small_section_header(w, "synthetic-implementors", "Auto implementors", - "
")?; - write_loading_content(w, "
")?; + "
"); + write_loading_content(w, "
"); } } write!(w, r#""#, - as_json(&synthetic_types))?; + as_json(&synthetic_types)); write!(w, r#"", - name = it.name.as_ref().map(|x| &x[..]).unwrap_or(""), - ty = it.type_().css_class(), - path = relpath)?; - if parentlen == 0 { - // There is no sidebar-items.js beyond the crate root path - // FIXME maybe dynamic crate loading can be merged here - } else { - write!(fmt, "", - path = relpath)?; - } - // Closes sidebar-elems div. - write!(fmt, "
")?; - - Ok(()) + _ => "", + }, + it.name.as_ref().unwrap()); + } + + if it.is_crate() { + if let Some(ref version) = cx.cache.crate_version { + write!(buffer, + "
\ +

Version {}

\ +
", + version); + } + } + + write!(buffer, "
"); + if it.is_crate() { + write!(buffer, "

See all {}'s items

", + it.name.as_ref().expect("crates always have a name")); + } + match it.inner { + clean::StructItem(ref s) => sidebar_struct(buffer, it, s), + clean::TraitItem(ref t) => sidebar_trait(buffer, it, t), + clean::PrimitiveItem(_) => sidebar_primitive(buffer, it), + clean::UnionItem(ref u) => sidebar_union(buffer, it, u), + clean::EnumItem(ref e) => sidebar_enum(buffer, it, e), + clean::TypedefItem(_, _) => sidebar_typedef(buffer, it), + clean::ModuleItem(ref m) => sidebar_module(buffer, &m.items), + clean::ForeignTypeItem => sidebar_foreign_type(buffer, it), + _ => (), + } + + // The sidebar is designed to display sibling functions, modules and + // other miscellaneous information. since there are lots of sibling + // items (and that causes quadratic growth in large modules), + // we refactor common parts into a shared JavaScript file per module. + // still, we don't move everything into JS because we want to preserve + // as much HTML as possible in order to allow non-JS-enabled browsers + // to navigate the documentation (though slightly inefficiently). + + write!(buffer, "

"); + for (i, name) in cx.current.iter().take(parentlen).enumerate() { + if i > 0 { + write!(buffer, "::"); + } + write!(buffer, "{}", + &cx.root_path()[..(cx.current.len() - i - 1) * 3], + *name); + } + write!(buffer, "

"); + + // Sidebar refers to the enclosing module, not this module. + let relpath = if it.is_mod() { "../" } else { "" }; + write!(buffer, + "", + name = it.name.as_ref().map(|x| &x[..]).unwrap_or(""), + ty = it.type_(), + path = relpath); + if parentlen == 0 { + // There is no sidebar-items.js beyond the crate root path + // FIXME maybe dynamic crate loading can be merged here + } else { + write!(buffer, "", + path = relpath); } + // Closes sidebar-elems div. + write!(buffer, "
"); } fn get_next_url(used_links: &mut FxHashSet, url: String) -> String { @@ -4591,8 +3734,7 @@ fn get_methods( ) -> Vec { i.items.iter().filter_map(|item| { match item.name { - // Maybe check with clean::Visibility::Public as well? - Some(ref name) if !name.is_empty() && item.visibility.is_some() && item.is_method() => { + Some(ref name) if !name.is_empty() && item.is_method() => { if !for_deref || should_render_item(item, deref_mut) { Some(format!("{}", get_next_url(used_links, format!("method.{}", name)), @@ -4629,12 +3771,12 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { let mut used_links = FxHashSet::default(); { - let used_links_bor = Rc::new(RefCell::new(&mut used_links)); + let used_links_bor = &mut used_links; let mut ret = v.iter() .filter(|i| i.inner_impl().trait_.is_none()) .flat_map(move |i| get_methods(i.inner_impl(), false, - &mut used_links_bor.borrow_mut(), false)) + used_links_bor, false)) .collect::>(); // We want links' order to be reproducible so we don't use unstable sort. ret.sort(); @@ -4660,9 +3802,10 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { if let Some(impls) = inner_impl { out.push_str(""); out.push_str(&format!("Methods from {}<Target={}>", - Escape(&format!("{:#}", - impl_.inner_impl().trait_.as_ref().unwrap())), - Escape(&format!("{:#}", target)))); + Escape(&format!( + "{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print() + )), + Escape(&format!("{:#}", target.print())))); out.push_str(""); let mut ret = impls.iter() .filter(|i| i.inner_impl().trait_.is_none()) @@ -4687,9 +3830,9 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { .filter_map(|i| { let is_negative_impl = is_negative_impl(i.inner_impl()); if let Some(ref i) = i.inner_impl().trait_ { - let i_display = format!("{:#}", i); + let i_display = format!("{:#}", i.print()); let out = Escape(&i_display); - let encoded = small_url_encode(&format!("{:#}", i)); + let encoded = small_url_encode(&format!("{:#}", i.print())); let generated = format!("{}{}", encoded, if is_negative_impl { "!" } else { "" }, @@ -4742,8 +3885,7 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { out } -fn sidebar_struct(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - s: &clean::Struct) -> fmt::Result { +fn sidebar_struct(buf: &mut Buffer, it: &clean::Item, s: &clean::Struct) { let mut sidebar = String::new(); let fields = get_struct_fields_name(&s.fields); @@ -4757,20 +3899,22 @@ fn sidebar_struct(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, sidebar.push_str(&sidebar_assoc_items(it)); if !sidebar.is_empty() { - write!(fmt, "
{}
", sidebar)?; + write!(buf, "
{}
", sidebar); } - Ok(()) } fn get_id_for_impl_on_foreign_type(for_: &clean::Type, trait_: &clean::Type) -> String { - small_url_encode(&format!("impl-{:#}-for-{:#}", trait_, for_)) + small_url_encode(&format!("impl-{:#}-for-{:#}", trait_.print(), for_.print())) } fn extract_for_impl_name(item: &clean::Item) -> Option<(String, String)> { match item.inner { clean::ItemEnum::ImplItem(ref i) => { if let Some(ref trait_) = i.trait_ { - Some((format!("{:#}", i.for_), get_id_for_impl_on_foreign_type(&i.for_, trait_))) + Some(( + format!("{:#}", i.for_.print()), + get_id_for_impl_on_foreign_type(&i.for_, trait_), + )) } else { None } @@ -4783,8 +3927,7 @@ fn is_negative_impl(i: &clean::Impl) -> bool { i.polarity == Some(clean::ImplPolarity::Negative) } -fn sidebar_trait(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - t: &clean::Trait) -> fmt::Result { +fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { let mut sidebar = String::new(); let types = t.items @@ -4892,27 +4035,23 @@ fn sidebar_trait(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, sidebar.push_str(&sidebar_assoc_items(it)); - write!(fmt, "
{}
", sidebar) + write!(buf, "
{}
", sidebar) } -fn sidebar_primitive(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - _p: &clean::PrimitiveType) -> fmt::Result { +fn sidebar_primitive(buf: &mut Buffer, it: &clean::Item) { let sidebar = sidebar_assoc_items(it); if !sidebar.is_empty() { - write!(fmt, "
{}
", sidebar)?; + write!(buf, "
{}
", sidebar); } - Ok(()) } -fn sidebar_typedef(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - _t: &clean::Typedef) -> fmt::Result { +fn sidebar_typedef(buf: &mut Buffer, it: &clean::Item) { let sidebar = sidebar_assoc_items(it); if !sidebar.is_empty() { - write!(fmt, "
{}
", sidebar)?; + write!(buf, "
{}
", sidebar); } - Ok(()) } fn get_struct_fields_name(fields: &[clean::Item]) -> String { @@ -4930,8 +4069,7 @@ fn get_struct_fields_name(fields: &[clean::Item]) -> String { .collect() } -fn sidebar_union(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - u: &clean::Union) -> fmt::Result { +fn sidebar_union(buf: &mut Buffer, it: &clean::Item, u: &clean::Union) { let mut sidebar = String::new(); let fields = get_struct_fields_name(&u.fields); @@ -4943,13 +4081,11 @@ fn sidebar_union(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, sidebar.push_str(&sidebar_assoc_items(it)); if !sidebar.is_empty() { - write!(fmt, "
{}
", sidebar)?; + write!(buf, "
{}
", sidebar); } - Ok(()) } -fn sidebar_enum(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - e: &clean::Enum) -> fmt::Result { +fn sidebar_enum(buf: &mut Buffer, it: &clean::Item, e: &clean::Enum) { let mut sidebar = String::new(); let variants = e.variants.iter() @@ -4967,9 +4103,8 @@ fn sidebar_enum(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, sidebar.push_str(&sidebar_assoc_items(it)); if !sidebar.is_empty() { - write!(fmt, "
{}
", sidebar)?; + write!(buf, "
{}
", sidebar); } - Ok(()) } fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) { @@ -5003,8 +4138,7 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) { } } -fn sidebar_module(fmt: &mut fmt::Formatter<'_>, _it: &clean::Item, - items: &[clean::Item]) -> fmt::Result { +fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) { let mut sidebar = String::new(); if items.iter().any(|it| it.type_() == ItemType::ExternCrate || @@ -5031,133 +4165,72 @@ fn sidebar_module(fmt: &mut fmt::Formatter<'_>, _it: &clean::Item, } if !sidebar.is_empty() { - write!(fmt, "
    {}
", sidebar)?; + write!(buf, "
    {}
", sidebar); } - Ok(()) } -fn sidebar_foreign_type(fmt: &mut fmt::Formatter<'_>, it: &clean::Item) -> fmt::Result { +fn sidebar_foreign_type(buf: &mut Buffer, it: &clean::Item) { let sidebar = sidebar_assoc_items(it); if !sidebar.is_empty() { - write!(fmt, "
{}
", sidebar)?; - } - Ok(()) -} - -impl<'a> fmt::Display for Source<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let Source(s) = *self; - let lines = s.lines().count(); - let mut cols = 0; - let mut tmp = lines; - while tmp > 0 { - cols += 1; - tmp /= 10; - } - write!(fmt, "
")?;
-        for i in 1..=lines {
-            write!(fmt, "{0:1$}\n", i, cols)?;
-        }
-        write!(fmt, "
")?; - write!(fmt, "{}", - highlight::render_with_highlighting(s, None, None, None))?; - Ok(()) + write!(buf, "
{}
", sidebar); } } -fn item_macro(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, - t: &clean::Macro) -> fmt::Result { +fn item_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Macro) { wrap_into_docblock(w, |w| { w.write_str(&highlight::render_with_highlighting(&t.source, Some("macro"), None, None)) - })?; + }); document(w, cx, it) } -fn item_proc_macro(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, m: &clean::ProcMacro) - -> fmt::Result -{ +fn item_proc_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, m: &clean::ProcMacro) { let name = it.name.as_ref().expect("proc-macros always have names"); match m.kind { MacroKind::Bang => { - write!(w, "
")?;
-            write!(w, "{}!() {{ /* proc-macro */ }}", name)?;
-            write!(w, "
")?; + write!(w, "
");
+            write!(w, "{}!() {{ /* proc-macro */ }}", name);
+            write!(w, "
"); } MacroKind::Attr => { - write!(w, "
")?;
-            write!(w, "#[{}]", name)?;
-            write!(w, "
")?; + write!(w, "
");
+            write!(w, "#[{}]", name);
+            write!(w, "
"); } MacroKind::Derive => { - write!(w, "
")?;
-            write!(w, "#[derive({})]", name)?;
+            write!(w, "
");
+            write!(w, "#[derive({})]", name);
             if !m.helpers.is_empty() {
-                writeln!(w, "\n{{")?;
-                writeln!(w, "    // Attributes available to this derive:")?;
+                writeln!(w, "\n{{");
+                writeln!(w, "    // Attributes available to this derive:");
                 for attr in &m.helpers {
-                    writeln!(w, "    #[{}]", attr)?;
+                    writeln!(w, "    #[{}]", attr);
                 }
-                write!(w, "}}")?;
+                write!(w, "}}");
             }
-            write!(w, "
")?; + write!(w, "
"); } } document(w, cx, it) } -fn item_primitive(w: &mut fmt::Formatter<'_>, cx: &Context, - it: &clean::Item, - _p: &clean::PrimitiveType) -> fmt::Result { - document(w, cx, it)?; +fn item_primitive(w: &mut Buffer, cx: &Context, it: &clean::Item) { + document(w, cx, it); render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } -fn item_keyword(w: &mut fmt::Formatter<'_>, cx: &Context, - it: &clean::Item, - _p: &str) -> fmt::Result { +fn item_keyword(w: &mut Buffer, cx: &Context, it: &clean::Item) { document(w, cx, it) } -const BASIC_KEYWORDS: &'static str = "rust, rustlang, rust-lang"; +crate const BASIC_KEYWORDS: &'static str = "rust, rustlang, rust-lang"; fn make_item_keywords(it: &clean::Item) -> String { format!("{}, {}", BASIC_KEYWORDS, it.name.as_ref().unwrap()) } -fn get_index_search_type(item: &clean::Item) -> Option { - let (all_types, ret_types) = match item.inner { - clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types), - clean::MethodItem(ref m) => (&m.all_types, &m.ret_types), - clean::TyMethodItem(ref m) => (&m.all_types, &m.ret_types), - _ => return None, - }; - - let inputs = all_types.iter().map(|arg| { - get_index_type(&arg) - }).filter(|a| a.name.is_some()).collect(); - let output = ret_types.iter().map(|arg| { - get_index_type(&arg) - }).filter(|a| a.name.is_some()).collect::>(); - let output = if output.is_empty() { - None - } else { - Some(output) - }; - - Some(IndexItemFunctionType { inputs, output }) -} - -fn get_index_type(clean_type: &clean::Type) -> Type { - let t = Type { - name: get_index_type_name(clean_type, true).map(|s| s.to_ascii_lowercase()), - generics: get_generics(clean_type), - }; - t -} - /// Returns a list of all paths used in the type. /// This is used to help deduplicate imported impls /// for reexported types. If any of the contained @@ -5215,39 +4288,6 @@ fn collect_paths_for_type(first_ty: clean::Type) -> Vec { out } -fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option { - match *clean_type { - clean::ResolvedPath { ref path, .. } => { - let segments = &path.segments; - let path_segment = segments.into_iter().last().unwrap_or_else(|| panic!( - "get_index_type_name(clean_type: {:?}, accept_generic: {:?}) had length zero path", - clean_type, accept_generic - )); - Some(path_segment.name.clone()) - } - clean::Generic(ref s) if accept_generic => Some(s.clone()), - clean::Primitive(ref p) => Some(format!("{:?}", p)), - clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic), - // FIXME: add all from clean::Type. - _ => None - } -} - -fn get_generics(clean_type: &clean::Type) -> Option> { - clean_type.generics() - .and_then(|types| { - let r = types.iter() - .filter_map(|t| get_index_type_name(t, false)) - .map(|s| s.to_ascii_lowercase()) - .collect::>(); - if r.is_empty() { - None - } else { - Some(r) - } - }) -} - -pub fn cache() -> Arc { +crate fn cache() -> Arc { CACHE_KEY.with(|c| c.borrow().clone()) } diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs new file mode 100644 index 0000000000000..65dd119c27cb7 --- /dev/null +++ b/src/librustdoc/html/render/cache.rs @@ -0,0 +1,675 @@ +use crate::clean::{self, GetDefId, AttributesExt}; +use crate::fold::DocFolder; +use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; +use rustc::middle::privacy::AccessLevels; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use std::mem; +use std::path::{Path, PathBuf}; +use std::collections::BTreeMap; +use syntax::source_map::FileName; +use syntax::symbol::sym; +use serialize::json::{ToJson, Json, as_json}; + +use super::{ItemType, IndexItem, IndexItemFunctionType, Impl, shorten, plain_summary_line}; +use super::{Type, RenderInfo}; + +/// Indicates where an external crate can be found. +pub enum ExternalLocation { + /// Remote URL root of the external crate + Remote(String), + /// This external crate can be found in the local doc/ folder + Local, + /// The external crate could not be found. + Unknown, +} + +/// This cache is used to store information about the `clean::Crate` being +/// rendered in order to provide more useful documentation. This contains +/// information like all implementors of a trait, all traits a type implements, +/// documentation for all known traits, etc. +/// +/// This structure purposefully does not implement `Clone` because it's intended +/// to be a fairly large and expensive structure to clone. Instead this adheres +/// to `Send` so it may be stored in a `Arc` instance and shared among the various +/// rendering threads. +#[derive(Default)] +crate struct Cache { + /// Maps a type ID to all known implementations for that type. This is only + /// recognized for intra-crate `ResolvedPath` types, and is used to print + /// out extra documentation on the page of an enum/struct. + /// + /// The values of the map are a list of implementations and documentation + /// found on that implementation. + pub impls: FxHashMap>, + + /// Maintains a mapping of local crate `NodeId`s to the fully qualified name + /// and "short type description" of that node. This is used when generating + /// URLs when a type is being linked to. External paths are not located in + /// this map because the `External` type itself has all the information + /// necessary. + pub paths: FxHashMap, ItemType)>, + + /// Similar to `paths`, but only holds external paths. This is only used for + /// generating explicit hyperlinks to other crates. + pub external_paths: FxHashMap, ItemType)>, + + /// Maps local `DefId`s of exported types to fully qualified paths. + /// Unlike 'paths', this mapping ignores any renames that occur + /// due to 'use' statements. + /// + /// This map is used when writing out the special 'implementors' + /// javascript file. By using the exact path that the type + /// is declared with, we ensure that each path will be identical + /// to the path used if the corresponding type is inlined. By + /// doing this, we can detect duplicate impls on a trait page, and only display + /// the impl for the inlined type. + pub exact_paths: FxHashMap>, + + /// This map contains information about all known traits of this crate. + /// Implementations of a crate should inherit the documentation of the + /// parent trait if no extra documentation is specified, and default methods + /// should show up in documentation about trait implementations. + pub traits: FxHashMap, + + /// When rendering traits, it's often useful to be able to list all + /// implementors of the trait, and this mapping is exactly, that: a mapping + /// of trait ids to the list of known implementors of the trait + pub implementors: FxHashMap>, + + /// Cache of where external crate documentation can be found. + pub extern_locations: FxHashMap, + + /// Cache of where documentation for primitives can be found. + pub primitive_locations: FxHashMap, + + // Note that external items for which `doc(hidden)` applies to are shown as + // non-reachable while local items aren't. This is because we're reusing + // the access levels from the privacy check pass. + pub access_levels: AccessLevels, + + /// The version of the crate being documented, if given from the `--crate-version` flag. + pub crate_version: Option, + + // Private fields only used when initially crawling a crate to build a cache + + stack: Vec, + parent_stack: Vec, + parent_is_trait_impl: bool, + search_index: Vec, + stripped_mod: bool, + pub deref_trait_did: Option, + pub deref_mut_trait_did: Option, + pub owned_box_did: Option, + masked_crates: FxHashSet, + + // In rare case where a structure is defined in one module but implemented + // in another, if the implementing module is parsed before defining module, + // then the fully qualified name of the structure isn't presented in `paths` + // yet when its implementation methods are being indexed. Caches such methods + // and their parent id here and indexes them at the end of crate parsing. + orphan_impl_items: Vec<(DefId, clean::Item)>, + + // Similarly to `orphan_impl_items`, sometimes trait impls are picked up + // even though the trait itself is not exported. This can happen if a trait + // was defined in function/expression scope, since the impl will be picked + // up by `collect-trait-impls` but the trait won't be scraped out in the HIR + // crawl. In order to prevent crashes when looking for spotlight traits or + // when gathering trait documentation on a type, hold impls here while + // folding and add them to the cache later on if we find the trait. + orphan_trait_impls: Vec<(DefId, FxHashSet, Impl)>, + + /// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias, + /// we need the alias element to have an array of items. + pub(super) aliases: FxHashMap>, +} + +impl Cache { + pub fn from_krate( + renderinfo: RenderInfo, + extern_html_root_urls: &BTreeMap, + dst: &Path, + mut krate: clean::Crate, + ) -> (clean::Crate, String, Cache) { + // Crawl the crate to build various caches used for the output + let RenderInfo { + inlined: _, + external_paths, + exact_paths, + access_levels, + deref_trait_did, + deref_mut_trait_did, + owned_box_did, + } = renderinfo; + + let external_paths = external_paths.into_iter() + .map(|(k, (v, t))| (k, (v, ItemType::from(t)))) + .collect(); + + let mut cache = Cache { + impls: Default::default(), + external_paths, + exact_paths, + paths: Default::default(), + implementors: Default::default(), + stack: Vec::new(), + parent_stack: Vec::new(), + search_index: Vec::new(), + parent_is_trait_impl: false, + extern_locations: Default::default(), + primitive_locations: Default::default(), + stripped_mod: false, + access_levels, + crate_version: krate.version.take(), + orphan_impl_items: Vec::new(), + orphan_trait_impls: Vec::new(), + traits: krate.external_traits.replace(Default::default()), + deref_trait_did, + deref_mut_trait_did, + owned_box_did, + masked_crates: mem::take(&mut krate.masked_crates), + aliases: Default::default(), + }; + + // Cache where all our extern crates are located + for &(n, ref e) in &krate.externs { + let src_root = match e.src { + FileName::Real(ref p) => match p.parent() { + Some(p) => p.to_path_buf(), + None => PathBuf::new(), + }, + _ => PathBuf::new(), + }; + let extern_url = extern_html_root_urls.get(&e.name).map(|u| &**u); + cache.extern_locations.insert(n, (e.name.clone(), src_root, + extern_location(e, extern_url, &dst))); + + let did = DefId { krate: n, index: CRATE_DEF_INDEX }; + cache.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module)); + } + + // Cache where all known primitives have their documentation located. + // + // Favor linking to as local extern as possible, so iterate all crates in + // reverse topological order. + for &(_, ref e) in krate.externs.iter().rev() { + for &(def_id, prim, _) in &e.primitives { + cache.primitive_locations.insert(prim, def_id); + } + } + for &(def_id, prim, _) in &krate.primitives { + cache.primitive_locations.insert(prim, def_id); + } + + cache.stack.push(krate.name.clone()); + krate = cache.fold_crate(krate); + + for (trait_did, dids, impl_) in cache.orphan_trait_impls.drain(..) { + if cache.traits.contains_key(&trait_did) { + for did in dids { + cache.impls.entry(did).or_insert(vec![]).push(impl_.clone()); + } + } + } + + // Build our search index + let index = build_index(&krate, &mut cache); + + (krate, index, cache) + } +} + +impl DocFolder for Cache { + fn fold_item(&mut self, item: clean::Item) -> Option { + if item.def_id.is_local() { + debug!("folding {} \"{:?}\", id {:?}", item.type_(), item.name, item.def_id); + } + + // If this is a stripped module, + // we don't want it or its children in the search index. + let orig_stripped_mod = match item.inner { + clean::StrippedItem(box clean::ModuleItem(..)) => { + mem::replace(&mut self.stripped_mod, true) + } + _ => self.stripped_mod, + }; + + // If the impl is from a masked crate or references something from a + // masked crate then remove it completely. + if let clean::ImplItem(ref i) = item.inner { + if self.masked_crates.contains(&item.def_id.krate) || + i.trait_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) || + i.for_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) { + return None; + } + } + + // Propagate a trait method's documentation to all implementors of the + // trait. + if let clean::TraitItem(ref t) = item.inner { + self.traits.entry(item.def_id).or_insert_with(|| t.clone()); + } + + // Collect all the implementors of traits. + if let clean::ImplItem(ref i) = item.inner { + if let Some(did) = i.trait_.def_id() { + if i.blanket_impl.is_none() { + self.implementors.entry(did).or_default().push(Impl { + impl_item: item.clone(), + }); + } + } + } + + // Index this method for searching later on. + if let Some(ref s) = item.name { + let (parent, is_inherent_impl_item) = match item.inner { + clean::StrippedItem(..) => ((None, None), false), + clean::AssocConstItem(..) | + clean::TypedefItem(_, true) if self.parent_is_trait_impl => { + // skip associated items in trait impls + ((None, None), false) + } + clean::AssocTypeItem(..) | + clean::TyMethodItem(..) | + clean::StructFieldItem(..) | + clean::VariantItem(..) => { + ((Some(*self.parent_stack.last().unwrap()), + Some(&self.stack[..self.stack.len() - 1])), + false) + } + clean::MethodItem(..) | clean::AssocConstItem(..) => { + if self.parent_stack.is_empty() { + ((None, None), false) + } else { + let last = self.parent_stack.last().unwrap(); + let did = *last; + let path = match self.paths.get(&did) { + // The current stack not necessarily has correlation + // for where the type was defined. On the other + // hand, `paths` always has the right + // information if present. + Some(&(ref fqp, ItemType::Trait)) | + Some(&(ref fqp, ItemType::Struct)) | + Some(&(ref fqp, ItemType::Union)) | + Some(&(ref fqp, ItemType::Enum)) => + Some(&fqp[..fqp.len() - 1]), + Some(..) => Some(&*self.stack), + None => None + }; + ((Some(*last), path), true) + } + } + _ => ((None, Some(&*self.stack)), false) + }; + + match parent { + (parent, Some(path)) if is_inherent_impl_item || (!self.stripped_mod) => { + debug_assert!(!item.is_stripped()); + + // A crate has a module at its root, containing all items, + // which should not be indexed. The crate-item itself is + // inserted later on when serializing the search-index. + if item.def_id.index != CRATE_DEF_INDEX { + self.search_index.push(IndexItem { + ty: item.type_(), + name: s.to_string(), + path: path.join("::"), + desc: shorten(plain_summary_line(item.doc_value())), + parent, + parent_idx: None, + search_type: get_index_search_type(&item), + }); + } + } + (Some(parent), None) if is_inherent_impl_item => { + // We have a parent, but we don't know where they're + // defined yet. Wait for later to index this item. + self.orphan_impl_items.push((parent, item.clone())); + } + _ => {} + } + } + + // Keep track of the fully qualified path for this item. + let pushed = match item.name { + Some(ref n) if !n.is_empty() => { + self.stack.push(n.to_string()); + true + } + _ => false, + }; + + match item.inner { + clean::StructItem(..) | clean::EnumItem(..) | + clean::TypedefItem(..) | clean::TraitItem(..) | + clean::FunctionItem(..) | clean::ModuleItem(..) | + clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) | + clean::ConstantItem(..) | clean::StaticItem(..) | + clean::UnionItem(..) | clean::ForeignTypeItem | + clean::MacroItem(..) | clean::ProcMacroItem(..) + if !self.stripped_mod => { + // Re-exported items mean that the same id can show up twice + // in the rustdoc ast that we're looking at. We know, + // however, that a re-exported item doesn't show up in the + // `public_items` map, so we can skip inserting into the + // paths map if there was already an entry present and we're + // not a public item. + if !self.paths.contains_key(&item.def_id) || + self.access_levels.is_public(item.def_id) + { + self.paths.insert(item.def_id, + (self.stack.clone(), item.type_())); + } + self.add_aliases(&item); + } + // Link variants to their parent enum because pages aren't emitted + // for each variant. + clean::VariantItem(..) if !self.stripped_mod => { + let mut stack = self.stack.clone(); + stack.pop(); + self.paths.insert(item.def_id, (stack, ItemType::Enum)); + } + + clean::PrimitiveItem(..) => { + self.add_aliases(&item); + self.paths.insert(item.def_id, (self.stack.clone(), + item.type_())); + } + + _ => {} + } + + // Maintain the parent stack + let orig_parent_is_trait_impl = self.parent_is_trait_impl; + let parent_pushed = match item.inner { + clean::TraitItem(..) | clean::EnumItem(..) | clean::ForeignTypeItem | + clean::StructItem(..) | clean::UnionItem(..) => { + self.parent_stack.push(item.def_id); + self.parent_is_trait_impl = false; + true + } + clean::ImplItem(ref i) => { + self.parent_is_trait_impl = i.trait_.is_some(); + match i.for_ { + clean::ResolvedPath{ did, .. } => { + self.parent_stack.push(did); + true + } + ref t => { + let prim_did = t.primitive_type().and_then(|t| { + self.primitive_locations.get(&t).cloned() + }); + match prim_did { + Some(did) => { + self.parent_stack.push(did); + true + } + None => false, + } + } + } + } + _ => false + }; + + // Once we've recursively found all the generics, hoard off all the + // implementations elsewhere. + let ret = self.fold_item_recur(item).and_then(|item| { + if let clean::Item { inner: clean::ImplItem(_), .. } = item { + // Figure out the id of this impl. This may map to a + // primitive rather than always to a struct/enum. + // Note: matching twice to restrict the lifetime of the `i` borrow. + let mut dids = FxHashSet::default(); + if let clean::Item { inner: clean::ImplItem(ref i), .. } = item { + match i.for_ { + clean::ResolvedPath { did, .. } | + clean::BorrowedRef { + type_: box clean::ResolvedPath { did, .. }, .. + } => { + dids.insert(did); + } + ref t => { + let did = t.primitive_type().and_then(|t| { + self.primitive_locations.get(&t).cloned() + }); + + if let Some(did) = did { + dids.insert(did); + } + } + } + + if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) { + for bound in generics { + if let Some(did) = bound.def_id() { + dids.insert(did); + } + } + } + } else { + unreachable!() + }; + let impl_item = Impl { + impl_item: item, + }; + if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) { + for did in dids { + self.impls.entry(did).or_insert(vec![]).push(impl_item.clone()); + } + } else { + let trait_did = impl_item.trait_did().unwrap(); + self.orphan_trait_impls.push((trait_did, dids, impl_item)); + } + None + } else { + Some(item) + } + }); + + if pushed { self.stack.pop().unwrap(); } + if parent_pushed { self.parent_stack.pop().unwrap(); } + self.stripped_mod = orig_stripped_mod; + self.parent_is_trait_impl = orig_parent_is_trait_impl; + ret + } +} + +impl Cache { + fn add_aliases(&mut self, item: &clean::Item) { + if item.def_id.index == CRATE_DEF_INDEX { + return + } + if let Some(ref item_name) = item.name { + let path = self.paths.get(&item.def_id) + .map(|p| p.0[..p.0.len() - 1].join("::")) + .unwrap_or("std".to_owned()); + for alias in item.attrs.lists(sym::doc) + .filter(|a| a.check_name(sym::alias)) + .filter_map(|a| a.value_str() + .map(|s| s.to_string().replace("\"", ""))) + .filter(|v| !v.is_empty()) + .collect::>() + .into_iter() { + self.aliases.entry(alias) + .or_insert(Vec::with_capacity(1)) + .push(IndexItem { + ty: item.type_(), + name: item_name.to_string(), + path: path.clone(), + desc: shorten(plain_summary_line(item.doc_value())), + parent: None, + parent_idx: None, + search_type: get_index_search_type(&item), + }); + } + } + } +} + +/// Attempts to find where an external crate is located, given that we're +/// rendering in to the specified source destination. +fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Path) + -> ExternalLocation +{ + use ExternalLocation::*; + // See if there's documentation generated into the local directory + let local_location = dst.join(&e.name); + if local_location.is_dir() { + return Local; + } + + if let Some(url) = extern_url { + let mut url = url.to_string(); + if !url.ends_with("/") { + url.push('/'); + } + return Remote(url); + } + + // Failing that, see if there's an attribute specifying where to find this + // external crate + e.attrs.lists(sym::doc) + .filter(|a| a.check_name(sym::html_root_url)) + .filter_map(|a| a.value_str()) + .map(|url| { + let mut url = url.to_string(); + if !url.ends_with("/") { + url.push('/') + } + Remote(url) + }).next().unwrap_or(Unknown) // Well, at least we tried. +} + +/// Builds the search index from the collected metadata +fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { + let mut nodeid_to_pathid = FxHashMap::default(); + let mut crate_items = Vec::with_capacity(cache.search_index.len()); + let mut crate_paths = Vec::::new(); + + let Cache { ref mut search_index, + ref orphan_impl_items, + ref paths, .. } = *cache; + + // Attach all orphan items to the type's definition if the type + // has since been learned. + for &(did, ref item) in orphan_impl_items { + if let Some(&(ref fqp, _)) = paths.get(&did) { + search_index.push(IndexItem { + ty: item.type_(), + name: item.name.clone().unwrap(), + path: fqp[..fqp.len() - 1].join("::"), + desc: shorten(plain_summary_line(item.doc_value())), + parent: Some(did), + parent_idx: None, + search_type: get_index_search_type(&item), + }); + } + } + + // Reduce `NodeId` in paths into smaller sequential numbers, + // and prune the paths that do not appear in the index. + let mut lastpath = String::new(); + let mut lastpathid = 0usize; + + for item in search_index { + item.parent_idx = item.parent.map(|nodeid| { + if nodeid_to_pathid.contains_key(&nodeid) { + *nodeid_to_pathid.get(&nodeid).unwrap() + } else { + let pathid = lastpathid; + nodeid_to_pathid.insert(nodeid, pathid); + lastpathid += 1; + + let &(ref fqp, short) = paths.get(&nodeid).unwrap(); + crate_paths.push(((short as usize), fqp.last().unwrap().clone()).to_json()); + pathid + } + }); + + // Omit the parent path if it is same to that of the prior item. + if lastpath == item.path { + item.path.clear(); + } else { + lastpath = item.path.clone(); + } + crate_items.push(item.to_json()); + } + + let crate_doc = krate.module.as_ref().map(|module| { + shorten(plain_summary_line(module.doc_value())) + }).unwrap_or(String::new()); + + let mut crate_data = BTreeMap::new(); + crate_data.insert("doc".to_owned(), Json::String(crate_doc)); + crate_data.insert("i".to_owned(), Json::Array(crate_items)); + crate_data.insert("p".to_owned(), Json::Array(crate_paths)); + + // Collect the index into a string + format!("searchIndex[{}] = {};", + as_json(&krate.name), + Json::Object(crate_data)) +} + +fn get_index_search_type(item: &clean::Item) -> Option { + let (all_types, ret_types) = match item.inner { + clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types), + clean::MethodItem(ref m) => (&m.all_types, &m.ret_types), + clean::TyMethodItem(ref m) => (&m.all_types, &m.ret_types), + _ => return None, + }; + + let inputs = all_types.iter().map(|arg| { + get_index_type(&arg) + }).filter(|a| a.name.is_some()).collect(); + let output = ret_types.iter().map(|arg| { + get_index_type(&arg) + }).filter(|a| a.name.is_some()).collect::>(); + let output = if output.is_empty() { + None + } else { + Some(output) + }; + + Some(IndexItemFunctionType { inputs, output }) +} + +fn get_index_type(clean_type: &clean::Type) -> Type { + let t = Type { + name: get_index_type_name(clean_type, true).map(|s| s.to_ascii_lowercase()), + generics: get_generics(clean_type), + }; + t +} + +fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option { + match *clean_type { + clean::ResolvedPath { ref path, .. } => { + let segments = &path.segments; + let path_segment = segments.into_iter().last().unwrap_or_else(|| panic!( + "get_index_type_name(clean_type: {:?}, accept_generic: {:?}) had length zero path", + clean_type, accept_generic + )); + Some(path_segment.name.clone()) + } + clean::Generic(ref s) if accept_generic => Some(s.clone()), + clean::Primitive(ref p) => Some(format!("{:?}", p)), + clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic), + // FIXME: add all from clean::Type. + _ => None + } +} + +fn get_generics(clean_type: &clean::Type) -> Option> { + clean_type.generics() + .and_then(|types| { + let r = types.iter() + .filter_map(|t| get_index_type_name(t, false)) + .map(|s| s.to_ascii_lowercase()) + .collect::>(); + if r.is_empty() { + None + } else { + Some(r) + } + }) +} diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs new file mode 100644 index 0000000000000..d840683a7af87 --- /dev/null +++ b/src/librustdoc/html/sources.rs @@ -0,0 +1,175 @@ +use crate::clean; +use crate::docfs::PathError; +use crate::fold::DocFolder; +use crate::html::layout; +use crate::html::render::{Error, SharedContext, BASIC_KEYWORDS}; +use crate::html::highlight; +use crate::html::format::Buffer; +use std::ffi::OsStr; +use std::fs; +use std::path::{Component, Path, PathBuf}; +use syntax::source_map::FileName; + +crate fn render(dst: &Path, scx: &mut SharedContext, + krate: clean::Crate) -> Result { + info!("emitting source files"); + let dst = dst.join("src").join(&krate.name); + scx.ensure_dir(&dst)?; + let mut folder = SourceCollector { + dst, + scx, + }; + Ok(folder.fold_crate(krate)) +} + +/// Helper struct to render all source code to HTML pages +struct SourceCollector<'a> { + scx: &'a mut SharedContext, + + /// Root destination to place all HTML output into + dst: PathBuf, +} + +impl<'a> DocFolder for SourceCollector<'a> { + fn fold_item(&mut self, item: clean::Item) -> Option { + // If we're including source files, and we haven't seen this file yet, + // then we need to render it out to the filesystem. + if self.scx.include_sources + // skip all invalid or macro spans + && item.source.filename.is_real() + // skip non-local items + && item.def_id.is_local() { + + // If it turns out that we couldn't read this file, then we probably + // can't read any of the files (generating html output from json or + // something like that), so just don't include sources for the + // entire crate. The other option is maintaining this mapping on a + // per-file basis, but that's probably not worth it... + self.scx + .include_sources = match self.emit_source(&item.source.filename) { + Ok(()) => true, + Err(e) => { + println!("warning: source code was requested to be rendered, \ + but processing `{}` had an error: {}", + item.source.filename, e); + println!(" skipping rendering of source code"); + false + } + }; + } + self.fold_item_recur(item) + } +} + +impl<'a> SourceCollector<'a> { + /// Renders the given filename into its corresponding HTML source file. + fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> { + let p = match *filename { + FileName::Real(ref file) => file, + _ => return Ok(()), + }; + if self.scx.local_sources.contains_key(&**p) { + // We've already emitted this source + return Ok(()); + } + + let contents = match fs::read_to_string(&p) { + Ok(contents) => contents, + Err(e) => { + return Err(Error::new(e, &p)); + } + }; + + // Remove the utf-8 BOM if any + let contents = if contents.starts_with("\u{feff}") { + &contents[3..] + } else { + &contents[..] + }; + + // Create the intermediate directories + let mut cur = self.dst.clone(); + let mut root_path = String::from("../../"); + let mut href = String::new(); + clean_path(&self.scx.src_root, &p, false, |component| { + cur.push(component); + root_path.push_str("../"); + href.push_str(&component.to_string_lossy()); + href.push('/'); + }); + self.scx.ensure_dir(&cur)?; + let mut fname = p.file_name() + .expect("source has no filename") + .to_os_string(); + fname.push(".html"); + cur.push(&fname); + href.push_str(&fname.to_string_lossy()); + + let title = format!("{} -- source", cur.file_name().expect("failed to get file name") + .to_string_lossy()); + let desc = format!("Source to the Rust file `{}`.", filename); + let page = layout::Page { + title: &title, + css_class: "source", + root_path: &root_path, + static_root_path: self.scx.static_root_path.as_deref(), + description: &desc, + keywords: BASIC_KEYWORDS, + resource_suffix: &self.scx.resource_suffix, + extra_scripts: &[&format!("source-files{}", self.scx.resource_suffix)], + static_extra_scripts: &[&format!("source-script{}", self.scx.resource_suffix)], + }; + let v = layout::render(&self.scx.layout, + &page, "", |buf: &mut _| print_src(buf, &contents), + &self.scx.themes); + self.scx.fs.write(&cur, v.as_bytes())?; + self.scx.local_sources.insert(p.clone(), href); + Ok(()) + } +} + +/// 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 +/// argument to `f`. The very last component of the path (ie the file name) will +/// be passed to `f` if `keep_filename` is true, and ignored otherwise. +pub fn clean_path(src_root: &Path, p: &Path, keep_filename: bool, mut f: F) +where + F: FnMut(&OsStr), +{ + // make it relative, if possible + let p = p.strip_prefix(src_root).unwrap_or(p); + + let mut iter = p.components().peekable(); + + while let Some(c) = iter.next() { + if !keep_filename && iter.peek().is_none() { + break; + } + + match c { + Component::ParentDir => f("up".as_ref()), + Component::Normal(c) => f(c), + _ => continue, + } + } +} + +/// Wrapper struct to render the source code of a file. This will do things like +/// adding line numbers to the left-hand side. +fn print_src(buf: &mut Buffer, s: &str) { + let lines = s.lines().count(); + let mut cols = 0; + let mut tmp = lines; + while tmp > 0 { + cols += 1; + tmp /= 10; + } + write!(buf, "
");
+    for i in 1..=lines {
+        write!(buf, "{0:1$}\n", i, cols);
+    }
+    write!(buf, "
"); + write!(buf, "{}", + highlight::render_with_highlighting(s, None, None, None)); +} diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 82d2c11b2497b..17a940cc4c9f8 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -3,7 +3,7 @@ // Local js definitions: /* global addClass, getCurrentValue, hasClass */ -/* global isHidden onEach, removeClass, updateLocalStorage */ +/* global isHidden, onEach, removeClass, updateLocalStorage */ if (!String.prototype.startsWith) { String.prototype.startsWith = function(searchString, position) { @@ -39,6 +39,14 @@ if (!DOMTokenList.prototype.remove) { }; } +function getSearchInput() { + return document.getElementsByClassName("search-input")[0]; +} + +function getSearchElement() { + return document.getElementById("search"); +} + (function() { "use strict"; @@ -71,7 +79,7 @@ if (!DOMTokenList.prototype.remove) { "derive", "traitalias"]; - var search_input = document.getElementsByClassName("search-input")[0]; + var search_input = getSearchInput(); // On the search screen, so you remain on the last tab you opened. // @@ -105,9 +113,9 @@ if (!DOMTokenList.prototype.remove) { sidebar.appendChild(div); } } - var themePicker = document.getElementsByClassName("theme-picker"); - if (themePicker && themePicker.length > 0) { - themePicker[0].style.display = "none"; + var themePickers = document.getElementsByClassName("theme-picker"); + if (themePickers && themePickers.length > 0) { + themePickers[0].style.display = "none"; } } @@ -123,9 +131,9 @@ if (!DOMTokenList.prototype.remove) { filler.remove(); } document.getElementsByTagName("body")[0].style.marginTop = ""; - var themePicker = document.getElementsByClassName("theme-picker"); - if (themePicker && themePicker.length > 0) { - themePicker[0].style.display = null; + var themePickers = document.getElementsByClassName("theme-picker"); + if (themePickers && themePickers.length > 0) { + themePickers[0].style.display = null; } } @@ -158,7 +166,7 @@ if (!DOMTokenList.prototype.remove) { // If we're in mobile mode, we should add the sidebar in any case. hideSidebar(); var elem; - var search = document.getElementById("search"); + var search = getSearchElement(); var i, from, to, match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/); if (match) { from = parseInt(match[1], 10); @@ -250,7 +258,12 @@ if (!DOMTokenList.prototype.remove) { return String.fromCharCode(c); } + function getHelpElement() { + return document.getElementById("help"); + } + function displayHelp(display, ev, help) { + var help = help ? help : getHelpElement(); if (display === true) { if (hasClass(help, "hidden")) { ev.preventDefault(); @@ -264,9 +277,10 @@ if (!DOMTokenList.prototype.remove) { } } - function handleEscape(ev, help) { + function handleEscape(ev) { + var help = getHelpElement(); + var search = getSearchElement(); hideModal(); - var search = document.getElementById("search"); if (hasClass(help, "hidden") === false) { displayHelp(false, ev, help); } else if (hasClass(search, "hidden") === false) { @@ -284,22 +298,21 @@ if (!DOMTokenList.prototype.remove) { return; } - var help = document.getElementById("help"); if (document.activeElement.tagName === "INPUT") { switch (getVirtualKey(ev)) { case "Escape": - handleEscape(ev, help); + handleEscape(ev); break; } } else { switch (getVirtualKey(ev)) { case "Escape": - handleEscape(ev, help); + handleEscape(ev); break; case "s": case "S": - displayHelp(false, ev, help); + displayHelp(false, ev); hideModal(); ev.preventDefault(); focusSearchBar(); @@ -314,7 +327,7 @@ if (!DOMTokenList.prototype.remove) { case "?": if (ev.shiftKey) { hideModal(); - displayHelp(true, ev, help); + displayHelp(true, ev); } break; } @@ -344,7 +357,7 @@ if (!DOMTokenList.prototype.remove) { var set_fragment = function(name) { if (browserSupportsHistoryApi()) { history.replaceState(null, null, "#" + name); - window.hashchange(); + highlightSourceLines(null); } else { location.replace("#" + name); } @@ -445,6 +458,21 @@ if (!DOMTokenList.prototype.remove) { var OUTPUT_DATA = 1; var params = getQueryStringParams(); + // Set the crate filter from saved storage, if the current page has the saved crate filter. + // + // If not, ignore the crate filter -- we want to support filtering for crates on sites like + // doc.rust-lang.org where the crates may differ from page to page while on the same domain. + var savedCrate = getCurrentValue("rustdoc-saved-filter-crate"); + if (savedCrate !== null) { + onEachLazy(document.getElementById("crate-search").getElementsByTagName("option"), + function(e) { + if (e.value === savedCrate) { + document.getElementById("crate-search").value = e.value; + return true; + } + }); + } + // Populate search bar with query string search term when provided, // but only if the input bar is empty. This avoid the obnoxious issue // where you start trying to do a search, and the index loads, and @@ -532,6 +560,11 @@ if (!DOMTokenList.prototype.remove) { results.sort(function(aaa, bbb) { var a, b; + // sort by exact match with regard to the last word (mismatch goes later) + a = (aaa.word !== val); + b = (bbb.word !== val); + if (a !== b) { return a - b; } + // Sort by non levenshtein results and then levenshtein results by the distance // (less changes required to match means higher rankings) a = (aaa.lev); @@ -543,11 +576,6 @@ if (!DOMTokenList.prototype.remove) { b = (bbb.item.crate !== window.currentCrate); if (a !== b) { return a - b; } - // sort by exact match (mismatch goes later) - a = (aaa.word !== valLower); - b = (bbb.word !== valLower); - if (a !== b) { return a - b; } - // sort by item name length (longer goes later) a = aaa.word.length; b = bbb.word.length; @@ -1013,7 +1041,7 @@ if (!DOMTokenList.prototype.remove) { if (lev > MAX_LEV_DISTANCE) { continue; } else if (lev > 0) { - lev_add = 1; + lev_add = lev / 10; } } @@ -1084,10 +1112,6 @@ if (!DOMTokenList.prototype.remove) { if (index !== -1 || lev <= MAX_LEV_DISTANCE) { if (index !== -1 && paths.length < 2) { lev = 0; - } else if (searchWords[j] === val) { - // Small trick to fix when you're looking for a one letter type - // and there are other short named types. - lev = -1; } if (results[fullId] === undefined) { results[fullId] = { @@ -1270,9 +1294,7 @@ if (!DOMTokenList.prototype.remove) { } else if (e.which === 16) { // shift // Does nothing, it's just to avoid losing "focus" on the highlighted element. } else if (e.which === 27) { // escape - removeClass(actives[currentTab][0], "highlighted"); - search_input.value = ""; - defocusSearchBar(); + handleEscape(e); } else if (actives[currentTab].length > 0) { removeClass(actives[currentTab][0], "highlighted"); } @@ -1423,7 +1445,7 @@ if (!DOMTokenList.prototype.remove) { ret_others[0] + ret_in_args[0] + ret_returned[0] + "
"; addClass(main, "hidden"); - var search = document.getElementById("search"); + var search = getSearchElement(); removeClass(search, "hidden"); search.innerHTML = output; var tds = search.getElementsByTagName("td"); @@ -1633,7 +1655,7 @@ if (!DOMTokenList.prototype.remove) { if (hasClass(main, "content")) { removeClass(main, "hidden"); } - var search_c = document.getElementById("search"); + var search_c = getSearchElement(); if (hasClass(search_c, "content")) { addClass(search_c, "hidden"); } @@ -1658,9 +1680,10 @@ if (!DOMTokenList.prototype.remove) { }; search_input.onpaste = search_input.onchange; - var selectCrate = document.getElementById('crate-search'); + var selectCrate = document.getElementById("crate-search"); if (selectCrate) { selectCrate.onchange = function() { + updateLocalStorage("rustdoc-saved-filter-crate", selectCrate.value); search(undefined, true); }; } @@ -1679,7 +1702,7 @@ if (!DOMTokenList.prototype.remove) { if (hasClass(main, "content")) { removeClass(main, "hidden"); } - var search_c = document.getElementById("search"); + var search_c = getSearchElement(); if (hasClass(search_c, "content")) { addClass(search_c, "hidden"); } @@ -2448,7 +2471,7 @@ if (!DOMTokenList.prototype.remove) { var params = getQueryStringParams(); if (params && params.search) { addClass(main, "hidden"); - var search = document.getElementById("search"); + var search = getSearchElement(); removeClass(search, "hidden"); search.innerHTML = "

Loading search results...

"; } @@ -2496,7 +2519,7 @@ if (!DOMTokenList.prototype.remove) { } function addSearchOptions(crates) { - var elem = document.getElementById('crate-search'); + var elem = document.getElementById("crate-search"); if (!elem) { return; @@ -2533,10 +2556,10 @@ if (!DOMTokenList.prototype.remove) { // Sets the focus on the search bar at the top of the page function focusSearchBar() { - document.getElementsByClassName("search-input")[0].focus(); + getSearchInput().focus(); } // Removes the focus from the search bar function defocusSearchBar() { - document.getElementsByClassName("search-input")[0].blur(); + getSearchInput().blur(); } diff --git a/src/librustdoc/html/static/noscript.css b/src/librustdoc/html/static/noscript.css index 4a434d49e4dfe..832bd9ba2d628 100644 --- a/src/librustdoc/html/static/noscript.css +++ b/src/librustdoc/html/static/noscript.css @@ -5,3 +5,11 @@ .loading-content { display: none; } + +#main > h2 + div, #main > h3 + div { + display: block; +} + +#main > h2 + h3 { + display: flex; +} diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 59d10668f11ab..64c858238dbce 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -54,6 +54,21 @@ box-sizing: border-box; } +/* This part handles the "default" theme being used depending on the system one. */ +html { + content: ""; +} +@media (prefers-color-scheme: light) { + html { + content: "light"; + } +} +@media (prefers-color-scheme: dark) { + html { + content: "dark"; + } +} + /* General structure and fonts */ body { @@ -168,7 +183,7 @@ nav.sub { position: fixed; left: 0; top: 0; - height: 100vh; + bottom: 0; overflow: auto; } @@ -558,7 +573,7 @@ h4 > code, h3 > code, .invisible > code { margin-top: 0; } -nav { +nav:not(.sidebar) { border-bottom: 1px solid; padding-bottom: 10px; margin-bottom: 10px; diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index e3927350d1104..eae998ca3ecbf 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -57,7 +57,7 @@ function onEachLazy(lazyArray, func, reversed) { function usableLocalStorage() { // Check if the browser supports localStorage at all: - if (typeof(Storage) === "undefined") { + if (typeof Storage === "undefined") { return false; } // Check if we can access it; this access will fail if the browser @@ -86,7 +86,7 @@ function getCurrentValue(name) { return null; } -function switchTheme(styleElem, mainStyleElem, newTheme) { +function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) { var fullBasicCss = "rustdoc" + resourcesSuffix + ".css"; var fullNewTheme = newTheme + resourcesSuffix + ".css"; var newHref = mainStyleElem.href.replace(fullBasicCss, fullNewTheme); @@ -109,8 +109,19 @@ function switchTheme(styleElem, mainStyleElem, newTheme) { }); if (found === true) { styleElem.href = newHref; - updateLocalStorage("rustdoc-theme", newTheme); + // If this new value comes from a system setting or from the previously saved theme, no + // need to save it. + if (saveTheme === true) { + updateLocalStorage("rustdoc-theme", newTheme); + } } } -switchTheme(currentTheme, mainTheme, getCurrentValue("rustdoc-theme") || "light"); +function getSystemValue() { + var property = getComputedStyle(document.documentElement).getPropertyValue('content'); + return property.replace(/[\"\']/g, ""); +} + +switchTheme(currentTheme, mainTheme, + getCurrentValue("rustdoc-theme") || getSystemValue() || "light", + false); diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index e44ae2ad10cee..c3116dbe7a242 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -129,7 +129,7 @@ pre { pre.rust .comment { color: #8d8d8b; } pre.rust .doccomment { color: #8ca375; } -nav { +nav:not(.sidebar) { border-bottom-color: #4e4e4e; } nav.main .current { diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 4c37000dde2c5..e2bf9f9d2f23a 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -129,7 +129,7 @@ pre { pre.rust .comment { color: #8E908C; } pre.rust .doccomment { color: #4D4D4C; } -nav { +nav:not(.sidebar) { border-bottom-color: #e0e0e0; } nav.main .current { diff --git a/src/librustdoc/html/toc.rs b/src/librustdoc/html/toc.rs index 2da7aceae8bf4..0fb2f8dd7962a 100644 --- a/src/librustdoc/html/toc.rs +++ b/src/librustdoc/html/toc.rs @@ -1,10 +1,7 @@ //! Table-of-contents creation. -use std::fmt; -use std::string::String; - /// A (recursive) table of contents -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] pub struct Toc { /// The levels are strictly decreasing, i.e. /// @@ -28,7 +25,7 @@ impl Toc { } } -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] pub struct TocEntry { level: u32, sec_number: String, @@ -165,25 +162,23 @@ impl TocBuilder { } } -impl fmt::Debug for Toc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -impl fmt::Display for Toc { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "
    ")?; +impl Toc { + fn print_inner(&self, v: &mut String) { + v.push_str("
      "); for entry in &self.entries { - // recursively format this table of contents (the - // `{children}` is the key). - write!(fmt, - "\n
    • {num} {name}{children}
    • ", + // recursively format this table of contents + v.push_str(&format!("\n
    • {num} {name}", id = entry.id, - num = entry.sec_number, name = entry.name, - children = entry.children)? + num = entry.sec_number, name = entry.name)); + entry.children.print_inner(&mut *v); + v.push_str("
    • "); } - write!(fmt, "
    ") + v.push_str("
"); + } + crate fn print(&self) -> String { + let mut v = String::new(); + self.print_inner(&mut v); + v } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 799b5d923ae89..6bcb4a817d78e 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -1,7 +1,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/")] -#![feature(bind_by_move_pattern_guards)] #![feature(rustc_private)] #![feature(arbitrary_self_types)] #![feature(box_patterns)] @@ -15,9 +14,7 @@ #![feature(crate_visibility_modifier)] #![feature(const_fn)] #![feature(drain_filter)] -#![feature(inner_deref)] #![feature(never_type)] -#![feature(mem_take)] #![feature(unicode_internals)] #![recursion_limit="256"] @@ -26,6 +23,7 @@ extern crate getopts; extern crate env_logger; extern crate rustc; extern crate rustc_data_structures; +extern crate rustc_index; extern crate rustc_driver; extern crate rustc_resolve; extern crate rustc_lint; @@ -33,6 +31,7 @@ extern crate rustc_interface; extern crate rustc_metadata; extern crate rustc_target; extern crate rustc_typeck; +extern crate rustc_lexer; extern crate serialize; extern crate syntax; extern crate syntax_pos; @@ -44,10 +43,9 @@ use std::default::Default; use std::env; use std::panic; use std::process; -use std::sync::mpsc::channel; use rustc::session::{early_warn, early_error}; -use rustc::session::config::{ErrorOutputType, RustcOptGroup}; +use rustc::session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option}; #[macro_use] mod externalfiles; @@ -68,6 +66,7 @@ pub mod html { crate mod render; crate mod static_files; crate mod toc; + crate mod sources; } mod markdown; mod passes; @@ -80,7 +79,6 @@ struct Output { krate: clean::Crate, renderinfo: html::render::RenderInfo, renderopts: config::RenderOptions, - passes: Vec, } pub fn main() { @@ -90,7 +88,7 @@ pub fn main() { 32_000_000 // 32MB on other platforms }; rustc_driver::set_sigpipe_handler(); - env_logger::init(); + env_logger::init_from_env("RUSTDOC_LOG"); let res = std::thread::Builder::new().stack_size(thread_stack_size).spawn(move || { get_args().map(|args| main_args(&args)).unwrap_or(1) }).unwrap().join().unwrap_or(rustc_driver::EXIT_FAILURE); @@ -134,6 +132,7 @@ fn opts() -> Vec { stable("crate-name", |o| { o.optopt("", "crate-name", "specify the name of this crate", "NAME") }), + make_crate_type_option(), stable("L", |o| { o.optmulti("L", "library-path", "directory to add to crate search path", "DIR") @@ -242,9 +241,6 @@ fn opts() -> Vec { unstable("crate-version", |o| { o.optopt("", "crate-version", "crate version to print into documentation", "VERSION") }), - unstable("linker", |o| { - o.optopt("", "linker", "linker used for building executable test code", "PATH") - }), unstable("sort-modules-by-appearance", |o| { o.optflag("", "sort-modules-by-appearance", "sort modules by where they appear in the \ program, rather than alphabetically") @@ -358,6 +354,28 @@ fn opts() -> Vec { "show-coverage", "calculate percentage of public items with documentation") }), + unstable("enable-per-target-ignores", |o| { + o.optflag("", + "enable-per-target-ignores", + "parse ignore-foo for ignoring doctests on a per-target basis") + }), + unstable("runtool", |o| { + o.optopt("", + "runtool", + "", + "The tool to run tests with when building for a different target than host") + }), + unstable("runtool-arg", |o| { + o.optmulti("", + "runtool-arg", + "", + "One (of possibly many) arguments to pass to the runtool") + }), + unstable("test-builder", |o| { + o.optflag("", + "test-builder", + "specified the rustc-like binary to use as the test builder") + }), ] } @@ -419,14 +437,13 @@ fn main_options(options: config::Options) -> i32 { return rustc_driver::EXIT_SUCCESS; } - let Output { krate, passes, renderinfo, renderopts } = out; + let Output { krate, renderinfo, renderopts } = out; info!("going to format"); let (error_format, treat_err_as_bug, ui_testing, edition) = diag_opts; let diag = core::new_handler(error_format, None, treat_err_as_bug, ui_testing); match html::render::run( krate, renderopts, - passes.into_iter().collect(), renderinfo, &diag, edition, @@ -454,12 +471,10 @@ where R: 'static + Send, // First, parse the crate and extract all relevant information. info!("starting to run rustc"); - let (tx, rx) = channel(); - - let result = rustc_driver::report_ices_to_stderr_if_any(move || { + let result = rustc_driver::catch_fatal_errors(move || { let crate_name = options.crate_name.clone(); let crate_version = options.crate_version.clone(); - let (mut krate, renderinfo, renderopts, passes) = core::run_core(options); + let (mut krate, renderinfo, renderopts) = core::run_core(options); info!("finished with rustc"); @@ -469,16 +484,15 @@ where R: 'static + Send, krate.version = crate_version; - tx.send(f(Output { - krate: krate, - renderinfo: renderinfo, + f(Output { + krate, + renderinfo, renderopts, - passes: passes - })).unwrap(); + }) }); match result { - Ok(()) => rx.recv().unwrap(), + Ok(output) => output, Err(_) => panic::resume_unwind(Box::new(errors::FatalErrorMarker)), } } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 50a647f244db5..8431271e62d56 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -1,7 +1,6 @@ use std::fs::File; use std::io::prelude::*; use std::path::PathBuf; -use std::cell::RefCell; use errors; use testing; @@ -44,7 +43,7 @@ pub fn render( edition: Edition ) -> i32 { let mut output = options.output; - output.push(input.file_stem().unwrap()); + output.push(input.file_name().unwrap()); output.set_extension("html"); let mut css = String::new(); @@ -60,9 +59,10 @@ pub fn render( }; let playground_url = options.markdown_playground_url .or(options.playground_url); - if let Some(playground) = playground_url { - markdown::PLAYGROUND.with(|s| { *s.borrow_mut() = Some((None, playground)); }); - } + let playground = playground_url.map(|url| markdown::Playground { + crate_name: None, + url, + }); let mut out = match File::create(&output) { Err(e) => { @@ -82,9 +82,9 @@ pub fn render( let mut ids = IdMap::new(); let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); let text = if !options.markdown_no_toc { - MarkdownWithToc(text, RefCell::new(&mut ids), error_codes, edition).to_string() + MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).to_string() } else { - Markdown(text, &[], RefCell::new(&mut ids), error_codes, edition).to_string() + Markdown(text, &[], &mut ids, error_codes, edition, &playground).to_string() }; let err = write!( @@ -142,18 +142,16 @@ pub fn test(mut options: Options, diag: &errors::Handler) -> i32 { let mut opts = TestOptions::default(); opts.no_crate_inject = true; opts.display_warnings = options.display_warnings; - let mut collector = Collector::new(options.input.display().to_string(), options.cfgs, - options.libs, options.codegen_options, options.externs, - true, opts, options.maybe_sysroot, None, - Some(options.input), - options.linker, options.edition, options.persist_doctests); + let mut collector = Collector::new(options.input.display().to_string(), options.clone(), + true, opts, None, Some(options.input), + options.enable_per_target_ignores); collector.set_position(DUMMY_SP); let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); - find_testable_code(&input_str, &mut collector, codes); + find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores); options.test_args.insert(0, "rustdoctest".to_string()); testing::test_main(&options.test_args, collector.tests, - testing::Options::new().display_output(options.display_warnings)); + Some(testing::Options::new().display_output(options.display_warnings))); 0 } diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 4ee09f7096b61..dc1ca8d7668ae 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -142,7 +142,8 @@ impl fold::DocFolder for CoverageCalculator { } clean::ImplItem(ref impl_) => { if let Some(ref tr) = impl_.trait_ { - debug!("impl {:#} for {:#} in {}", tr, impl_.for_, i.source.filename); + debug!("impl {:#} for {:#} in {}", + tr.print(), impl_.for_.print(), i.source.filename); // don't count trait impls, the missing-docs lint doesn't so we shouldn't // either @@ -151,11 +152,11 @@ impl fold::DocFolder for CoverageCalculator { // inherent impls *can* be documented, and those docs show up, but in most // cases it doesn't make sense, as all methods on a type are in one single // impl block - debug!("impl {:#} in {}", impl_.for_, i.source.filename); + debug!("impl {:#} in {}", impl_.for_.print(), i.source.filename); } } _ => { - debug!("counting {} {:?} in {}", i.type_(), i.name, i.source.filename); + debug!("counting {:?} {:?} in {}", i.type_(), i.name, i.source.filename); self.items.entry(i.source.filename.clone()) .or_default() .count_item(has_docs); diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 357e17d2d1bc4..32044e48b6f99 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -32,27 +32,39 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { dox[code_block.code].to_owned(), ); - let has_errors = { - let mut has_errors = false; + let validation_status = { + let mut has_syntax_errors = false; + let mut only_whitespace = true; + // even if there is a syntax error, we need to run the lexer over the whole file let mut lexer = Lexer::new(&sess, source_file, None); loop { match lexer.next_token().kind { token::Eof => break, - token::Unknown(..) => has_errors = true, - _ => (), + token::Whitespace => (), + token::Unknown(..) => has_syntax_errors = true, + _ => only_whitespace = false, } } - has_errors + + if has_syntax_errors { + Some(CodeBlockInvalid::SyntaxError) + } else if only_whitespace { + Some(CodeBlockInvalid::Empty) + } else { + None + } }; - if has_errors { + if let Some(code_block_invalid) = validation_status { let mut diag = if let Some(sp) = super::source_span_for_markdown_range(self.cx, &dox, &code_block.range, &item.attrs) { - let mut diag = self - .cx - .sess() - .struct_span_warn(sp, "could not parse code block as Rust code"); + let warning_message = match code_block_invalid { + CodeBlockInvalid::SyntaxError => "could not parse code block as Rust code", + CodeBlockInvalid::Empty => "Rust code block is empty", + }; + + let mut diag = self.cx.sess().struct_span_warn(sp, warning_message); if code_block.syntax.is_none() && code_block.is_fenced { let sp = sp.from_inner(InnerSpan::new(0, 3)); @@ -69,7 +81,7 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { // We couldn't calculate the span of the markdown block that had the error, so our // diagnostics are going to be a bit lacking. let mut diag = self.cx.sess().struct_span_warn( - super::span_of_attrs(&item.attrs), + super::span_of_attrs(&item.attrs).unwrap_or(item.source.span()), "doc comment contains an invalid Rust code block", ); @@ -96,3 +108,8 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> { self.fold_item_recur(item) } } + +enum CodeBlockInvalid { + SyntaxError, + Empty, +} diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs index 144ff226c4283..31288345ce57b 100644 --- a/src/librustdoc/passes/collapse_docs.rs +++ b/src/librustdoc/passes/collapse_docs.rs @@ -30,7 +30,9 @@ impl DocFragment { } pub fn collapse_docs(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { - Collapser.fold_crate(krate) + let mut krate = Collapser.fold_crate(krate); + krate.collapsed = true; + krate } struct Collapser; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 84cfdd790b733..9186ed514202f 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -4,6 +4,7 @@ use rustc::hir::def_id::DefId; use rustc::hir; use rustc::lint as lint; use rustc::ty; +use rustc_resolve::ParentScope; use syntax; use syntax::ast::{self, Ident}; use syntax::ext::base::SyntaxExtensionKind; @@ -61,15 +62,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { { let cx = self.cx; - // In case we're in a module, try to resolve the relative - // path. - if let Some(id) = parent_id.or(self.mod_ids.last().cloned()) { - // FIXME: `with_scope` requires the `NodeId` of a module. - let node_id = cx.tcx.hir().hir_to_node_id(id); + // In case we're in a module, try to resolve the relative path. + if let Some(module_id) = parent_id.or(self.mod_ids.last().cloned()) { + let module_id = cx.tcx.hir().hir_to_node_id(module_id); let result = cx.enter_resolver(|resolver| { - resolver.with_scope(node_id, |resolver| { - resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns == ValueNS) - }) + resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id) }); let result = match result { Ok((_, Res::Err)) => Err(()), @@ -85,6 +82,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { Res::Def(DefKind::AssocTy, _) => false, Res::Def(DefKind::Variant, _) => return handle_variant(cx, res), // Not a trait item; just return what we found. + Res::PrimTy(..) => return Ok((res, Some(path_str.to_owned()))), _ => return Ok((res, None)) }; @@ -133,11 +131,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .ok_or(()); } - // FIXME: `with_scope` requires the `NodeId` of a module. - let node_id = cx.tcx.hir().hir_to_node_id(id); - let (_, ty_res) = cx.enter_resolver(|resolver| resolver.with_scope(node_id, |resolver| { - resolver.resolve_str_path_error(DUMMY_SP, &path, false) - }))?; + let (_, ty_res) = cx.enter_resolver(|resolver| { + resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) + })?; if let Res::Err = ty_res { return Err(()); } @@ -159,7 +155,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }; Ok((ty_res, Some(format!("{}.{}", out, item_name)))) } else { - match cx.tcx.type_of(did).sty { + match cx.tcx.type_of(did).kind { ty::Adt(def, _) => { if let Some(item) = if def.is_enum() { def.all_fields().find(|item| item.ident.name == item_name) @@ -241,7 +237,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { }); if parent_node.is_some() { - debug!("got parent node for {} {:?}, id {:?}", item.type_(), item.name, item.def_id); + debug!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.def_id); } let current_item = match item.inner { @@ -436,7 +432,7 @@ fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option { let path = ast::Path::from_ident(Ident::from_str(path_str)); cx.enter_resolver(|resolver| { if let Ok((Some(ext), res)) = resolver.resolve_macro_path( - &path, None, &resolver.dummy_parent_scope(), false, false + &path, None, &ParentScope::module(resolver.graph_root), false, false ) { if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind { return Some(res.map_id(|_| panic!("unexpected id"))); @@ -469,7 +465,7 @@ fn resolution_failure( } }; let attrs = &item.attrs; - let sp = span_of_attrs(attrs); + let sp = span_of_attrs(attrs).unwrap_or(item.source.span()); let mut diag = cx.tcx.struct_span_lint_hir( lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, @@ -521,7 +517,7 @@ fn ambiguity_error( } }; let attrs = &item.attrs; - let sp = span_of_attrs(attrs); + let sp = span_of_attrs(attrs).unwrap_or(item.source.span()); let mut msg = format!("`{}` is ", path_str); @@ -683,6 +679,7 @@ fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option { "f32" => tcx.lang_items().f32_impl(), "f64" => tcx.lang_items().f64_impl(), "str" => tcx.lang_items().str_impl(), + "bool" => tcx.lang_items().bool_impl(), "char" => tcx.lang_items().char_impl(), _ => None, } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index cd488b9df78d2..28c64d0b9638e 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -4,7 +4,7 @@ use crate::fold::DocFolder; use super::Pass; use rustc::util::nodemap::FxHashSet; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{LOCAL_CRATE, DefId}; use syntax::symbol::sym; pub const COLLECT_TRAIT_IMPLS: Pass = Pass { @@ -53,6 +53,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { lang_items.f64_impl(), lang_items.f32_runtime_impl(), lang_items.f64_runtime_impl(), + lang_items.bool_impl(), lang_items.char_impl(), lang_items.str_impl(), lang_items.slice_impl(), @@ -116,7 +117,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { // `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations` // doesn't work with it anyway, so pull them from the HIR map instead - for &trait_did in cx.all_traits.iter() { + for &trait_did in cx.tcx.all_traits(LOCAL_CRATE).iter() { for &impl_node in cx.tcx.hir().trait_impls(trait_did) { let impl_did = cx.tcx.hir().local_def_id(impl_node); inline::build_impl(cx, impl_did, None, &mut new_items); diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index ca40d6d02f86d..f6560218a78c8 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -10,7 +10,7 @@ use syntax_pos::{DUMMY_SP, InnerSpan, Span}; use std::ops::Range; use crate::clean::{self, GetDefId, Item}; -use crate::core::{DocContext, DocAccessLevels}; +use crate::core::DocContext; use crate::fold::{DocFolder, StripItem}; use crate::html::markdown::{find_testable_code, ErrorCodes, LangString}; @@ -57,8 +57,9 @@ pub struct Pass { pub description: &'static str, } + /// The full list of passes. -pub const PASSES: &'static [Pass] = &[ +pub const PASSES: &[Pass] = &[ CHECK_PRIVATE_ITEMS_DOC_TESTS, STRIP_HIDDEN, UNINDENT_COMMENTS, @@ -73,43 +74,43 @@ pub const PASSES: &'static [Pass] = &[ ]; /// The list of passes run by default. -pub const DEFAULT_PASSES: &[&str] = &[ - "collect-trait-impls", - "collapse-docs", - "unindent-comments", - "check-private-items-doc-tests", - "strip-hidden", - "strip-private", - "collect-intra-doc-links", - "check-code-block-syntax", - "propagate-doc-cfg", +pub const DEFAULT_PASSES: &[Pass] = &[ + COLLECT_TRAIT_IMPLS, + COLLAPSE_DOCS, + UNINDENT_COMMENTS, + CHECK_PRIVATE_ITEMS_DOC_TESTS, + STRIP_HIDDEN, + STRIP_PRIVATE, + COLLECT_INTRA_DOC_LINKS, + CHECK_CODE_BLOCK_SYNTAX, + PROPAGATE_DOC_CFG, ]; /// The list of default passes run with `--document-private-items` is passed to rustdoc. -pub const DEFAULT_PRIVATE_PASSES: &[&str] = &[ - "collect-trait-impls", - "collapse-docs", - "unindent-comments", - "check-private-items-doc-tests", - "strip-priv-imports", - "collect-intra-doc-links", - "check-code-block-syntax", - "propagate-doc-cfg", +pub const DEFAULT_PRIVATE_PASSES: &[Pass] = &[ + COLLECT_TRAIT_IMPLS, + COLLAPSE_DOCS, + UNINDENT_COMMENTS, + CHECK_PRIVATE_ITEMS_DOC_TESTS, + STRIP_PRIV_IMPORTS, + COLLECT_INTRA_DOC_LINKS, + CHECK_CODE_BLOCK_SYNTAX, + PROPAGATE_DOC_CFG, ]; /// The list of default passes run when `--doc-coverage` is passed to rustdoc. -pub const DEFAULT_COVERAGE_PASSES: &'static [&'static str] = &[ - "collect-trait-impls", - "strip-hidden", - "strip-private", - "calculate-doc-coverage", +pub const DEFAULT_COVERAGE_PASSES: &[Pass] = &[ + COLLECT_TRAIT_IMPLS, + STRIP_HIDDEN, + STRIP_PRIVATE, + CALCULATE_DOC_COVERAGE, ]; /// The list of default passes run when `--doc-coverage --document-private-items` is passed to /// rustdoc. -pub const PRIVATE_COVERAGE_PASSES: &'static [&'static str] = &[ - "collect-trait-impls", - "calculate-doc-coverage", +pub const PRIVATE_COVERAGE_PASSES: &[Pass] = &[ + COLLECT_TRAIT_IMPLS, + CALCULATE_DOC_COVERAGE, ]; /// A shorthand way to refer to which set of passes to use, based on the presence of @@ -124,7 +125,7 @@ pub enum DefaultPassOption { } /// Returns the given default set of passes. -pub fn defaults(default_set: DefaultPassOption) -> &'static [&'static str] { +pub fn defaults(default_set: DefaultPassOption) -> &'static [Pass] { match default_set { DefaultPassOption::Default => DEFAULT_PASSES, DefaultPassOption::Private => DEFAULT_PRIVATE_PASSES, @@ -152,7 +153,7 @@ impl<'a> DocFolder for Stripper<'a> { // We need to recurse into stripped modules to strip things // like impl methods but when doing so we must not add any // items to the `retained` set. - debug!("Stripper: recursing into stripped {} {:?}", i.type_(), i.name); + debug!("Stripper: recursing into stripped {:?} {:?}", i.type_(), i.name); let old = mem::replace(&mut self.update_retained, false); let ret = self.fold_item_recur(i); self.update_retained = old; @@ -177,20 +178,20 @@ impl<'a> DocFolder for Stripper<'a> { | clean::ForeignTypeItem => { if i.def_id.is_local() { if !self.access_levels.is_exported(i.def_id) { - debug!("Stripper: stripping {} {:?}", i.type_(), i.name); + debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name); return None; } } } clean::StructFieldItem(..) => { - if i.visibility != Some(clean::Public) { + if i.visibility != clean::Public { return StripItem(i).strip(); } } clean::ModuleItem(..) => { - if i.def_id.is_local() && i.visibility != Some(clean::Public) { + if i.def_id.is_local() && i.visibility != clean::Public { debug!("Stripper: stripping module {:?}", i.name); let old = mem::replace(&mut self.update_retained, false); let ret = StripItem(self.fold_item_recur(i).unwrap()).strip(); @@ -298,7 +299,7 @@ impl DocFolder for ImportStripper { fn fold_item(&mut self, i: Item) -> Option { match i.inner { clean::ExternCrateItem(..) | clean::ImportItem(..) - if i.visibility != Some(clean::Public) => + if i.visibility != clean::Public => { None } @@ -335,10 +336,10 @@ pub fn look_for_tests<'tcx>( found_tests: 0, }; - find_testable_code(&dox, &mut tests, ErrorCodes::No); + find_testable_code(&dox, &mut tests, ErrorCodes::No, false); if check_missing_code == true && tests.found_tests == 0 { - let sp = span_of_attrs(&item.attrs).substitute_dummy(item.source.span()); + let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span()); let mut diag = cx.tcx.struct_span_lint_hir( lint::builtin::MISSING_DOC_CODE_EXAMPLES, hir_id, @@ -347,24 +348,27 @@ pub fn look_for_tests<'tcx>( diag.emit(); } else if check_missing_code == false && tests.found_tests > 0 && - !cx.renderinfo.borrow().access_levels.is_doc_reachable(item.def_id) { + !cx.renderinfo.borrow().access_levels.is_public(item.def_id) { let mut diag = cx.tcx.struct_span_lint_hir( lint::builtin::PRIVATE_DOC_TESTS, hir_id, - span_of_attrs(&item.attrs), + span_of_attrs(&item.attrs).unwrap_or(item.source.span()), "Documentation test in private item"); diag.emit(); } } /// Returns a span encompassing all the given attributes. -crate fn span_of_attrs(attrs: &clean::Attributes) -> Span { +crate fn span_of_attrs(attrs: &clean::Attributes) -> Option { if attrs.doc_strings.is_empty() { - return DUMMY_SP; + return None; } let start = attrs.doc_strings[0].span(); + if start == DUMMY_SP { + return None; + } let end = attrs.doc_strings.last().expect("No doc strings provided").span(); - start.to(end) + Some(start.to(end)) } /// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code. @@ -390,7 +394,7 @@ crate fn source_span_for_markdown_range( let snippet = cx .sess() .source_map() - .span_to_snippet(span_of_attrs(attrs)) + .span_to_snippet(span_of_attrs(attrs)?) .ok()?; let starting_line = markdown[..md_range.start].matches('\n').count(); @@ -440,10 +444,8 @@ crate fn source_span_for_markdown_range( } } - let sp = span_of_attrs(attrs).from_inner(InnerSpan::new( + Some(span_of_attrs(attrs)?.from_inner(InnerSpan::new( md_range.start + start_bytes, md_range.end + start_bytes + end_bytes, - )); - - Some(sp) + ))) } diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index da8977544f64b..0159e03f6f299 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -39,7 +39,7 @@ struct Stripper<'a> { impl<'a> DocFolder for Stripper<'a> { fn fold_item(&mut self, i: Item) -> Option { if i.attrs.lists(sym::doc).has_word(sym::hidden) { - debug!("strip_hidden: stripping {} {:?}", i.type_(), i.name); + debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name); // use a dedicated hidden item for given item type if any match i.inner { clean::StructFieldItem(..) | clean::ModuleItem(..) => { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 462e21b8f6b55..05e6f36c95869 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -1,11 +1,9 @@ use rustc_data_structures::sync::Lrc; use rustc_interface::interface; +use rustc_target::spec::TargetTriple; use rustc::hir; use rustc::hir::intravisit; -use rustc::hir::def_id::LOCAL_CRATE; use rustc::session::{self, config, DiagnosticOutput}; -use rustc::session::config::{OutputType, OutputTypes, Externs, CodegenOptions}; -use rustc::session::search_paths::SearchPath; use rustc::util::common::ErrorReported; use syntax::ast; use syntax::with_globals; @@ -13,13 +11,11 @@ use syntax::source_map::SourceMap; use syntax::edition::Edition; use syntax::feature_gate::UnstableFeatures; use std::env; -use std::io::prelude::*; -use std::io; -use std::panic::{self, AssertUnwindSafe}; +use std::io::{self, Write}; +use std::panic; use std::path::PathBuf; -use std::process::{self, Command}; +use std::process::{self, Command, Stdio}; use std::str; -use std::sync::{Arc, Mutex}; use syntax::symbol::sym; use syntax_pos::{BytePos, DUMMY_SP, Pos, Span, FileName}; use tempfile::Builder as TempFileBuilder; @@ -27,7 +23,7 @@ use testing; use crate::clean::Attributes; use crate::config::Options; -use crate::html::markdown::{self, ErrorCodes, LangString}; +use crate::html::markdown::{self, ErrorCodes, LangString, Ignore}; #[derive(Clone, Default)] pub struct TestOptions { @@ -43,10 +39,16 @@ pub struct TestOptions { pub fn run(options: Options) -> i32 { let input = config::Input::File(options.input.clone()); + let crate_types = if options.proc_macro_crate { + vec![config::CrateType::ProcMacro] + } else { + vec![config::CrateType::Dylib] + }; + let sessopts = config::Options { maybe_sysroot: options.maybe_sysroot.clone(), search_paths: options.libs.clone(), - crate_types: vec![config::CrateType::Dylib], + crate_types, cg: options.codegen_options.clone(), externs: options.externs.clone(), unstable_features: UnstableFeatures::from_environment(), @@ -56,12 +58,16 @@ pub fn run(options: Options) -> i32 { ..config::basic_debugging_options() }, edition: options.edition, + target_triple: options.target.clone(), ..config::Options::default() }; + let mut cfgs = options.cfgs.clone(); + cfgs.push("rustdoc".to_owned()); + cfgs.push("doctest".to_owned()); let config = interface::Config { opts: sessopts, - crate_cfg: config::parse_cfgspecs(options.cfgs.clone()), + crate_cfg: config::parse_cfgspecs(cfgs), input, input_path: None, output_file: None, @@ -81,20 +87,15 @@ pub fn run(options: Options) -> i32 { let mut opts = scrape_test_config(lower_to_hir.peek().0.borrow().krate()); opts.display_warnings |= options.display_warnings; + let enable_per_target_ignores = options.enable_per_target_ignores; let mut collector = Collector::new( compiler.crate_name()?.peek().to_string(), - options.cfgs, - options.libs, - options.codegen_options, - options.externs, + options, false, opts, - options.maybe_sysroot, Some(compiler.source_map().clone()), None, - options.linker, - options.edition, - options.persist_doctests, + enable_per_target_ignores, ); let mut global_ctxt = compiler.global_ctxt()?.take(); @@ -120,7 +121,7 @@ pub fn run(options: Options) -> i32 { testing::test_main( &test_args, tests, - testing::Options::new().display_output(display_warnings) + Some(testing::Options::new().display_output(display_warnings)) ); 0 @@ -183,20 +184,17 @@ fn run_test( cratename: &str, filename: &FileName, line: usize, - cfgs: Vec, - libs: Vec, - cg: CodegenOptions, - externs: Externs, + options: Options, should_panic: bool, no_run: bool, as_test_harness: bool, + runtool: Option, + runtool_args: Vec, + target: TargetTriple, compile_fail: bool, mut error_codes: Vec, opts: &TestOptions, - maybe_sysroot: Option, - linker: Option, edition: Edition, - persist_doctests: Option, ) -> Result<(), TestFailure> { let (test, line_offset) = match panic::catch_unwind(|| { make_test(test, Some(cratename), as_test_harness, opts, edition) @@ -217,61 +215,6 @@ fn run_test( _ => PathBuf::from(r"doctest.rs"), }; - let input = config::Input::Str { - name: FileName::DocTest(path, line as isize - line_offset as isize), - input: test, - }; - let outputs = OutputTypes::new(&[(OutputType::Exe, None)]); - - let sessopts = config::Options { - maybe_sysroot, - search_paths: libs, - crate_types: vec![config::CrateType::Executable], - output_types: outputs, - externs, - cg: config::CodegenOptions { - linker, - ..cg - }, - test: as_test_harness, - unstable_features: UnstableFeatures::from_environment(), - debugging_opts: config::DebuggingOptions { - ..config::basic_debugging_options() - }, - edition, - ..config::Options::default() - }; - - // 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>>); - impl Write for Sink { - fn write(&mut self, data: &[u8]) -> io::Result { - Write::write(&mut *self.0.lock().unwrap(), data) - } - fn flush(&mut self) -> io::Result<()> { Ok(()) } - } - struct Bomb(Arc>>, Option>); - impl Drop for Bomb { - fn drop(&mut self) { - let mut old = self.1.take().unwrap(); - let _ = old.write_all(&self.0.lock().unwrap()); - io::set_panic(Some(old)); - } - } - let data = Arc::new(Mutex::new(Vec::new())); - - let old = io::set_panic(Some(box Sink(data.clone()))); - let _bomb = Bomb(data.clone(), Some(old.unwrap_or(box io::stdout()))); - enum DirState { Temp(tempfile::TempDir), Perm(PathBuf), @@ -286,7 +229,7 @@ fn run_test( } } - let outdir = if let Some(mut path) = persist_doctests { + let outdir = if let Some(mut path) = options.persist_doctests { path.push(format!("{}_{}", filename .to_string() @@ -308,41 +251,67 @@ fn run_test( }; let output_file = outdir.path().join("rust_out"); - let config = interface::Config { - opts: sessopts, - crate_cfg: config::parse_cfgspecs(cfgs), - input, - input_path: None, - output_file: Some(output_file.clone()), - output_dir: None, - file_loader: None, - diagnostic_output: DiagnosticOutput::Raw(box Sink(data.clone())), - stderr: Some(data.clone()), - crate_name: None, - lint_caps: Default::default(), - }; + let rustc_binary = options.test_builder.as_ref().map(|v| &**v).unwrap_or_else(|| { + rustc_interface::util::rustc_path().expect("found rustc") + }); + let mut compiler = Command::new(&rustc_binary); + compiler.arg("--crate-type").arg("bin"); + for cfg in &options.cfgs { + compiler.arg("--cfg").arg(&cfg); + } + if let Some(sysroot) = options.maybe_sysroot { + compiler.arg("--sysroot").arg(sysroot); + } + compiler.arg("--edition").arg(&edition.to_string()); + compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", path); + compiler.env("UNSTABLE_RUSTDOC_TEST_LINE", + format!("{}", line as isize - line_offset as isize)); + compiler.arg("-o").arg(&output_file); + if as_test_harness { + compiler.arg("--test"); + } + for lib_str in &options.lib_strs { + compiler.arg("-L").arg(&lib_str); + } + for extern_str in &options.extern_strs { + compiler.arg("--extern").arg(&extern_str); + } + compiler.arg("-Ccodegen-units=1"); + for codegen_options_str in &options.codegen_options_strs { + compiler.arg("-C").arg(&codegen_options_str); + } + if no_run { + compiler.arg("--emit=metadata"); + } + compiler.arg("--target").arg(target.to_string()); - let compile_result = panic::catch_unwind(AssertUnwindSafe(|| { - interface::run_compiler(config, |compiler| { - if no_run { - compiler.global_ctxt().and_then(|global_ctxt| global_ctxt.take().enter(|tcx| { - tcx.analysis(LOCAL_CRATE) - })).ok(); - } else { - compiler.compile().ok(); - }; - compiler.session().compile_status() - }) - })).map_err(|_| ()).and_then(|s| s.map_err(|_| ())); + compiler.arg("-"); + compiler.stdin(Stdio::piped()); + compiler.stderr(Stdio::piped()); - match (compile_result, compile_fail) { - (Ok(()), true) => { + let mut child = compiler.spawn().expect("Failed to spawn rustc process"); + { + let stdin = child.stdin.as_mut().expect("Failed to open stdin"); + stdin.write_all(test.as_bytes()).expect("could write out test sources"); + } + let output = child.wait_with_output().expect("Failed to read stdout"); + + struct Bomb<'a>(&'a str); + impl Drop for Bomb<'_> { + fn drop(&mut self) { + eprint!("{}",self.0); + } + } + + let out = str::from_utf8(&output.stderr).unwrap(); + let _bomb = Bomb(&out); + match (output.status.success(), compile_fail) { + (true, true) => { return Err(TestFailure::UnexpectedCompilePass); } - (Ok(()), false) => {} - (Err(_), true) => { + (true, false) => {} + (false, true) => { if !error_codes.is_empty() { - let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap(); error_codes.retain(|err| !out.contains(err)); if !error_codes.is_empty() { @@ -350,7 +319,7 @@ fn run_test( } } } - (Err(_), false) => { + (false, false) => { return Err(TestFailure::CompileError); } } @@ -360,7 +329,15 @@ fn run_test( } // Run the code! - let mut cmd = Command::new(output_file); + let mut cmd; + + if let Some(tool) = runtool { + cmd = Command::new(tool); + cmd.arg(output_file); + cmd.args(runtool_args); + } else { + cmd = Command::new(output_file); + } match cmd.output() { Err(e) => return Err(TestFailure::ExecutionError(e)), @@ -427,7 +404,7 @@ pub fn make_test(s: &str, // Any errors in parsing should also appear when the doctest is compiled for real, so just // send all the errors that libsyntax emits directly into a `Sink` instead of stderr. let cm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let emitter = EmitterWriter::new(box io::sink(), None, false, false, false); + let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None, false); // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser let handler = Handler::with_emitter(false, None, box emitter); let sess = ParseSess::with_span_handler(handler, cm); @@ -451,15 +428,15 @@ pub fn make_test(s: &str, match parser.parse_item() { Ok(Some(item)) => { if !found_main { - if let ast::ItemKind::Fn(..) = item.node { - if item.ident.as_str() == "main" { + if let ast::ItemKind::Fn(..) = item.kind { + if item.ident.name == sym::main { found_main = true; } } } if !found_extern_crate { - if let ast::ItemKind::ExternCrate(original) = item.node { + if let ast::ItemKind::ExternCrate(original) = item.kind { // This code will never be reached if `cratename` is none because // `found_extern_crate` is initialized to `true` if it is none. let cratename = cratename.unwrap(); @@ -472,7 +449,7 @@ pub fn make_test(s: &str, } if !found_macro { - if let ast::ItemKind::Mac(..) = item.node { + if let ast::ItemKind::Mac(..) = item.kind { found_macro = true; } } @@ -646,45 +623,31 @@ pub struct Collector { // the `names` vector of that test will be `["Title", "Subtitle"]`. names: Vec, - cfgs: Vec, - libs: Vec, - cg: CodegenOptions, - externs: Externs, + options: Options, use_headers: bool, + enable_per_target_ignores: bool, cratename: String, opts: TestOptions, - maybe_sysroot: Option, position: Span, source_map: Option>, filename: Option, - linker: Option, - edition: Edition, - persist_doctests: Option, } impl Collector { - pub fn new(cratename: String, cfgs: Vec, libs: Vec, cg: CodegenOptions, - externs: Externs, use_headers: bool, opts: TestOptions, - maybe_sysroot: Option, source_map: Option>, - filename: Option, linker: Option, edition: Edition, - persist_doctests: Option) -> Collector { + pub fn new(cratename: String, options: Options, use_headers: bool, opts: TestOptions, + source_map: Option>, filename: Option, + enable_per_target_ignores: bool) -> Collector { Collector { tests: Vec::new(), names: Vec::new(), - cfgs, - libs, - cg, - externs, + options, use_headers, + enable_per_target_ignores, cratename, opts, - maybe_sysroot, position: DUMMY_SP, source_map, filename, - linker, - edition, - persist_doctests, } } @@ -719,25 +682,30 @@ impl Tester for Collector { fn add_test(&mut self, test: String, config: LangString, line: usize) { let filename = self.get_filename(); let name = self.generate_name(line, &filename); - let cfgs = self.cfgs.clone(); - let libs = self.libs.clone(); - let cg = self.cg.clone(); - let externs = self.externs.clone(); let cratename = self.cratename.to_string(); let opts = self.opts.clone(); - let maybe_sysroot = self.maybe_sysroot.clone(); - let linker = self.linker.clone(); - let edition = config.edition.unwrap_or(self.edition); - let persist_doctests = self.persist_doctests.clone(); + let edition = config.edition.unwrap_or(self.options.edition.clone()); + let options = self.options.clone(); + let runtool = self.options.runtool.clone(); + let runtool_args = self.options.runtool_args.clone(); + let target = self.options.target.clone(); + let target_str = target.to_string(); debug!("creating test {}: {}", name, test); self.tests.push(testing::TestDescAndFn { desc: testing::TestDesc { - name: testing::DynTestName(name), - ignore: config.ignore, + name: testing::DynTestName(name.clone()), + ignore: match config.ignore { + Ignore::All => true, + Ignore::None => false, + Ignore::Some(ref ignores) => { + ignores.iter().any(|s| target_str.contains(s)) + }, + }, // compiler failures are test failures should_panic: testing::ShouldPanic::No, allow_fail: config.allow_fail, + test_type: testing::TestType::DocTest, }, testfn: testing::DynTestFn(box move || { let res = run_test( @@ -745,20 +713,17 @@ impl Tester for Collector { &cratename, &filename, line, - cfgs, - libs, - cg, - externs, + options, config.should_panic, config.no_run, config.test_harness, + runtool, + runtool_args, + target, config.compile_fail, config.error_codes, &opts, - maybe_sysroot, - linker, edition, - persist_doctests ); if let Err(err) = res { @@ -837,8 +802,8 @@ impl Tester for Collector { // We use these headings as test names, so it's good if // they're valid identifiers. let name = name.chars().enumerate().map(|(i, c)| { - if (i == 0 && c.is_xid_start()) || - (i != 0 && c.is_xid_continue()) { + if (i == 0 && rustc_lexer::is_id_start(c)) || + (i != 0 && rustc_lexer::is_id_continue(c)) { c } else { '_' @@ -901,7 +866,10 @@ impl<'a, 'hir> HirCollector<'a, 'hir> { // anything else, this will combine them for us. if let Some(doc) = attrs.collapsed_doc_value() { self.collector.set_position(attrs.span.unwrap_or(DUMMY_SP)); - markdown::find_testable_code(&doc, self.collector, self.codes); + markdown::find_testable_code(&doc, + self.collector, + self.codes, + self.collector.enable_per_target_ignores); } nested(self); @@ -918,7 +886,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> { } fn visit_item(&mut self, item: &'hir hir::Item) { - let name = if let hir::ItemKind::Impl(.., ref ty, _) = item.node { + let name = if let hir::ItemKind::Impl(.., ref ty, _) = item.kind { self.map.hir_to_pretty_string(ty.hir_id) } else { item.ident.to_string() @@ -951,7 +919,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> { v: &'hir hir::Variant, g: &'hir hir::Generics, item_id: hir::HirId) { - self.visit_testable(v.node.ident.to_string(), &v.node.attrs, |this| { + self.visit_testable(v.ident.to_string(), &v.attrs, |this| { intravisit::walk_variant(this, v, g, item_id); }); } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 1ba2c0333d6bf..b6a90e1fb988b 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -6,8 +6,8 @@ use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::middle::privacy::AccessLevel; use rustc::util::nodemap::{FxHashSet, FxHashMap}; +use rustc::ty::TyCtxt; use syntax::ast; -use syntax::attr; use syntax::ext::base::MacroKind; use syntax::source_map::Spanned; use syntax::symbol::sym; @@ -16,66 +16,61 @@ use syntax_pos::{self, Span}; use std::mem; use crate::core; -use crate::clean::{self, AttributesExt, NestedAttributesExt, def_id_to_path}; +use crate::clean::{self, AttributesExt, NestedAttributesExt}; use crate::doctree::*; - -// Looks to me like the first two of these are actually -// output parameters, maybe only mutated once; perhaps -// better simply to have the visit method return a tuple -// containing them? +// FIXME: Should this be replaced with tcx.def_path_str? +fn def_id_to_path( + tcx: TyCtxt<'_>, + did: DefId, +) -> Vec { + let crate_name = tcx.crate_name(did.krate).to_string(); + let relative = tcx.def_path(did).data.into_iter().filter_map(|elem| { + // extern blocks have an empty name + let s = elem.data.to_string(); + if !s.is_empty() { + Some(s) + } else { + None + } + }); + std::iter::once(crate_name).chain(relative).collect() +} // Also, is there some reason that this doesn't use the 'visit' // framework from syntax?. pub struct RustdocVisitor<'a, 'tcx> { - pub module: Option>, - pub cx: &'a core::DocContext<'tcx>, + cx: &'a mut core::DocContext<'tcx>, view_item_stack: FxHashSet, inlining: bool, /// Are the current module and all of its parents public? inside_public_path: bool, - exact_paths: Option>>, + exact_paths: FxHashMap>, } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { pub fn new( - cx: &'a core::DocContext<'tcx> + cx: &'a mut core::DocContext<'tcx> ) -> RustdocVisitor<'a, 'tcx> { // If the root is re-exported, terminate all recursion. let mut stack = FxHashSet::default(); stack.insert(hir::CRATE_HIR_ID); RustdocVisitor { - module: None, cx, view_item_stack: stack, inlining: false, inside_public_path: true, - exact_paths: Some(FxHashMap::default()), + exact_paths: FxHashMap::default(), } } fn store_path(&mut self, did: DefId) { - // We can't use the entry API, as that keeps the mutable borrow of `self` active - // when we try to use `cx`. - let exact_paths = self.exact_paths.as_mut().unwrap(); - if exact_paths.get(&did).is_none() { - let path = def_id_to_path(self.cx, did, self.cx.crate_name.clone()); - exact_paths.insert(did, path); - } - } - - fn stability(&self, id: hir::HirId) -> Option { - self.cx.tcx.hir().opt_local_def_id(id) - .and_then(|def_id| self.cx.tcx.lookup_stability(def_id)).cloned() - } - - fn deprecation(&self, id: hir::HirId) -> Option { - self.cx.tcx.hir().opt_local_def_id(id) - .and_then(|def_id| self.cx.tcx.lookup_deprecation(def_id)) + let tcx = self.cx.tcx; + self.exact_paths.entry(did).or_insert_with(|| def_id_to_path(tcx, did)); } - pub fn visit(&mut self, krate: &'tcx hir::Crate) { + pub fn visit(mut self, krate: &'tcx hir::Crate) -> Module<'tcx> { let mut module = self.visit_mod_contents(krate.span, &krate.attrs, &Spanned { span: syntax_pos::DUMMY_SP, @@ -88,12 +83,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { krate.exported_macros.iter().map(|def| self.visit_local_macro(def, None)), ); module.is_crate = true; - self.module = Some(module); - self.cx.renderinfo.borrow_mut().exact_paths = self.exact_paths.take().unwrap(); + self.cx.renderinfo.get_mut().exact_paths = self.exact_paths; + + module } - pub fn visit_variant_data(&mut self, item: &'tcx hir::Item, + fn visit_variant_data(&mut self, item: &'tcx hir::Item, name: ast::Name, sd: &'tcx hir::VariantData, generics: &'tcx hir::Generics) -> Struct<'tcx> { debug!("visiting struct"); @@ -103,8 +99,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { struct_type, name, vis: &item.vis, - stab: self.stability(item.hir_id), - depr: self.deprecation(item.hir_id), attrs: &item.attrs, generics, fields: sd.fields(), @@ -112,7 +106,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } - pub fn visit_union_data(&mut self, item: &'tcx hir::Item, + fn visit_union_data(&mut self, item: &'tcx hir::Item, name: ast::Name, sd: &'tcx hir::VariantData, generics: &'tcx hir::Generics) -> Union<'tcx> { debug!("visiting union"); @@ -122,8 +116,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { struct_type, name, vis: &item.vis, - stab: self.stability(item.hir_id), - depr: self.deprecation(item.hir_id), attrs: &item.attrs, generics, fields: sd.fields(), @@ -131,24 +123,20 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } - pub fn visit_enum_def(&mut self, it: &'tcx hir::Item, + fn visit_enum_def(&mut self, it: &'tcx hir::Item, name: ast::Name, def: &'tcx hir::EnumDef, generics: &'tcx hir::Generics) -> Enum<'tcx> { debug!("visiting enum"); Enum { name, variants: def.variants.iter().map(|v| Variant { - name: v.node.ident.name, - id: v.node.id, - attrs: &v.node.attrs, - stab: self.stability(v.node.id), - depr: self.deprecation(v.node.id), - def: &v.node.data, + name: v.ident.name, + id: v.id, + attrs: &v.attrs, + def: &v.data, whence: v.span, }).collect(), vis: &it.vis, - stab: self.stability(it.hir_id), - depr: self.deprecation(it.hir_id), generics, attrs: &it.attrs, id: it.hir_id, @@ -156,7 +144,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } - pub fn visit_fn(&mut self, om: &mut Module<'tcx>, item: &'tcx hir::Item, + fn visit_fn(&mut self, om: &mut Module<'tcx>, item: &'tcx hir::Item, name: ast::Name, decl: &'tcx hir::FnDecl, header: hir::FnHeader, generics: &'tcx hir::Generics, @@ -207,16 +195,12 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { helpers, attrs: &item.attrs, whence: item.span, - stab: self.stability(item.hir_id), - depr: self.deprecation(item.hir_id), }); } None => { om.fns.push(Function { id: item.hir_id, vis: &item.vis, - stab: self.stability(item.hir_id), - depr: self.deprecation(item.hir_id), attrs: &item.attrs, decl, name, @@ -229,16 +213,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } - pub fn visit_mod_contents(&mut self, span: Span, attrs: &'tcx hir::HirVec, + fn visit_mod_contents(&mut self, span: Span, attrs: &'tcx hir::HirVec, vis: &'tcx hir::Visibility, id: hir::HirId, m: &'tcx hir::Mod, name: Option) -> Module<'tcx> { let mut om = Module::new(name, attrs, vis); om.where_outer = span; om.where_inner = m.inner; - om.stab = self.stability(id); - om.depr = self.deprecation(id); - om.id = self.cx.tcx.hir().hir_to_node_id(id); + om.id = id; // Keep track of if there were any private modules in the path. let orig_inside_public_path = self.inside_public_path; self.inside_public_path &= vis.node.is_pub(); @@ -310,7 +292,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { Res::Def(DefKind::ForeignTy, did) | Res::Def(DefKind::TyAlias, did) if !self_is_hidden => { self.cx.renderinfo - .borrow_mut() + .get_mut() .access_levels.map .insert(did, AccessLevel::Public); }, @@ -338,7 +320,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { if !self.view_item_stack.insert(res_hir_id) { return false } let ret = match tcx.hir().get(res_hir_id) { - Node::Item(&hir::Item { node: hir::ItemKind::Mod(ref m), .. }) if glob => { + Node::Item(&hir::Item { kind: hir::ItemKind::Mod(ref m), .. }) if glob => { let prev = mem::replace(&mut self.inlining, true); for i in &m.item_ids { let i = self.cx.tcx.hir().expect_item(i.id); @@ -369,7 +351,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { ret } - pub fn visit_item(&mut self, item: &'tcx hir::Item, + fn visit_item(&mut self, item: &'tcx hir::Item, renamed: Option, om: &mut Module<'tcx>) { debug!("visiting item {:?}", item); let ident = renamed.unwrap_or(item.ident); @@ -379,7 +361,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { self.store_path(def_id); } - match item.node { + match item.kind { hir::ItemKind::ForeignMod(ref fm) => { for item in &fm.items { self.visit_foreign_item(item, None, om); @@ -467,8 +449,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, whence: item.span, vis: &item.vis, - stab: self.stability(item.hir_id), - depr: self.deprecation(item.hir_id), }; om.typedefs.push(t); }, @@ -480,8 +460,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, whence: item.span, vis: &item.vis, - stab: self.stability(item.hir_id), - depr: self.deprecation(item.hir_id), }; om.opaque_tys.push(t); }, @@ -495,8 +473,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, whence: item.span, vis: &item.vis, - stab: self.stability(item.hir_id), - depr: self.deprecation(item.hir_id), }; om.statics.push(s); }, @@ -509,8 +485,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, whence: item.span, vis: &item.vis, - stab: self.stability(item.hir_id), - depr: self.deprecation(item.hir_id), }; om.constants.push(s); }, @@ -529,8 +503,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, whence: item.span, vis: &item.vis, - stab: self.stability(item.hir_id), - depr: self.deprecation(item.hir_id), }; om.traits.push(t); }, @@ -543,8 +515,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, whence: item.span, vis: &item.vis, - stab: self.stability(item.hir_id), - depr: self.deprecation(item.hir_id), }; om.trait_aliases.push(t); }, @@ -574,8 +544,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { id: item.hir_id, whence: item.span, vis: &item.vis, - stab: self.stability(item.hir_id), - depr: self.deprecation(item.hir_id), }; om.impls.push(i); } @@ -593,10 +561,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { om.foreigns.push(ForeignItem { id: item.hir_id, name: renamed.unwrap_or(item.ident).name, - kind: &item.node, + kind: &item.kind, vis: &item.vis, - stab: self.stability(item.hir_id), - depr: self.deprecation(item.hir_id), attrs: &item.attrs, whence: item.span }); @@ -614,14 +580,12 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let matchers = tts.chunks(4).map(|arm| arm[0].span()).collect(); Macro { - + hid: def.hir_id, def_id: self.cx.tcx.hir().local_def_id(def.hir_id), attrs: &def.attrs, name: renamed.unwrap_or(def.name), whence: def.span, matchers, - stab: self.stability(def.hir_id), - depr: self.deprecation(def.hir_id), imported_from: None, } } diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 2547e3a06e9ef..b229b5f6884d8 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -1,12 +1,10 @@ use rustc::middle::privacy::{AccessLevels, AccessLevel}; use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; -use rustc::ty::Visibility; +use rustc::ty::{TyCtxt, Visibility}; use rustc::util::nodemap::FxHashSet; use syntax::symbol::sym; -use std::cell::RefMut; - use crate::clean::{AttributesExt, NestedAttributesExt}; // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses @@ -14,9 +12,9 @@ use crate::clean::{AttributesExt, NestedAttributesExt}; /// Similar to `librustc_privacy::EmbargoVisitor`, but also takes /// specific rustdoc annotations into account (i.e., `doc(hidden)`) pub struct LibEmbargoVisitor<'a, 'tcx> { - cx: &'a crate::core::DocContext<'tcx>, + tcx: TyCtxt<'tcx>, // Accessibility levels for reachable nodes - access_levels: RefMut<'a, AccessLevels>, + access_levels: &'a mut AccessLevels, // Previous accessibility level, None means unreachable prev_level: Option, // Keeps track of already visited modules, in case a module re-exports its parent @@ -25,13 +23,13 @@ pub struct LibEmbargoVisitor<'a, 'tcx> { impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { pub fn new( - cx: &'a crate::core::DocContext<'tcx> + cx: &'a mut crate::core::DocContext<'tcx> ) -> LibEmbargoVisitor<'a, 'tcx> { LibEmbargoVisitor { - cx, - access_levels: RefMut::map(cx.renderinfo.borrow_mut(), |ri| &mut ri.access_levels), + tcx: cx.tcx, + access_levels: &mut cx.renderinfo.get_mut().access_levels, prev_level: Some(AccessLevel::Public), - visited_mods: FxHashSet::default() + visited_mods: FxHashSet::default(), } } @@ -43,7 +41,7 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { // Updates node level and returns the updated level fn update(&mut self, did: DefId, level: Option) -> Option { - let is_hidden = self.cx.tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden); + let is_hidden = self.tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden); let old_level = self.access_levels.map.get(&did).cloned(); // Accessibility levels can only grow @@ -60,9 +58,9 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { return; } - for item in self.cx.tcx.item_children(def_id).iter() { + for item in self.tcx.item_children(def_id).iter() { if let Some(def_id) = item.res.opt_def_id() { - if self.cx.tcx.def_key(def_id).parent.map_or(false, |d| d == def_id.index) || + if self.tcx.def_key(def_id).parent.map_or(false, |d| d == def_id.index) || item.vis == Visibility::Public { self.visit_item(item.res); } @@ -72,7 +70,7 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { fn visit_item(&mut self, res: Res) { let def_id = res.def_id(); - let vis = self.cx.tcx.visibility(def_id); + let vis = self.tcx.visibility(def_id); let inherited_item_level = if vis == Visibility::Public { self.prev_level } else { diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index 80aeecb84d72b..d981740780e6f 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -9,10 +9,7 @@ use std::sync::Arc; use smallvec::{Array, SmallVec}; -impl Encodable for SmallVec - where A: Array, - A::Item: Encodable -{ +impl> Encodable for SmallVec { fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { for (i, e) in self.iter().enumerate() { @@ -23,10 +20,7 @@ impl Encodable for SmallVec } } -impl Decodable for SmallVec - where A: Array, - A::Item: Decodable -{ +impl> Decodable for SmallVec { fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut vec = SmallVec::with_capacity(len); diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index d0007074a823c..d2e360f5e20fd 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -1053,12 +1053,12 @@ impl Json { /// a value associated with the provided key is found. If no value is found /// or the Json value is not an Object, returns `None`. pub fn search(&self, key: &str) -> Option<&Json> { - match self { - &Json::Object(ref map) => { + match *self { + Json::Object(ref map) => { match map.get(key) { Some(json_value) => Some(json_value), None => { - for (_, v) in map { + for v in map.values() { match v.search(key) { x if x.is_some() => return x, _ => () @@ -1487,12 +1487,12 @@ impl> Parser { } fn parse_number(&mut self) -> JsonEvent { - let mut neg = false; - - if self.ch_is('-') { + let neg = if self.ch_is('-') { self.bump(); - neg = true; - } + true + } else { + false + }; let res = match self.parse_u64() { Ok(res) => res, @@ -2162,10 +2162,9 @@ impl crate::Decoder for Decoder { let s = self.read_str()?; { let mut it = s.chars(); - match (it.next(), it.next()) { + if let (Some(c), None) = (it.next(), it.next()) { // exactly one character - (Some(c), None) => return Ok(c), - _ => () + return Ok(c); } } Err(ExpectedError("single character string".to_owned(), s.to_string())) diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 2ad85c603d1e4..e45d56c320cd8 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -13,7 +13,9 @@ Core encoding and decoding interfaces. #![feature(specialization)] #![feature(never_type)] #![feature(nll)] +#![feature(associated_type_bounds)] #![cfg_attr(test, feature(test))] +#![allow(rustc::internal)] pub use self::serialize::{Decoder, Encoder, Decodable, Encodable}; diff --git a/src/libserialize/tests/json.rs b/src/libserialize/tests/json.rs index 3fb6bda679bc1..898168252e554 100644 --- a/src/libserialize/tests/json.rs +++ b/src/libserialize/tests/json.rs @@ -1,3 +1,5 @@ +#![allow(rustc::internal)] + extern crate serialize as rustc_serialize; use rustc_serialize::{Encodable, Decodable}; diff --git a/src/libserialize/tests/opaque.rs b/src/libserialize/tests/opaque.rs index fff6fc69e7842..592bc09039947 100644 --- a/src/libserialize/tests/opaque.rs +++ b/src/libserialize/tests/opaque.rs @@ -1,3 +1,5 @@ +#![allow(rustc::internal)] + extern crate serialize as rustc_serialize; use rustc_serialize::{Encodable, Decodable}; diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 5334c4dfc68cc..5309af6f4c342 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -23,22 +23,16 @@ libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of compiler_builtins = { version = "0.1.16" } profiler_builtins = { path = "../libprofiler_builtins", optional = true } unwind = { path = "../libunwind" } -hashbrown = { version = "0.4.0", features = ['rustc-dep-of-std'] } +hashbrown = { version = "0.6.1", default-features = false, features = ['rustc-dep-of-std'] } -[dependencies.backtrace] -version = "0.3.34" -default-features = false # don't use coresymbolication on OSX -features = [ - "rustc-dep-of-std", # enable build support for integrating into libstd - "dbghelp", # backtrace/symbolize on MSVC - "libbacktrace", # symbolize on most platforms - "libunwind", # backtrace on most platforms - "dladdr", # symbolize on platforms w/o libbacktrace -] -optional = true +[dependencies.backtrace_rs] +package = "backtrace" +version = "0.3.37" +default-features = false # without the libstd `backtrace` feature, stub out everything +features = [ "rustc-dep-of-std" ] # enable build support for integrating into libstd [dev-dependencies] -rand = "0.6.1" +rand = "0.7" [target.x86_64-apple-darwin.dependencies] rustc_asan = { path = "../librustc_asan" } @@ -56,12 +50,19 @@ dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] } [target.x86_64-fortanix-unknown-sgx.dependencies] fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] } -[build-dependencies] -cc = "1.0" +[target.wasm32-wasi.dependencies] +wasi = { version = "0.7.0", features = ['rustc-dep-of-std', 'alloc'] } [features] default = ["std_detect_file_io", "std_detect_dlsym_getauxval"] +backtrace = [ + "backtrace_rs/dbghelp", # backtrace/symbolize on MSVC + "backtrace_rs/libbacktrace", # symbolize on most platforms + "backtrace_rs/libunwind", # backtrace on most platforms + "backtrace_rs/dladdr", # symbolize on platforms w/o libbacktrace +] + panic-unwind = ["panic_unwind"] profiler = ["profiler_builtins"] compiler-builtins-c = ["alloc/compiler-builtins-c"] @@ -70,11 +71,6 @@ llvm-libunwind = ["unwind/llvm-libunwind"] # Make panics and failed asserts immediately abort without formatting any message panic_immediate_abort = ["core/panic_immediate_abort"] -# An off-by-default feature which enables a linux-syscall-like ABI for libstd to -# interoperate with the host environment. Currently not well documented and -# requires rebuilding the standard library to use it. -wasm_syscall = [] - # Enable std_detect default features for stdarch/crates/std_detect: # https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml std_detect_file_io = [] diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs new file mode 100644 index 0000000000000..9f400713a86d4 --- /dev/null +++ b/src/libstd/backtrace.rs @@ -0,0 +1,353 @@ +//! Support for capturing a stack backtrace of an OS thread +//! +//! This module contains the support necessary to capture a stack backtrace of a +//! running OS thread from the OS thread itself. The `Backtrace` type supports +//! capturing a stack trace via the `Backtrace::capture` and +//! `Backtrace::force_capture` functions. +//! +//! A backtrace is typically quite handy to attach to errors (e.g. types +//! implementing `std::error::Error`) to get a causal chain of where an error +//! was generated. +//! +//! > **Note**: this module is unstable and is designed in [RFC 2504], and you +//! > can learn more about its status in the [tracking issue]. +//! +//! [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md +//! [tracking issue]: https://github.com/rust-lang/rust/issues/53487 +//! +//! ## Accuracy +//! +//! Backtraces are attempted to be as accurate as possible, but no guarantees +//! are provided about the exact accuracy of a backtrace. Instruction pointers, +//! symbol names, filenames, line numbers, etc, may all be incorrect when +//! reported. Accuracy is attempted on a best-effort basis, however, and bugs +//! are always welcome to indicate areas of improvement! +//! +//! For most platforms a backtrace with a filename/line number requires that +//! programs be compiled with debug information. Without debug information +//! filenames/line numbers will not be reported. +//! +//! ## Platform support +//! +//! Not all platforms that libstd compiles for support capturing backtraces. +//! Some platforms simply do nothing when capturing a backtrace. To check +//! whether the platform supports capturing backtraces you can consult the +//! `BacktraceStatus` enum as a result of `Backtrace::status`. +//! +//! Like above with accuracy platform support is done on a best effort basis. +//! Sometimes libraries may not be available at runtime or something may go +//! wrong which would cause a backtrace to not be captured. Please feel free to +//! report issues with platforms where a backtrace cannot be captured though! +//! +//! ## Environment Variables +//! +//! The `Backtrace::capture` function may not actually capture a backtrace by +//! default. Its behavior is governed by two environment variables: +//! +//! * `RUST_LIB_BACKTRACE` - if this is set to `0` then `Backtrace::capture` +//! will never capture a backtrace. Any other value this is set to will enable +//! `Backtrace::capture`. +//! +//! * `RUST_BACKTRACE` - if `RUST_LIB_BACKTRACE` is not set, then this variable +//! is consulted with the same rules of `RUST_LIB_BACKTRACE`. +//! +//! * If neither of the above env vars are set, then `Backtrace::capture` will +//! be disabled. +//! +//! Capturing a backtrace can be a quite expensive runtime operation, so the +//! environment variables allow either forcibly disabling this runtime +//! performance hit or allow selectively enabling it in some programs. +//! +//! Note that the `Backtrace::force_capture` function can be used to ignore +//! these environment variables. Also note that the state of environment +//! variables is cached once the first backtrace is created, so altering +//! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime may not actually change +//! how backtraces are captured. + +#![unstable(feature = "backtrace", issue = "53487")] + +// NB: A note on resolution of a backtrace: +// +// Backtraces primarily happen in two steps, one is where we actually capture +// the stack backtrace, giving us a list of instruction pointers corresponding +// to stack frames. Next we take these instruction pointers and, one-by-one, +// turn them into a human readable name (like `main`). +// +// The first phase can be somewhat expensive (walking the stack), especially +// on MSVC where debug information is consulted to return inline frames each as +// their own frame. The second phase, however, is almost always extremely +// expensive (on the order of milliseconds sometimes) when it's consulting debug +// information. +// +// We attempt to amortize this cost as much as possible by delaying resolution +// of an address to a human readable name for as long as possible. When +// `Backtrace::create` is called to capture a backtrace it doesn't actually +// perform any symbol resolution, but rather we lazily resolve symbols only just +// before they're needed for printing. This way we can make capturing a +// backtrace and throwing it away much cheaper, but actually printing a +// backtrace is still basically the same cost. +// +// This strategy comes at the cost of some synchronization required inside of a +// `Backtrace`, but that's a relatively small price to pay relative to capturing +// a backtrace or actually symbolizing it. + +use crate::env; +use crate::fmt; +use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; +use crate::sync::Mutex; +use crate::sys_common::backtrace::{output_filename, lock}; +use crate::vec::Vec; +use backtrace_rs as backtrace; +use backtrace::BytesOrWideString; + +/// A captured OS thread stack backtrace. +/// +/// This type represents a stack backtrace for an OS thread captured at a +/// previous point in time. In some instances the `Backtrace` type may +/// internally be empty due to configuration. For more information see +/// `Backtrace::capture`. +pub struct Backtrace { + inner: Inner, +} + +/// The current status of a backtrace, indicating whether it was captured or +/// whether it is empty for some other reason. +#[non_exhaustive] +#[derive(Debug, PartialEq, Eq)] +pub enum BacktraceStatus { + /// Capturing a backtrace is not supported, likely because it's not + /// implemented for the current platform. + Unsupported, + /// Capturing a backtrace has been disabled through either the + /// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables. + Disabled, + /// A backtrace has been captured and the `Backtrace` should print + /// reasonable information when rendered. + Captured, +} + +enum Inner { + Unsupported, + Disabled, + Captured(Mutex), +} + +struct Capture { + actual_start: usize, + resolved: bool, + frames: Vec, +} + +fn _assert_send_sync() { + fn _assert() {} + _assert::(); +} + +struct BacktraceFrame { + frame: backtrace::Frame, + symbols: Vec, +} + +struct BacktraceSymbol { + name: Option>, + filename: Option, + lineno: Option, +} + +enum BytesOrWide { + Bytes(Vec), + Wide(Vec), +} + +impl Backtrace { + /// Returns whether backtrace captures are enabled through environment + /// variables. + fn enabled() -> bool { + // Cache the result of reading the environment variables to make + // backtrace captures speedy, because otherwise reading environment + // variables every time can be somewhat slow. + static ENABLED: AtomicUsize = AtomicUsize::new(0); + match ENABLED.load(SeqCst) { + 0 => {} + 1 => return false, + _ => return true, + } + let enabled = match env::var("RUST_LIB_BACKTRACE") { + Ok(s) => s != "0", + Err(_) => match env::var("RUST_BACKTRACE") { + Ok(s) => s != "0", + Err(_) => false, + }, + }; + ENABLED.store(enabled as usize + 1, SeqCst); + return enabled; + } + + /// Capture a stack backtrace of the current thread. + /// + /// This function will capture a stack backtrace of the current OS thread of + /// execution, returning a `Backtrace` type which can be later used to print + /// the entire stack trace or render it to a string. + /// + /// This function will be a noop if the `RUST_BACKTRACE` or + /// `RUST_LIB_BACKTRACE` backtrace variables are both not set. If either + /// environment variable is set and enabled then this function will actually + /// capture a backtrace. Capturing a backtrace can be both memory intensive + /// and slow, so these environment variables allow liberally using + /// `Backtrace::capture` and only incurring a slowdown when the environment + /// variables are set. + /// + /// To forcibly capture a backtrace regardless of environment variables, use + /// the `Backtrace::force_capture` function. + #[inline(never)] // want to make sure there's a frame here to remove + pub fn capture() -> Backtrace { + if !Backtrace::enabled() { + return Backtrace { inner: Inner::Disabled }; + } + Backtrace::create(Backtrace::capture as usize) + } + + /// Forcibly captures a full backtrace, regardless of environment variable + /// configuration. + /// + /// This function behaves the same as `capture` except that it ignores the + /// values of the `RUST_BACKTRACE` and `RUST_LIB_BACKTRACE` environment + /// variables, always capturing a backtrace. + /// + /// Note that capturing a backtrace can be an expensive operation on some + /// platforms, so this should be used with caution in performance-sensitive + /// parts of code. + #[inline(never)] // want to make sure there's a frame here to remove + pub fn force_capture() -> Backtrace { + Backtrace::create(Backtrace::force_capture as usize) + } + + // Capture a backtrace which start just before the function addressed by + // `ip` + fn create(ip: usize) -> Backtrace { + let _lock = lock(); + let mut frames = Vec::new(); + let mut actual_start = None; + unsafe { + backtrace::trace_unsynchronized(|frame| { + frames.push(BacktraceFrame { frame: frame.clone(), symbols: Vec::new() }); + if frame.symbol_address() as usize == ip && actual_start.is_none() { + actual_start = Some(frames.len()); + } + true + }); + } + + // If no frames came out assume that this is an unsupported platform + // since `backtrace` doesn't provide a way of learning this right now, + // and this should be a good enough approximation. + let inner = if frames.len() == 0 { + Inner::Unsupported + } else { + Inner::Captured(Mutex::new(Capture { + actual_start: actual_start.unwrap_or(0), + frames, + resolved: false, + })) + }; + + Backtrace { inner } + } + + /// Returns the status of this backtrace, indicating whether this backtrace + /// request was unsupported, disabled, or a stack trace was actually + /// captured. + pub fn status(&self) -> BacktraceStatus { + match self.inner { + Inner::Unsupported => BacktraceStatus::Unsupported, + Inner::Disabled => BacktraceStatus::Disabled, + Inner::Captured(_) => BacktraceStatus::Captured, + } + } +} + +impl fmt::Display for Backtrace { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self, fmt) + } +} + +impl fmt::Debug for Backtrace { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut capture = match &self.inner { + Inner::Unsupported => return fmt.write_str("unsupported backtrace"), + Inner::Disabled => return fmt.write_str("disabled backtrace"), + Inner::Captured(c) => c.lock().unwrap(), + }; + capture.resolve(); + + let full = fmt.alternate(); + let (frames, style) = if full { + (&capture.frames[..], backtrace::PrintFmt::Full) + } else { + (&capture.frames[capture.actual_start..], backtrace::PrintFmt::Short) + }; + + // When printing paths we try to strip the cwd if it exists, otherwise + // we just print the path as-is. Note that we also only do this for the + // short format, because if it's full we presumably want to print + // everything. + let cwd = crate::env::current_dir(); + let mut print_path = move |fmt: &mut fmt::Formatter<'_>, path: BytesOrWideString<'_>| { + output_filename(fmt, path, style, cwd.as_ref().ok()) + }; + + let mut f = backtrace::BacktraceFmt::new(fmt, style, &mut print_path); + f.add_context()?; + for frame in frames { + let mut f = f.frame(); + if frame.symbols.is_empty() { + f.print_raw(frame.frame.ip(), None, None, None)?; + } else { + for symbol in frame.symbols.iter() { + f.print_raw( + frame.frame.ip(), + symbol.name.as_ref().map(|b| backtrace::SymbolName::new(b)), + symbol.filename.as_ref().map(|b| match b { + BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w), + BytesOrWide::Wide(w) => BytesOrWideString::Wide(w), + }), + symbol.lineno, + )?; + } + } + } + f.finish()?; + Ok(()) + } +} + +impl Capture { + fn resolve(&mut self) { + // If we're already resolved, nothing to do! + if self.resolved { + return; + } + self.resolved = true; + + // Use the global backtrace lock to synchronize this as it's a + // requirement of the `backtrace` crate, and then actually resolve + // everything. + let _lock = lock(); + for frame in self.frames.iter_mut() { + let symbols = &mut frame.symbols; + unsafe { + backtrace::resolve_frame_unsynchronized(&frame.frame, |symbol| { + symbols.push(BacktraceSymbol { + name: symbol.name().map(|m| m.as_bytes().to_vec()), + filename: symbol.filename_raw().map(|b| match b { + BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()), + BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()), + }), + lineno: symbol.lineno(), + }); + }); + } + } + } +} diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 1e28ee8da26b4..6b0225a1b443a 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -6,7 +6,7 @@ use hashbrown::hash_map as base; use crate::borrow::Borrow; use crate::cell::Cell; -use crate::collections::CollectionAllocErr; +use crate::collections::TryReserveError; use crate::fmt::{self, Debug}; #[allow(deprecated)] use crate::hash::{BuildHasher, Hash, Hasher, SipHasher13}; @@ -192,14 +192,9 @@ use crate::sys; /// ``` /// use std::collections::HashMap; /// -/// fn main() { -/// let timber_resources: HashMap<&str, i32> = -/// [("Norway", 100), -/// ("Denmark", 50), -/// ("Iceland", 10)] -/// .iter().cloned().collect(); -/// // use the values stored in map -/// } +/// let timber_resources: HashMap<&str, i32> = [("Norway", 100), ("Denmark", 50), ("Iceland", 10)] +/// .iter().cloned().collect(); +/// // use the values stored in map /// ``` #[derive(Clone)] @@ -588,7 +583,7 @@ where /// ``` #[inline] #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.base .try_reserve(additional) .map_err(map_collection_alloc_err) @@ -714,7 +709,6 @@ where /// # Examples /// /// ``` - /// #![feature(map_get_key_value)] /// use std::collections::HashMap; /// /// let mut map = HashMap::new(); @@ -722,7 +716,7 @@ where /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); /// assert_eq!(map.get_key_value(&2), None); /// ``` - #[unstable(feature = "map_get_key_value", issue = "49347")] + #[stable(feature = "map_get_key_value", since = "1.40.0")] #[inline] pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> where @@ -2036,6 +2030,31 @@ impl<'a, K, V> Entry<'a, K, V> { Vacant(entry) => Vacant(entry), } } + + /// Sets the value of the entry, and returns an OccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// #![feature(entry_insert)] + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// let entry = map.entry("poneyland").insert("hoho".to_string()); + /// + /// assert_eq!(entry.key(), &"poneyland"); + /// ``` + #[inline] + #[unstable(feature = "entry_insert", issue = "65225")] + pub fn insert(self, value: V) -> OccupiedEntry<'a, K, V> { + match self { + Occupied(mut entry) => { + entry.insert(value); + entry + }, + Vacant(entry) => entry.insert_entry(value), + } + } } impl<'a, K, V: Default> Entry<'a, K, V> { @@ -2353,6 +2372,28 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { pub fn insert(self, value: V) -> &'a mut V { self.base.insert(value) } + + /// Sets the value of the entry with the VacantEntry's key, + /// and returns an OccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(o) = map.entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[inline] + fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> { + let base = self.base.insert_entry(value); + OccupiedEntry { base } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -2368,6 +2409,8 @@ where } } +/// Inserts all new key-values from the iterator and replaces values with existing +/// keys with new values returned from the iterator. #[stable(feature = "rust1", since = "1.0.0")] impl Extend<(K, V)> for HashMap where @@ -2542,10 +2585,13 @@ fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K, } #[inline] -fn map_collection_alloc_err(err: hashbrown::CollectionAllocErr) -> CollectionAllocErr { +fn map_collection_alloc_err(err: hashbrown::CollectionAllocErr) -> TryReserveError { match err { - hashbrown::CollectionAllocErr::CapacityOverflow => CollectionAllocErr::CapacityOverflow, - hashbrown::CollectionAllocErr::AllocErr => CollectionAllocErr::AllocErr, + hashbrown::CollectionAllocErr::CapacityOverflow => TryReserveError::CapacityOverflow, + hashbrown::CollectionAllocErr::AllocErr { layout } => TryReserveError::AllocError { + layout, + non_exhaustive: (), + }, } } @@ -2605,7 +2651,7 @@ mod test_map { use super::RandomState; use crate::cell::RefCell; use rand::{thread_rng, Rng}; - use realstd::collections::CollectionAllocErr::*; + use realstd::collections::TryReserveError::*; use realstd::usize; // https://github.com/rust-lang/rust/issues/62301 @@ -3405,7 +3451,7 @@ mod test_map { panic!("usize::MAX should trigger an overflow!"); } - if let Err(AllocErr) = empty_bytes.try_reserve(MAX_USIZE / 8) { + if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) { } else { panic!("usize::MAX / 8 should trigger an OOM!") } diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index d243412405a79..092fb44346848 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -1,5 +1,5 @@ use crate::borrow::Borrow; -use crate::collections::CollectionAllocErr; +use crate::collections::TryReserveError; use crate::fmt; use crate::hash::{Hash, BuildHasher}; use crate::iter::{Chain, FromIterator, FusedIterator}; @@ -93,11 +93,9 @@ use super::map::{self, HashMap, Keys, RandomState}; /// ``` /// use std::collections::HashSet; /// -/// fn main() { -/// let viking_names: HashSet<&'static str> = -/// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect(); -/// // use the values stored in the set -/// } +/// let viking_names: HashSet<&'static str> = +/// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect(); +/// // use the values stored in the set /// ``` /// /// [`Cell`]: ../../std/cell/struct.Cell.html @@ -383,7 +381,7 @@ impl HashSet /// ``` #[inline] #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.map.try_reserve(additional) } diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 15c2532f8b4e0..f5957466be841 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -427,7 +427,7 @@ pub use self::hash_map::HashMap; pub use self::hash_set::HashSet; #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -pub use alloc_crate::collections::CollectionAllocErr; +pub use alloc_crate::collections::TryReserveError; mod hash; diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 1f5de25b65c90..b89893692698c 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -182,6 +182,12 @@ impl fmt::Debug for VarsOs { /// * Environment variable is not present /// * Environment variable is not valid unicode /// +/// # Panics +/// +/// This function may panic if `key` is empty, contains an ASCII equals sign +/// `'='` or the NUL character `'\0'`, or when the value contains the NUL +/// character. +/// /// # Examples /// /// ``` @@ -210,6 +216,12 @@ fn _var(key: &OsStr) -> Result { /// /// [`None`]: ../option/enum.Option.html#variant.None /// +/// # Panics +/// +/// This function may panic if `key` is empty, contains an ASCII equals sign +/// `'='` or the NUL character `'\0'`, or when the value contains the NUL +/// character. +/// /// # Examples /// /// ``` @@ -278,7 +290,7 @@ impl Error for VarError { /// /// Note that while concurrent access to environment variables is safe in Rust, /// some platforms only expose inherently unsafe non-threadsafe APIs for -/// inspecting the environment. As a result extra care needs to be taken when +/// inspecting the environment. As a result, extra care needs to be taken when /// auditing calls to unsafe external FFI functions to ensure that any external /// environment accesses are properly synchronized with accesses in Rust. /// diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 117a430eec6b9..4a1bb75d588c9 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -17,6 +17,7 @@ use core::array; use crate::alloc::{AllocErr, LayoutErr, CannotReallocInPlace}; use crate::any::TypeId; +use crate::backtrace::Backtrace; use crate::borrow::Cow; use crate::cell; use crate::char; @@ -196,14 +197,28 @@ pub trait Error: Debug + Display { #[stable(feature = "error_source", since = "1.30.0")] fn source(&self) -> Option<&(dyn Error + 'static)> { None } - /// Gets the `TypeId` of `self` + /// Gets the `TypeId` of `self`. #[doc(hidden)] #[unstable(feature = "error_type_id", - reason = "this is memory unsafe to override in user code", + reason = "this is memory-unsafe to override in user code", issue = "60784")] fn type_id(&self, _: private::Internal) -> TypeId where Self: 'static { TypeId::of::() } + + /// Returns a stack backtrace, if available, of where this error ocurred. + /// + /// This function allows inspecting the location, in code, of where an error + /// happened. The returned `Backtrace` contains information about the stack + /// trace of the OS thread of execution of where the error originated from. + /// + /// Note that not all errors contain a `Backtrace`. Also note that a + /// `Backtrace` may actually be empty. For more information consult the + /// `Backtrace` type itself. + #[unstable(feature = "backtrace", issue = "53487")] + fn backtrace(&self) -> Option<&Backtrace> { + None + } } mod private { @@ -601,19 +616,19 @@ impl Error for char::ParseCharError { } } -// copied from any.rs +// Copied from `any.rs`. impl dyn Error + 'static { /// Returns `true` if the boxed type is the same as `T` #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn is(&self) -> bool { - // Get TypeId of the type this function is instantiated with + // Get `TypeId` of the type this function is instantiated with. let t = TypeId::of::(); - // Get TypeId of the type in the trait object + // Get `TypeId` of the type in the trait object. let boxed = self.type_id(private::Internal); - // Compare both TypeIds on equality + // Compare both `TypeId`s on equality. t == boxed } @@ -647,21 +662,21 @@ impl dyn Error + 'static { } impl dyn Error + 'static + Send { - /// Forwards to the method defined on the type `Any`. + /// Forwards to the method defined on the type `dyn Error`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn is(&self) -> bool { ::is::(self) } - /// Forwards to the method defined on the type `Any`. + /// Forwards to the method defined on the type `dyn Error`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn downcast_ref(&self) -> Option<&T> { ::downcast_ref::(self) } - /// Forwards to the method defined on the type `Any`. + /// Forwards to the method defined on the type `dyn Error`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn downcast_mut(&mut self) -> Option<&mut T> { @@ -670,21 +685,21 @@ impl dyn Error + 'static + Send { } impl dyn Error + 'static + Send + Sync { - /// Forwards to the method defined on the type `Any`. + /// Forwards to the method defined on the type `dyn Error`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn is(&self) -> bool { ::is::(self) } - /// Forwards to the method defined on the type `Any`. + /// Forwards to the method defined on the type `dyn Error`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn downcast_ref(&self) -> Option<&T> { ::downcast_ref::(self) } - /// Forwards to the method defined on the type `Any`. + /// Forwards to the method defined on the type `dyn Error`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn downcast_mut(&mut self) -> Option<&mut T> { @@ -695,7 +710,7 @@ impl dyn Error + 'static + Send + Sync { impl dyn Error { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] - /// Attempt to downcast the box to a concrete type. + /// Attempts to downcast the box to a concrete type. pub fn downcast(self: Box) -> Result, Box> { if self.is::() { unsafe { @@ -863,12 +878,12 @@ impl<'a> Iterator for ErrorIter<'a> { impl dyn Error + Send { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] - /// Attempt to downcast the box to a concrete type. + /// Attempts to downcast the box to a concrete type. pub fn downcast(self: Box) -> Result, Box> { let err: Box = self; ::downcast(err).map_err(|s| unsafe { - // reapply the Send marker + // Reapply the `Send` marker. transmute::, Box>(s) }) } @@ -877,12 +892,12 @@ impl dyn Error + Send { impl dyn Error + Send + Sync { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] - /// Attempt to downcast the box to a concrete type. + /// Attempts to downcast the box to a concrete type. pub fn downcast(self: Box) -> Result, Box> { let err: Box = self; ::downcast(err).map_err(|s| unsafe { - // reapply the Send+Sync marker + // Reapply the `Send + Sync` marker. transmute::, Box>(s) }) } diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index f649170c40372..795830a52c545 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -236,7 +236,7 @@ impl f32 { /// let b = 60.0_f32; /// /// // 100.0 - /// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs(); + /// let abs_difference = (m.mul_add(x, b) - ((m * x) + b)).abs(); /// /// assert!(abs_difference <= f32::EPSILON); /// ``` @@ -318,7 +318,7 @@ impl f32 { /// use std::f32; /// /// let x = 2.0_f32; - /// let abs_difference = (x.powi(2) - x*x).abs(); + /// let abs_difference = (x.powi(2) - (x * x)).abs(); /// /// assert!(abs_difference <= f32::EPSILON); /// ``` @@ -336,7 +336,7 @@ impl f32 { /// use std::f32; /// /// let x = 2.0_f32; - /// let abs_difference = (x.powf(2.0) - x*x).abs(); + /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); /// /// assert!(abs_difference <= f32::EPSILON); /// ``` @@ -600,7 +600,7 @@ impl f32 { /// ``` /// use std::f32; /// - /// let x = f32::consts::PI/2.0; + /// let x = f32::consts::FRAC_PI_2; /// /// let abs_difference = (x.sin() - 1.0).abs(); /// @@ -623,7 +623,7 @@ impl f32 { /// ``` /// use std::f32; /// - /// let x = 2.0*f32::consts::PI; + /// let x = 2.0 * f32::consts::PI; /// /// let abs_difference = (x.cos() - 1.0).abs(); /// @@ -646,7 +646,7 @@ impl f32 { /// ``` /// use std::f32; /// - /// let x = f32::consts::PI / 4.0; + /// let x = f32::consts::FRAC_PI_4; /// let abs_difference = (x.tan() - 1.0).abs(); /// /// assert!(abs_difference <= f32::EPSILON); @@ -666,10 +666,10 @@ impl f32 { /// ``` /// use std::f32; /// - /// let f = f32::consts::PI / 2.0; + /// let f = f32::consts::FRAC_PI_2; /// /// // asin(sin(pi/2)) - /// let abs_difference = (f.sin().asin() - f32::consts::PI / 2.0).abs(); + /// let abs_difference = (f.sin().asin() - f32::consts::FRAC_PI_2).abs(); /// /// assert!(abs_difference <= f32::EPSILON); /// ``` @@ -688,10 +688,10 @@ impl f32 { /// ``` /// use std::f32; /// - /// let f = f32::consts::PI / 4.0; + /// let f = f32::consts::FRAC_PI_4; /// /// // acos(cos(pi/4)) - /// let abs_difference = (f.cos().acos() - f32::consts::PI / 4.0).abs(); + /// let abs_difference = (f.cos().acos() - f32::consts::FRAC_PI_4).abs(); /// /// assert!(abs_difference <= f32::EPSILON); /// ``` @@ -734,7 +734,6 @@ impl f32 { /// ``` /// use std::f32; /// - /// let pi = f32::consts::PI; /// // Positive angles measured counter-clockwise /// // from positive x axis /// // -pi/4 radians (45 deg clockwise) @@ -745,8 +744,8 @@ impl f32 { /// let x2 = -3.0f32; /// let y2 = 3.0f32; /// - /// let abs_difference_1 = (y1.atan2(x1) - (-pi/4.0)).abs(); - /// let abs_difference_2 = (y2.atan2(x2) - 3.0*pi/4.0).abs(); + /// let abs_difference_1 = (y1.atan2(x1) - (-f32::consts::FRAC_PI_4)).abs(); + /// let abs_difference_2 = (y2.atan2(x2) - (3.0 * f32::consts::FRAC_PI_4)).abs(); /// /// assert!(abs_difference_1 <= f32::EPSILON); /// assert!(abs_difference_2 <= f32::EPSILON); @@ -765,7 +764,7 @@ impl f32 { /// ``` /// use std::f32; /// - /// let x = f32::consts::PI/4.0; + /// let x = f32::consts::FRAC_PI_4; /// let f = x.sin_cos(); /// /// let abs_difference_0 = (f.0 - x.sin()).abs(); @@ -834,7 +833,7 @@ impl f32 { /// /// let f = x.sinh(); /// // Solving sinh() at 1 gives `(e^2-1)/(2e)` - /// let g = (e*e - 1.0)/(2.0*e); + /// let g = ((e * e) - 1.0) / (2.0 * e); /// let abs_difference = (f - g).abs(); /// /// assert!(abs_difference <= f32::EPSILON); @@ -856,7 +855,7 @@ impl f32 { /// let x = 1.0f32; /// let f = x.cosh(); /// // Solving cosh() at 1 gives this result - /// let g = (e*e + 1.0)/(2.0*e); + /// let g = ((e * e) + 1.0) / (2.0 * e); /// let abs_difference = (f - g).abs(); /// /// // Same result @@ -880,7 +879,7 @@ impl f32 { /// /// let f = x.tanh(); /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))` - /// let g = (1.0 - e.powi(-2))/(1.0 + e.powi(-2)); + /// let g = (1.0 - e.powi(-2)) / (1.0 + e.powi(-2)); /// let abs_difference = (f - g).abs(); /// /// assert!(abs_difference <= f32::EPSILON); @@ -911,7 +910,7 @@ impl f32 { if self == NEG_INFINITY { NEG_INFINITY } else { - (self + ((self * self) + 1.0).sqrt()).ln() + (self + ((self * self) + 1.0).sqrt()).ln().copysign(self) } } @@ -932,9 +931,10 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn acosh(self) -> f32 { - match self { - x if x < 1.0 => crate::f32::NAN, - x => (x + ((x * x) - 1.0).sqrt()).ln(), + if self < 1.0 { + crate::f32::NAN + } else { + (self + ((self * self) - 1.0).sqrt()).ln() } } @@ -1488,6 +1488,7 @@ mod tests { assert_eq!(inf.asinh(), inf); assert_eq!(neg_inf.asinh(), neg_inf); assert!(nan.asinh().is_nan()); + assert!((-0.0f32).asinh().is_sign_negative()); // issue 63271 assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32); } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index f61630997dcdb..44d25f1b47657 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -212,7 +212,7 @@ impl f64 { /// let b = 60.0_f64; /// /// // 100.0 - /// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs(); + /// let abs_difference = (m.mul_add(x, b) - ((m * x) + b)).abs(); /// /// assert!(abs_difference < 1e-10); /// ``` @@ -244,7 +244,7 @@ impl f64 { pub fn div_euclid(self, rhs: f64) -> f64 { let q = (self / rhs).trunc(); if self % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 } + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; } q } @@ -291,7 +291,7 @@ impl f64 { /// /// ``` /// let x = 2.0_f64; - /// let abs_difference = (x.powi(2) - x*x).abs(); + /// let abs_difference = (x.powi(2) - (x * x)).abs(); /// /// assert!(abs_difference < 1e-10); /// ``` @@ -307,7 +307,7 @@ impl f64 { /// /// ``` /// let x = 2.0_f64; - /// let abs_difference = (x.powf(2.0) - x*x).abs(); + /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); /// /// assert!(abs_difference < 1e-10); /// ``` @@ -437,9 +437,9 @@ impl f64 { pub fn log2(self) -> f64 { self.log_wrapper(|n| { #[cfg(target_os = "android")] - return crate::sys::android::log2f64(n); + return crate::sys::android::log2f64(n); #[cfg(not(target_os = "android"))] - return unsafe { intrinsics::log2f64(n) }; + return unsafe { intrinsics::log2f64(n) }; }) } @@ -481,16 +481,16 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] #[rustc_deprecated(since = "1.10.0", - reason = "you probably meant `(self - other).abs()`: \ + reason = "you probably meant `(self - other).abs()`: \ this operation is `(self - other).max(0.0)` \ except that `abs_sub` also propagates NaNs (also \ known as `fdim` in C). If you truly need the positive \ difference, consider using that expression or the C function \ `fdim`, depending on how you wish to handle NaN (please consider \ filing an issue describing your use-case too).")] - pub fn abs_sub(self, other: f64) -> f64 { - unsafe { cmath::fdim(self, other) } - } + pub fn abs_sub(self, other: f64) -> f64 { + unsafe { cmath::fdim(self, other) } + } /// Takes the cubic root of a number. /// @@ -537,7 +537,7 @@ impl f64 { /// ``` /// use std::f64; /// - /// let x = f64::consts::PI/2.0; + /// let x = f64::consts::FRAC_PI_2; /// /// let abs_difference = (x.sin() - 1.0).abs(); /// @@ -556,7 +556,7 @@ impl f64 { /// ``` /// use std::f64; /// - /// let x = 2.0*f64::consts::PI; + /// let x = 2.0 * f64::consts::PI; /// /// let abs_difference = (x.cos() - 1.0).abs(); /// @@ -575,7 +575,7 @@ impl f64 { /// ``` /// use std::f64; /// - /// let x = f64::consts::PI/4.0; + /// let x = f64::consts::FRAC_PI_4; /// let abs_difference = (x.tan() - 1.0).abs(); /// /// assert!(abs_difference < 1e-14); @@ -595,10 +595,10 @@ impl f64 { /// ``` /// use std::f64; /// - /// let f = f64::consts::PI / 2.0; + /// let f = f64::consts::FRAC_PI_2; /// /// // asin(sin(pi/2)) - /// let abs_difference = (f.sin().asin() - f64::consts::PI / 2.0).abs(); + /// let abs_difference = (f.sin().asin() - f64::consts::FRAC_PI_2).abs(); /// /// assert!(abs_difference < 1e-10); /// ``` @@ -617,10 +617,10 @@ impl f64 { /// ``` /// use std::f64; /// - /// let f = f64::consts::PI / 4.0; + /// let f = f64::consts::FRAC_PI_4; /// /// // acos(cos(pi/4)) - /// let abs_difference = (f.cos().acos() - f64::consts::PI / 4.0).abs(); + /// let abs_difference = (f.cos().acos() - f64::consts::FRAC_PI_4).abs(); /// /// assert!(abs_difference < 1e-10); /// ``` @@ -661,7 +661,6 @@ impl f64 { /// ``` /// use std::f64; /// - /// let pi = f64::consts::PI; /// // Positive angles measured counter-clockwise /// // from positive x axis /// // -pi/4 radians (45 deg clockwise) @@ -672,8 +671,8 @@ impl f64 { /// let x2 = -3.0_f64; /// let y2 = 3.0_f64; /// - /// let abs_difference_1 = (y1.atan2(x1) - (-pi/4.0)).abs(); - /// let abs_difference_2 = (y2.atan2(x2) - 3.0*pi/4.0).abs(); + /// let abs_difference_1 = (y1.atan2(x1) - (-f64::consts::FRAC_PI_4)).abs(); + /// let abs_difference_2 = (y2.atan2(x2) - (3.0 * f64::consts::FRAC_PI_4)).abs(); /// /// assert!(abs_difference_1 < 1e-10); /// assert!(abs_difference_2 < 1e-10); @@ -692,7 +691,7 @@ impl f64 { /// ``` /// use std::f64; /// - /// let x = f64::consts::PI/4.0; + /// let x = f64::consts::FRAC_PI_4; /// let f = x.sin_cos(); /// /// let abs_difference_0 = (f.0 - x.sin()).abs(); @@ -759,7 +758,7 @@ impl f64 { /// /// let f = x.sinh(); /// // Solving sinh() at 1 gives `(e^2-1)/(2e)` - /// let g = (e*e - 1.0)/(2.0*e); + /// let g = ((e * e) - 1.0) / (2.0 * e); /// let abs_difference = (f - g).abs(); /// /// assert!(abs_difference < 1e-10); @@ -781,7 +780,7 @@ impl f64 { /// let x = 1.0_f64; /// let f = x.cosh(); /// // Solving cosh() at 1 gives this result - /// let g = (e*e + 1.0)/(2.0*e); + /// let g = ((e * e) + 1.0) / (2.0 * e); /// let abs_difference = (f - g).abs(); /// /// // Same result @@ -805,7 +804,7 @@ impl f64 { /// /// let f = x.tanh(); /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))` - /// let g = (1.0 - e.powi(-2))/(1.0 + e.powi(-2)); + /// let g = (1.0 - e.powi(-2)) / (1.0 + e.powi(-2)); /// let abs_difference = (f - g).abs(); /// /// assert!(abs_difference < 1.0e-10); @@ -834,7 +833,7 @@ impl f64 { if self == NEG_INFINITY { NEG_INFINITY } else { - (self + ((self * self) + 1.0).sqrt()).ln() + (self + ((self * self) + 1.0).sqrt()).ln().copysign(self) } } @@ -853,9 +852,10 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn acosh(self) -> f64 { - match self { - x if x < 1.0 => NAN, - x => (x + ((x * x) - 1.0).sqrt()).ln(), + if self < 1.0 { + NAN + } else { + (self + ((self * self) - 1.0).sqrt()).ln() } } @@ -1188,7 +1188,7 @@ mod tests { assert_eq!((-0f64).abs(), 0f64); assert_eq!((-1f64).abs(), 1f64); assert_eq!(NEG_INFINITY.abs(), INFINITY); - assert_eq!((1f64/NEG_INFINITY).abs(), 0f64); + assert_eq!((1f64 / NEG_INFINITY).abs(), 0f64); assert!(NAN.abs().is_nan()); } @@ -1200,7 +1200,7 @@ mod tests { assert_eq!((-0f64).signum(), -1f64); assert_eq!((-1f64).signum(), -1f64); assert_eq!(NEG_INFINITY.signum(), -1f64); - assert_eq!((1f64/NEG_INFINITY).signum(), -1f64); + assert_eq!((1f64 / NEG_INFINITY).signum(), -1f64); assert!(NAN.signum().is_nan()); } @@ -1212,7 +1212,7 @@ mod tests { assert!(!(-0f64).is_sign_positive()); assert!(!(-1f64).is_sign_positive()); assert!(!NEG_INFINITY.is_sign_positive()); - assert!(!(1f64/NEG_INFINITY).is_sign_positive()); + assert!(!(1f64 / NEG_INFINITY).is_sign_positive()); assert!(NAN.is_sign_positive()); assert!(!(-NAN).is_sign_positive()); } @@ -1225,7 +1225,7 @@ mod tests { assert!((-0f64).is_sign_negative()); assert!((-1f64).is_sign_negative()); assert!(NEG_INFINITY.is_sign_negative()); - assert!((1f64/NEG_INFINITY).is_sign_negative()); + assert!((1f64 / NEG_INFINITY).is_sign_negative()); assert!(!NAN.is_sign_negative()); assert!((-NAN).is_sign_negative()); } @@ -1434,6 +1434,8 @@ mod tests { assert_eq!(inf.asinh(), inf); assert_eq!(neg_inf.asinh(), neg_inf); assert!(nan.asinh().is_nan()); + assert!((-0.0f64).asinh().is_sign_negative()); + // issue 63271 assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64); assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 6e111f2423659..d7f4cc5d1fdaa 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -195,6 +195,12 @@ pub struct CString { /// [`from_ptr`]: #method.from_ptr #[derive(Hash)] #[stable(feature = "rust1", since = "1.0.0")] +// FIXME: +// `fn from` in `impl From<&CStr> for Box` current implementation relies +// on `CStr` being layout-compatible with `[u8]`. +// When attribute privacy is implemented, `CStr` should be annotated as `#[repr(transparent)]`. +// Anyway, `CStr` representation and layout are considered implementation detail, are +// not documented and must not be relied upon. pub struct CStr { // FIXME: this should not be represented with a DST slice but rather with // just a raw `c_char` along with some form of marker to make @@ -566,8 +572,8 @@ impl CString { /// use std::ffi::{CString, CStr}; /// /// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed"); - /// let c_str = c_string.as_c_str(); - /// assert_eq!(c_str, + /// let cstr = c_string.as_c_str(); + /// assert_eq!(cstr, /// CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed")); /// ``` #[inline] @@ -609,7 +615,7 @@ impl CString { } // Turns this `CString` into an empty string to prevent -// memory unsafe code from working by accident. Inline +// memory-unsafe code from working by accident. Inline // to prevent LLVM from optimizing it away in debug builds. #[stable(feature = "cstring_drop", since = "1.13.0")] impl Drop for CString { @@ -929,8 +935,10 @@ impl CStr { /// Wraps a raw C string with a safe C string wrapper. /// /// This function will wrap the provided `ptr` with a `CStr` wrapper, which - /// allows inspection and interoperation of non-owned C strings. This method - /// is unsafe for a number of reasons: + /// allows inspection and interoperation of non-owned C strings. The total + /// size of the raw C string must be smaller than `isize::MAX` **bytes** + /// in memory due to calling the `slice::from_raw_parts` function. + /// This method is unsafe for a number of reasons: /// /// * There is no guarantee to the validity of `ptr`. /// * The returned lifetime is not guaranteed to be the actual lifetime of @@ -988,8 +996,8 @@ impl CStr { /// ``` /// use std::ffi::CStr; /// - /// let c_str = CStr::from_bytes_with_nul(b"hello"); - /// assert!(c_str.is_err()); + /// let cstr = CStr::from_bytes_with_nul(b"hello"); + /// assert!(cstr.is_err()); /// ``` /// /// Creating a `CStr` with an interior nul byte is an error: @@ -997,8 +1005,8 @@ impl CStr { /// ``` /// use std::ffi::CStr; /// - /// let c_str = CStr::from_bytes_with_nul(b"he\0llo\0"); - /// assert!(c_str.is_err()); + /// let cstr = CStr::from_bytes_with_nul(b"he\0llo\0"); + /// assert!(cstr.is_err()); /// ``` #[stable(feature = "cstr_from_bytes", since = "1.10.0")] pub fn from_bytes_with_nul(bytes: &[u8]) @@ -1105,8 +1113,8 @@ impl CStr { /// ``` /// use std::ffi::CStr; /// - /// let c_str = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); - /// assert_eq!(c_str.to_bytes(), b"foo"); + /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); + /// assert_eq!(cstr.to_bytes(), b"foo"); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -1131,8 +1139,8 @@ impl CStr { /// ``` /// use std::ffi::CStr; /// - /// let c_str = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); - /// assert_eq!(c_str.to_bytes_with_nul(), b"foo\0"); + /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); + /// assert_eq!(cstr.to_bytes_with_nul(), b"foo\0"); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -1158,8 +1166,8 @@ impl CStr { /// ``` /// use std::ffi::CStr; /// - /// let c_str = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); - /// assert_eq!(c_str.to_str(), Ok("foo")); + /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); + /// assert_eq!(cstr.to_str(), Ok("foo")); /// ``` #[stable(feature = "cstr_to_str", since = "1.4.0")] pub fn to_str(&self) -> Result<&str, str::Utf8Error> { @@ -1199,9 +1207,9 @@ impl CStr { /// use std::borrow::Cow; /// use std::ffi::CStr; /// - /// let c_str = CStr::from_bytes_with_nul(b"Hello World\0") + /// let cstr = CStr::from_bytes_with_nul(b"Hello World\0") /// .expect("CStr::from_bytes_with_nul failed"); - /// assert_eq!(c_str.to_string_lossy(), Cow::Borrowed("Hello World")); + /// assert_eq!(cstr.to_string_lossy(), Cow::Borrowed("Hello World")); /// ``` /// /// Calling `to_string_lossy` on a `CStr` containing invalid UTF-8: @@ -1210,10 +1218,10 @@ impl CStr { /// use std::borrow::Cow; /// use std::ffi::CStr; /// - /// let c_str = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0") + /// let cstr = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0") /// .expect("CStr::from_bytes_with_nul failed"); /// assert_eq!( - /// c_str.to_string_lossy(), + /// cstr.to_string_lossy(), /// Cow::Owned(String::from("Hello �World")) as Cow<'_, str> /// ); /// ``` diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 54e1c876f4caa..6cf062d4f30c0 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -97,6 +97,12 @@ pub struct OsString { /// [`String`]: ../string/struct.String.html /// [conversions]: index.html#conversions #[stable(feature = "rust1", since = "1.0.0")] +// FIXME: +// `OsStr::from_inner` current implementation relies +// on `OsStr` being layout-compatible with `Slice`. +// When attribute privacy is implemented, `OsStr` should be annotated as `#[repr(transparent)]`. +// Anyway, `OsStr` representation and layout are considered implementation detail, are +// not documented and must not be relied upon. pub struct OsStr { inner: Slice } @@ -227,7 +233,7 @@ impl OsString { /// ``` /// use std::ffi::OsString; /// - /// let mut os_string = OsString::with_capacity(10); + /// let os_string = OsString::with_capacity(10); /// assert!(os_string.capacity() >= 10); /// ``` #[stable(feature = "osstring_simple_functions", since = "1.9.0")] @@ -610,7 +616,7 @@ impl OsStr { /// Note that this does **not** return the number of bytes in the string in /// OS string form. /// - /// The length returned is that of the underlying storage used by `OsStr`; + /// The length returned is that of the underlying storage used by `OsStr`. /// As discussed in the [`OsString`] introduction, [`OsString`] and `OsStr` /// store strings in a form best suited for cheap inter-conversion between /// native-platform and Rust string forms, which may differ significantly diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 5f76875bd66c4..fc26dcb321148 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -114,6 +114,9 @@ pub struct Metadata(fs_imp::FileAttr); /// information like the entry's path and possibly other metadata can be /// learned. /// +/// The order in which this iterator returns entries is platform and filesystem +/// dependent. +/// /// # Errors /// /// This [`io::Result`] will be an [`Err`] if there's some sort of intermittent @@ -1956,11 +1959,15 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// # Platform-specific behavior /// /// This function currently corresponds to the `opendir` function on Unix -/// and the `FindFirstFile` function on Windows. +/// and the `FindFirstFile` function on Windows. Advancing the iterator +/// currently corresponds to `readdir` on Unix and `FindNextFile` on Windows. /// Note that, this [may change in the future][changes]. /// /// [changes]: ../io/index.html#platform-specific-behavior /// +/// The order in which this iterator returns entries is platform and filesystem +/// dependent. +/// /// # Errors /// /// This function will return an error in the following situations, but is not @@ -1993,6 +2000,25 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// Ok(()) /// } /// ``` +/// +/// ```rust,no_run +/// use std::{fs, io}; +/// +/// fn main() -> io::Result<()> { +/// let mut entries = fs::read_dir(".")? +/// .map(|res| res.map(|e| e.path())) +/// .collect::, io::Error>>()?; +/// +/// // The order in which `read_dir` returns entries is not guaranteed. If reproducible +/// // ordering is required the entries should be explicitly sorted. +/// +/// entries.sort(); +/// +/// // The entries have now been sorted by their path. +/// +/// Ok(()) +/// } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn read_dir>(path: P) -> io::Result { fs_imp::readdir(path.as_ref()).map(ReadDir) @@ -2144,7 +2170,7 @@ mod tests { use crate::sys_common::io::test::{TempDir, tmpdir}; use crate::thread; - use rand::{rngs::StdRng, FromEntropy, RngCore}; + use rand::{rngs::StdRng, RngCore, SeedableRng}; #[cfg(windows)] use crate::os::windows::fs::{symlink_dir, symlink_file}; @@ -3086,8 +3112,10 @@ mod tests { #[cfg(windows)] let invalid_options = 87; // ERROR_INVALID_PARAMETER - #[cfg(unix)] + #[cfg(all(unix, not(target_os = "vxworks")))] let invalid_options = "Invalid argument"; + #[cfg(target_os = "vxworks")] + let invalid_options = "invalid argument"; // Test various combinations of creation modes and access modes. // diff --git a/src/libstd/future.rs b/src/libstd/future.rs index 0406549ff0791..c65f71fb1a4e2 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -26,6 +26,7 @@ pub fn from_generator>(x: T) -> impl Future>(T); // We rely on the fact that async/await futures are immovable in order to create diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index aaf628e6c260f..9593a1bae0a3c 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -9,21 +9,21 @@ use crate::io::{self, Initializer, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom, IoSliceMut}; use crate::memchr; -/// The `BufReader` struct adds buffering to any reader. +/// The `BufReader` struct adds buffering to any reader. /// /// It can be excessively inefficient to work directly with a [`Read`] instance. /// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`] -/// results in a system call. A `BufReader` performs large, infrequent reads on +/// results in a system call. A `BufReader` performs large, infrequent reads on /// the underlying [`Read`] and maintains an in-memory buffer of the results. /// -/// `BufReader` can improve the speed of programs that make *small* and +/// `BufReader` can improve the speed of programs that make *small* and /// *repeated* read calls to the same file or network socket. It does not /// help when reading very large amounts at once, or reading just one or a few /// times. It also provides no advantage when reading from a source that is /// already in memory, like a `Vec`. /// -/// When the `BufReader` is dropped, the contents of its buffer will be -/// discarded. Creating multiple instances of a `BufReader` on the same +/// When the `BufReader` is dropped, the contents of its buffer will be +/// discarded. Creating multiple instances of a `BufReader` on the same /// stream can cause data loss. /// /// [`Read`]: ../../std/io/trait.Read.html @@ -56,7 +56,7 @@ pub struct BufReader { } impl BufReader { - /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB, + /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB, /// but may change in the future. /// /// # Examples @@ -76,7 +76,7 @@ impl BufReader { BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) } - /// Creates a new `BufReader` with the specified buffer capacity. + /// Creates a new `BufReader` with the specified buffer capacity. /// /// # Examples /// @@ -177,7 +177,7 @@ impl BufReader { &self.buf[self.pos..self.cap] } - /// Unwraps this `BufReader`, returning the underlying reader. + /// Unwraps this `BufReader`, returning the underlying reader. /// /// Note that any leftover data in the internal buffer is lost. /// @@ -304,7 +304,7 @@ impl Seek for BufReader { /// Seek to an offset, in bytes, in the underlying reader. /// /// The position used for seeking with `SeekFrom::Current(_)` is the - /// position the underlying reader would be at if the `BufReader` had no + /// position the underlying reader would be at if the `BufReader` had no /// internal buffer. /// /// Seeking always discards the internal buffer, even if the seek position @@ -355,19 +355,20 @@ impl Seek for BufReader { /// It can be excessively inefficient to work directly with something that /// implements [`Write`]. For example, every call to /// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A -/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying +/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying /// writer in large, infrequent batches. /// -/// `BufWriter` can improve the speed of programs that make *small* and +/// `BufWriter` can improve the speed of programs that make *small* and /// *repeated* write calls to the same file or network socket. It does not /// help when writing very large amounts at once, or writing just one or a few /// times. It also provides no advantage when writing to a destination that is /// in memory, like a `Vec`. /// -/// When the `BufWriter` is dropped, the contents of its buffer will be written -/// out. However, any errors that happen in the process of flushing the buffer -/// when the writer is dropped will be ignored. Code that wishes to handle such -/// errors must manually call [`flush`] before the writer is dropped. +/// It is critical to call [`flush`] before `BufWriter` is dropped. Though +/// dropping will attempt to flush the the contents of the buffer, any errors +/// that happen in the process of dropping will be ignored. Calling ['flush'] +/// ensures that the buffer is empty and thus dropping will not even attempt +/// file operations. /// /// # Examples /// @@ -386,7 +387,7 @@ impl Seek for BufReader { /// /// Because we're not buffering, we write each one in turn, incurring the /// overhead of a system call per byte written. We can fix this with a -/// `BufWriter`: +/// `BufWriter`: /// /// ```no_run /// use std::io::prelude::*; @@ -398,11 +399,12 @@ impl Seek for BufReader { /// for i in 0..10 { /// stream.write(&[i+1]).unwrap(); /// } +/// stream.flush().unwrap(); /// ``` /// -/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped -/// together by the buffer, and will all be written out in one system call when -/// the `stream` is dropped. +/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped +/// together by the buffer and will all be written out in one system call when +/// the `stream` is flushed. /// /// [`Write`]: ../../std/io/trait.Write.html /// [`TcpStream::write`]: ../../std/net/struct.TcpStream.html#method.write @@ -447,7 +449,7 @@ pub struct BufWriter { pub struct IntoInnerError(W, Error); impl BufWriter { - /// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB, + /// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB, /// but may change in the future. /// /// # Examples @@ -463,7 +465,7 @@ impl BufWriter { BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) } - /// Creates a new `BufWriter` with the specified buffer capacity. + /// Creates a new `BufWriter` with the specified buffer capacity. /// /// # Examples /// @@ -564,7 +566,7 @@ impl BufWriter { &self.buf } - /// Unwraps this `BufWriter`, returning the underlying writer. + /// Unwraps this `BufWriter`, returning the underlying writer. /// /// The buffer is written out before returning the writer. /// diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index f2b6ce6feb295..be364a10593da 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -353,12 +353,17 @@ fn append_to_string(buf: &mut String, f: F) -> Result // Because we're extending the buffer with uninitialized data for trusted // readers, we need to make sure to truncate that if any of this panics. fn read_to_end(r: &mut R, buf: &mut Vec) -> Result { - read_to_end_with_reservation(r, buf, 32) + read_to_end_with_reservation(r, buf, |_| 32) } -fn read_to_end_with_reservation(r: &mut R, - buf: &mut Vec, - reservation_size: usize) -> Result +fn read_to_end_with_reservation( + r: &mut R, + buf: &mut Vec, + mut reservation_size: F, +) -> Result +where + R: Read + ?Sized, + F: FnMut(&R) -> usize, { let start_len = buf.len(); let mut g = Guard { len: buf.len(), buf: buf }; @@ -366,7 +371,15 @@ fn read_to_end_with_reservation(r: &mut R, loop { if g.len == g.buf.len() { unsafe { - g.buf.reserve(reservation_size); + // FIXME(danielhenrymantilla): #42788 + // + // - This creates a (mut) reference to a slice of + // _uninitialized_ integers, which is **undefined behavior** + // + // - Only the standard library gets to soundly "ignore" this, + // based on its privileged knowledge of unstable rustc + // internals; + g.buf.reserve(reservation_size(r)); let capacity = g.buf.capacity(); g.buf.set_len(capacity); r.initializer().initialize(&mut g.buf[g.len..]); @@ -2253,9 +2266,10 @@ impl Read for Take { } fn read_to_end(&mut self, buf: &mut Vec) -> Result { - let reservation_size = cmp::min(self.limit, 32) as usize; - - read_to_end_with_reservation(self, buf, reservation_size) + // Pass in a reservation_size closure that respects the current value + // of limit for each read. If we hit the read limit, this prevents the + // final zero-byte read from allocating again. + read_to_end_with_reservation(self, buf, |self_| cmp::min(self_.limit, 32) as usize) } } @@ -2312,10 +2326,10 @@ impl Iterator for Bytes { /// An iterator over the contents of an instance of `BufRead` split on a /// particular byte. /// -/// This struct is generally created by calling [`split`][split] on a -/// `BufRead`. Please see the documentation of `split()` for more details. +/// This struct is generally created by calling [`split`] on a `BufRead`. +/// Please see the documentation of [`split`] for more details. /// -/// [split]: trait.BufRead.html#method.split +/// [`split`]: trait.BufRead.html#method.split #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Split { @@ -2344,10 +2358,10 @@ impl Iterator for Split { /// An iterator over the lines of an instance of `BufRead`. /// -/// This struct is generally created by calling [`lines`][lines] on a -/// `BufRead`. Please see the documentation of `lines()` for more details. +/// This struct is generally created by calling [`lines`] on a `BufRead`. +/// Please see the documentation of [`lines`] for more details. /// -/// [lines]: trait.BufRead.html#method.lines +/// [`lines`]: trait.BufRead.html#method.lines #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Lines { @@ -2378,6 +2392,7 @@ impl Iterator for Lines { #[cfg(test)] mod tests { + use crate::cmp; use crate::io::prelude::*; use super::{Cursor, SeekFrom, repeat}; use crate::io::{self, IoSlice, IoSliceMut}; @@ -2651,6 +2666,49 @@ mod tests { Ok(()) } + // A simple example reader which uses the default implementation of + // read_to_end. + struct ExampleSliceReader<'a> { + slice: &'a [u8], + } + + impl<'a> Read for ExampleSliceReader<'a> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let len = cmp::min(self.slice.len(), buf.len()); + buf[..len].copy_from_slice(&self.slice[..len]); + self.slice = &self.slice[len..]; + Ok(len) + } + } + + #[test] + fn test_read_to_end_capacity() -> io::Result<()> { + let input = &b"foo"[..]; + + // read_to_end() generally needs to over-allocate, both for efficiency + // and so that it can distinguish EOF. Assert that this is the case + // with this simple ExampleSliceReader struct, which uses the default + // implementation of read_to_end. Even though vec1 is allocated with + // exactly enough capacity for the read, read_to_end will allocate more + // space here. + let mut vec1 = Vec::with_capacity(input.len()); + ExampleSliceReader { slice: input }.read_to_end(&mut vec1)?; + assert_eq!(vec1.len(), input.len()); + assert!(vec1.capacity() > input.len(), "allocated more"); + + // However, std::io::Take includes an implementation of read_to_end + // that will not allocate when the limit has already been reached. In + // this case, vec2 never grows. + let mut vec2 = Vec::with_capacity(input.len()); + ExampleSliceReader { slice: input } + .take(input.len() as u64) + .read_to_end(&mut vec2)?; + assert_eq!(vec2.len(), input.len()); + assert_eq!(vec2.capacity(), input.len(), "did not allocate more"); + + Ok(()) + } + #[test] fn io_slice_mut_advance() { let mut buf1 = [1; 8]; diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 990c0eb8955e4..c798ee0e2209a 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -201,9 +201,9 @@ pub struct StdinLock<'a> { /// /// Each handle returned is a reference to a shared global buffer whose access /// is synchronized via a mutex. If you need more explicit control over -/// locking, see the [`lock() method`][lock]. +/// locking, see the [`Stdin::lock`] method. /// -/// [lock]: struct.Stdin.html#method.lock +/// [`Stdin::lock`]: struct.Stdin.html#method.lock /// /// ### Note: Windows Portability Consideration /// When operating in a console, the Windows implementation of this stream does not support @@ -425,9 +425,9 @@ pub struct StdoutLock<'a> { /// /// Each handle returned is a reference to a shared global buffer whose access /// is synchronized via a mutex. If you need more explicit control over -/// locking, see the [Stdout::lock] method. +/// locking, see the [`Stdout::lock`] method. /// -/// [Stdout::lock]: struct.Stdout.html#method.lock +/// [`Stdout::lock`]: struct.Stdout.html#method.lock /// /// ### Note: Windows Portability Consideration /// When operating in a console, the Windows implementation of this stream does not support diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index f5018485ef7bc..a8dfe924fdf06 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -681,14 +681,15 @@ mod while_keyword { } /// # break; /// } /// -/// let mut i = 0; +/// let mut i = 1; /// loop { /// println!("i is {}", i); -/// if i > 10 { +/// if i > 100 { /// break; /// } -/// i += 1; +/// i *= 2; /// } +/// assert_eq!(i, 128); /// ``` /// /// Unlike the other kinds of loops in Rust (`while`, `while let`, and `for`), loops can be used as @@ -984,7 +985,6 @@ mod where_keyword { } // 2018 Edition keywords -#[unstable(feature = "async_await", issue = "50547")] #[doc(keyword = "async")] // /// Return a [`Future`] instead of blocking the current thread. @@ -995,7 +995,6 @@ mod where_keyword { } /// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 mod async_keyword { } -#[unstable(feature = "async_await", issue = "50547")] #[doc(keyword = "await")] // /// Suspend execution until the result of a [`Future`] is ready. diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index cfee49a7b555c..af6cb656444d4 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -228,7 +228,6 @@ // std is implemented with unstable features, many of which are internal // compiler details that will never be stable // NB: the following list is sorted to minimize merge conflicts. -#![cfg_attr(not(bootstrap), feature(__rust_unstable_column))] #![feature(alloc_error_handler)] #![feature(alloc_layout_extra)] #![feature(allocator_api)] @@ -238,18 +237,18 @@ #![feature(arbitrary_self_types)] #![feature(array_error_internals)] #![feature(asm)] -#![feature(bind_by_move_pattern_guards)] +#![feature(associated_type_bounds)] #![feature(box_syntax)] #![feature(c_variadic)] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] #![feature(char_error_internals)] -#![feature(checked_duration_since)] #![feature(clamp)] #![feature(compiler_builtins_lib)] #![feature(concat_idents)] #![feature(const_cstr_unchecked)] #![feature(const_raw_ptr_deref)] +#![feature(container_error_extra)] #![feature(core_intrinsics)] #![feature(custom_test_frameworks)] #![feature(doc_alias)] @@ -278,7 +277,6 @@ #![feature(log_syntax)] #![feature(maybe_uninit_ref)] #![feature(maybe_uninit_slice)] -#![feature(mem_take)] #![feature(needs_panic_runtime)] #![feature(never_type)] #![feature(nll)] @@ -306,7 +304,6 @@ #![feature(str_internals)] #![feature(test)] #![feature(thread_local)] -#![feature(todo_macro)] #![feature(toowned_clone_into)] #![feature(trace_macros)] #![feature(try_reserve)] @@ -326,12 +323,6 @@ use prelude::v1::*; // Access to Bencher, etc. #[cfg(test)] extern crate test; -// Re-export a few macros from core -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::{assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::{unreachable, unimplemented, write, writeln, r#try, todo}; - #[allow(unused_imports)] // macros from `alloc` are not used on all platforms #[macro_use] extern crate alloc as alloc_crate; @@ -458,6 +449,7 @@ pub mod f64; #[macro_use] pub mod thread; pub mod ascii; +pub mod backtrace; pub mod collections; pub mod env; pub mod error; @@ -516,33 +508,50 @@ mod std_detect; #[cfg(not(test))] pub use std_detect::detect; -// Document built-in macros in the crate root for consistency with libcore and existing tradition. -// FIXME: Attribute and derive macros are not reexported because rustdoc renders them -// as reexports rather than as macros, and that's not what we want. -#[cfg(rustdoc)] +// Re-export macros defined in libcore. +#[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated, deprecated_in_future)] +pub use core::{ + // Stable + assert_eq, + assert_ne, + debug_assert_eq, + debug_assert_ne, + debug_assert, + r#try, + unimplemented, + unreachable, + write, + writeln, + // Unstable + todo, +}; + +// Re-export built-in macros defined through libcore. #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -pub use crate::prelude::v1::{ - __rust_unstable_column, - asm, +pub use core::{ + // Stable assert, cfg, column, compile_error, concat, - concat_idents, env, file, format_args, - format_args_nl, - global_asm, include, include_bytes, include_str, line, - log_syntax, module_path, option_env, stringify, + // Unstable + asm, + concat_idents, + format_args_nl, + global_asm, + log_syntax, trace_macros, }; diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 839b4c5656a09..cbeaf20b13adc 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -53,20 +53,20 @@ /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] -#[allow_internal_unstable(__rust_unstable_column, libstd_sys_internals)] +#[allow_internal_unstable(libstd_sys_internals)] macro_rules! panic { () => ({ $crate::panic!("explicit panic") }); ($msg:expr) => ({ - $crate::rt::begin_panic($msg, &(file!(), line!(), __rust_unstable_column!())) + $crate::rt::begin_panic($msg, &($crate::file!(), $crate::line!(), $crate::column!())) }); ($msg:expr,) => ({ $crate::panic!($msg) }); ($fmt:expr, $($arg:tt)+) => ({ - $crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+), - &(file!(), line!(), __rust_unstable_column!())) + $crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+), + &($crate::file!(), $crate::line!(), $crate::column!())) }); } @@ -113,13 +113,13 @@ macro_rules! panic { #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(print_internals)] macro_rules! print { - ($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*))); + ($($arg:tt)*) => ($crate::io::_print($crate::format_args!($($arg)*))); } /// Prints to the standard output, with a newline. /// /// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone -/// (no additional CARRIAGE RETURN (`\r`/`U+000D`). +/// (no additional CARRIAGE RETURN (`\r`/`U+000D`)). /// /// Use the [`format!`] syntax to write data to the standard output. /// See [`std::fmt`] for more information. @@ -147,7 +147,7 @@ macro_rules! print { macro_rules! println { () => ($crate::print!("\n")); ($($arg:tt)*) => ({ - $crate::io::_print(format_args_nl!($($arg)*)); + $crate::io::_print($crate::format_args_nl!($($arg)*)); }) } @@ -176,7 +176,7 @@ macro_rules! println { #[stable(feature = "eprint", since = "1.19.0")] #[allow_internal_unstable(print_internals)] macro_rules! eprint { - ($($arg:tt)*) => ($crate::io::_eprint(format_args!($($arg)*))); + ($($arg:tt)*) => ($crate::io::_eprint($crate::format_args!($($arg)*))); } /// Prints to the standard error, with a newline. @@ -206,7 +206,7 @@ macro_rules! eprint { macro_rules! eprintln { () => ($crate::eprint!("\n")); ($($arg:tt)*) => ({ - $crate::io::_eprint(format_args_nl!($($arg)*)); + $crate::io::_eprint($crate::format_args_nl!($($arg)*)); }) } @@ -337,7 +337,7 @@ macro_rules! eprintln { #[stable(feature = "dbg_macro", since = "1.32.0")] macro_rules! dbg { () => { - $crate::eprintln!("[{}:{}]", file!(), line!()); + $crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!()); }; ($val:expr) => { // Use of `match` here is intentional because it affects the lifetimes @@ -345,7 +345,7 @@ macro_rules! dbg { match $val { tmp => { $crate::eprintln!("[{}:{}] {} = {:#?}", - file!(), line!(), stringify!($val), &tmp); + $crate::file!(), $crate::line!(), $crate::stringify!($val), &tmp); tmp } } diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index ca86a175058b5..f9255b82fc83e 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -217,11 +217,9 @@ impl SocketAddr { /// ``` /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; /// - /// fn main() { - /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); - /// assert_eq!(socket.is_ipv4(), true); - /// assert_eq!(socket.is_ipv6(), false); - /// } + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// assert_eq!(socket.is_ipv4(), true); + /// assert_eq!(socket.is_ipv6(), false); /// ``` #[stable(feature = "sockaddr_checker", since = "1.16.0")] pub fn is_ipv4(&self) -> bool { @@ -244,12 +242,9 @@ impl SocketAddr { /// ``` /// use std::net::{IpAddr, Ipv6Addr, SocketAddr}; /// - /// fn main() { - /// let socket = SocketAddr::new( - /// IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080); - /// assert_eq!(socket.is_ipv4(), false); - /// assert_eq!(socket.is_ipv6(), true); - /// } + /// let socket = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080); + /// assert_eq!(socket.is_ipv4(), false); + /// assert_eq!(socket.is_ipv6(), true); /// ``` #[stable(feature = "sockaddr_checker", since = "1.16.0")] pub fn is_ipv6(&self) -> bool { diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 6b504056e5f87..70b68d1348550 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -197,11 +197,8 @@ impl IpAddr { /// /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// - /// fn main() { - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), - /// true); - /// } + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true); /// ``` pub fn is_global(&self) -> bool { match self { @@ -251,11 +248,11 @@ impl IpAddr { /// /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// - /// fn main() { - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)) - /// .is_documentation(), true); - /// } + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_documentation(), + /// true + /// ); /// ``` pub fn is_documentation(&self) -> bool { match self { @@ -275,11 +272,8 @@ impl IpAddr { /// ``` /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// - /// fn main() { - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), - /// false); - /// } + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false); /// ``` #[stable(feature = "ipaddr_checker", since = "1.16.0")] pub fn is_ipv4(&self) -> bool { @@ -300,11 +294,8 @@ impl IpAddr { /// ``` /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// - /// fn main() { - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), - /// true); - /// } + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true); /// ``` #[stable(feature = "ipaddr_checker", since = "1.16.0")] pub fn is_ipv6(&self) -> bool { @@ -526,48 +517,46 @@ impl Ipv4Addr { /// /// use std::net::Ipv4Addr; /// - /// fn main() { - /// // private addresses are not global - /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); - /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); - /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); + /// // private addresses are not global + /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); + /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); /// - /// // the 0.0.0.0/8 block is not global - /// assert_eq!(Ipv4Addr::new(0, 1, 2, 3).is_global(), false); - /// // in particular, the unspecified address is not global - /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false); + /// // the 0.0.0.0/8 block is not global + /// assert_eq!(Ipv4Addr::new(0, 1, 2, 3).is_global(), false); + /// // in particular, the unspecified address is not global + /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false); /// - /// // the loopback address is not global - /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_global(), false); + /// // the loopback address is not global + /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_global(), false); /// - /// // link local addresses are not global - /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false); + /// // link local addresses are not global + /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false); /// - /// // the broadcast address is not global - /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_global(), false); + /// // the broadcast address is not global + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_global(), false); /// - /// // the broadcast address is not global - /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false); - /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false); - /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false); + /// // the broadcast address is not global + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false); + /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false); + /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false); /// - /// // shared addresses are not global - /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false); + /// // shared addresses are not global + /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false); /// - /// // addresses reserved for protocol assignment are not global - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_global(), false); - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_global(), false); + /// // addresses reserved for protocol assignment are not global + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_global(), false); + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_global(), false); /// - /// // addresses reserved for future use are not global - /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false); + /// // addresses reserved for future use are not global + /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false); /// - /// // addresses reserved for network devices benchmarking are not global - /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false); + /// // addresses reserved for network devices benchmarking are not global + /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false); /// - /// // All the other addresses are global - /// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true); - /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); - /// } + /// // All the other addresses are global + /// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true); + /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); /// ``` pub fn is_global(&self) -> bool { // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two @@ -600,11 +589,9 @@ impl Ipv4Addr { /// #![feature(ip)] /// use std::net::Ipv4Addr; /// - /// fn main() { - /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true); - /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); - /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); - /// } + /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true); + /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); + /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); /// ``` pub fn is_shared(&self) -> bool { self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) @@ -631,14 +618,12 @@ impl Ipv4Addr { /// #![feature(ip)] /// use std::net::Ipv4Addr; /// - /// fn main() { - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_ietf_protocol_assignment(), true); - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 8).is_ietf_protocol_assignment(), true); - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 9).is_ietf_protocol_assignment(), true); - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_ietf_protocol_assignment(), true); - /// assert_eq!(Ipv4Addr::new(192, 0, 1, 0).is_ietf_protocol_assignment(), false); - /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false); - /// } + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 8).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 9).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(192, 0, 1, 0).is_ietf_protocol_assignment(), false); + /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false); /// ``` pub fn is_ietf_protocol_assignment(&self) -> bool { self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 @@ -658,12 +643,10 @@ impl Ipv4Addr { /// #![feature(ip)] /// use std::net::Ipv4Addr; /// - /// fn main() { - /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false); - /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true); - /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); - /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); - /// } + /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false); + /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true); + /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); + /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); /// ``` pub fn is_benchmarking(&self) -> bool { self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 @@ -690,15 +673,12 @@ impl Ipv4Addr { /// #![feature(ip)] /// use std::net::Ipv4Addr; /// - /// fn main() { - /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true); - /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true); + /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true); + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true); /// - /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false); - /// // The broadcast address is not considered as reserved for future use by this - /// // implementation - /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); - /// } + /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false); + /// // The broadcast address is not considered as reserved for future use by this implementation + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); /// ``` pub fn is_reserved(&self) -> bool { self.octets()[0] & 240 == 240 && !self.is_broadcast() @@ -788,8 +768,10 @@ impl Ipv4Addr { /// ``` /// use std::net::{Ipv4Addr, Ipv6Addr}; /// - /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), - /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767)); + /// assert_eq!( + /// Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767) + /// ); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_ipv6_compatible(&self) -> Ipv6Addr { @@ -1161,11 +1143,9 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false); - /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true); - /// } + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true); /// ``` pub fn is_global(&self) -> bool { match self.multicast_scope() { @@ -1189,11 +1169,8 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), - /// false); - /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); - /// } + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); + /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); /// ``` pub fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 @@ -1223,21 +1200,19 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// fn main() { - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local_strict()); + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); + /// assert!(ip.is_unicast_link_local_strict()); /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); - /// assert!(ip.is_unicast_link_local_strict()); + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); + /// assert!(ip.is_unicast_link_local_strict()); /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); - /// assert!(!ip.is_unicast_link_local_strict()); - /// assert!(ip.is_unicast_link_local()); + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); + /// assert!(!ip.is_unicast_link_local_strict()); + /// assert!(ip.is_unicast_link_local()); /// - /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); - /// assert!(!ip.is_unicast_link_local_strict()); - /// assert!(ip.is_unicast_link_local()); - /// } + /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); + /// assert!(!ip.is_unicast_link_local_strict()); + /// assert!(ip.is_unicast_link_local()); /// ``` /// /// # See also @@ -1284,21 +1259,19 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// fn main() { - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local()); + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); + /// assert!(ip.is_unicast_link_local()); /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); - /// assert!(ip.is_unicast_link_local()); + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); + /// assert!(ip.is_unicast_link_local()); /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local()); - /// assert!(!ip.is_unicast_link_local_strict()); + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); + /// assert!(ip.is_unicast_link_local()); + /// assert!(!ip.is_unicast_link_local_strict()); /// - /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local()); - /// assert!(!ip.is_unicast_link_local_strict()); - /// } + /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); + /// assert!(ip.is_unicast_link_local()); + /// assert!(!ip.is_unicast_link_local_strict()); /// ``` /// /// # See also @@ -1336,11 +1309,11 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_site_local(), - /// false); - /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true); - /// } + /// assert_eq!( + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_site_local(), + /// false + /// ); + /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true); /// ``` /// /// # Warning @@ -1369,11 +1342,8 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), - /// false); - /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); - /// } + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); /// ``` pub fn is_documentation(&self) -> bool { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) @@ -1407,11 +1377,8 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), - /// true); - /// } + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true); /// ``` pub fn is_unicast_global(&self) -> bool { !self.is_multicast() @@ -1431,11 +1398,11 @@ impl Ipv6Addr { /// /// use std::net::{Ipv6Addr, Ipv6MulticastScope}; /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(), - /// Some(Ipv6MulticastScope::Global)); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); - /// } + /// assert_eq!( + /// Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(), + /// Some(Ipv6MulticastScope::Global) + /// ); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); /// ``` pub fn multicast_scope(&self) -> Option { if self.is_multicast() { diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index cdffa390223a2..d8b6fb6da9395 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -1597,7 +1597,8 @@ mod tests { // FIXME: re-enabled openbsd tests once their socket timeout code // no longer has rounding errors. - #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd"), ignore)] + // VxWorks ignores SO_SNDTIMEO. + #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)] #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 #[test] fn timeouts() { diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index c430e103951f1..46bbd8855deda 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -185,7 +185,6 @@ impl UdpSocket { /// # Examples /// /// ```no_run - /// #![feature(udp_peer_addr)] /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; /// /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); @@ -199,14 +198,13 @@ impl UdpSocket { /// [`NotConnected`]: ../../std/io/enum.ErrorKind.html#variant.NotConnected /// /// ```no_run - /// #![feature(udp_peer_addr)] /// use std::net::UdpSocket; /// /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); /// assert_eq!(socket.peer_addr().unwrap_err().kind(), /// ::std::io::ErrorKind::NotConnected); /// ``` - #[unstable(feature = "udp_peer_addr", issue = "59127")] + #[stable(feature = "udp_peer_addr", since = "1.40.0")] pub fn peer_addr(&self) -> io::Result { self.0.peer_addr() } @@ -1026,7 +1024,8 @@ mod tests { // FIXME: re-enabled openbsd/netbsd tests once their socket timeout code // no longer has rounding errors. - #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd"), ignore)] + // VxWorks ignores SO_SNDTIMEO. + #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)] #[test] fn timeouts() { let addr = next_test_ip4(); diff --git a/src/libstd/os/raw/mod.rs b/src/libstd/os/raw/mod.rs index 0761c50f4b229..611a1709c8d91 100644 --- a/src/libstd/os/raw/mod.rs +++ b/src/libstd/os/raw/mod.rs @@ -8,8 +8,7 @@ #![stable(feature = "raw_os", since = "1.1.0")] -#[cfg_attr(bootstrap, doc(include = "os/raw/char.md"))] -#[cfg_attr(not(bootstrap), doc(include = "char.md"))] +#[doc(include = "char.md")] #[cfg(any(all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "hexagon", @@ -33,8 +32,7 @@ target_arch = "powerpc")), all(target_os = "fuchsia", target_arch = "aarch64")))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8; -#[cfg_attr(bootstrap, doc(include = "os/raw/char.md"))] -#[cfg_attr(not(bootstrap), doc(include = "char.md"))] +#[doc(include = "char.md")] #[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "hexagon", @@ -58,51 +56,37 @@ target_arch = "powerpc")), all(target_os = "fuchsia", target_arch = "aarch64"))))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8; -#[cfg_attr(bootstrap, doc(include = "os/raw/schar.md"))] -#[cfg_attr(not(bootstrap), doc(include = "schar.md"))] +#[doc(include = "schar.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8; -#[cfg_attr(bootstrap, doc(include = "os/raw/uchar.md"))] -#[cfg_attr(not(bootstrap), doc(include = "uchar.md"))] +#[doc(include = "uchar.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8; -#[cfg_attr(bootstrap, doc(include = "os/raw/short.md"))] -#[cfg_attr(not(bootstrap), doc(include = "short.md"))] +#[doc(include = "short.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_short = i16; -#[cfg_attr(bootstrap, doc(include = "os/raw/ushort.md"))] -#[cfg_attr(not(bootstrap), doc(include = "ushort.md"))] +#[doc(include = "ushort.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ushort = u16; -#[cfg_attr(bootstrap, doc(include = "os/raw/int.md"))] -#[cfg_attr(not(bootstrap), doc(include = "int.md"))] +#[doc(include = "int.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_int = i32; -#[cfg_attr(bootstrap, doc(include = "os/raw/uint.md"))] -#[cfg_attr(not(bootstrap), doc(include = "uint.md"))] +#[doc(include = "uint.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_uint = u32; -#[cfg_attr(bootstrap, doc(include = "os/raw/long.md"))] -#[cfg_attr(not(bootstrap), doc(include = "long.md"))] +#[doc(include = "long.md")] #[cfg(any(target_pointer_width = "32", windows))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32; -#[cfg_attr(bootstrap, doc(include = "os/raw/ulong.md"))] -#[cfg_attr(not(bootstrap), doc(include = "ulong.md"))] +#[doc(include = "ulong.md")] #[cfg(any(target_pointer_width = "32", windows))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u32; -#[cfg_attr(bootstrap, doc(include = "os/raw/long.md"))] -#[cfg_attr(not(bootstrap), doc(include = "long.md"))] +#[doc(include = "long.md")] #[cfg(all(target_pointer_width = "64", not(windows)))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64; -#[cfg_attr(bootstrap, doc(include = "os/raw/ulong.md"))] -#[cfg_attr(not(bootstrap), doc(include = "ulong.md"))] +#[doc(include = "ulong.md")] #[cfg(all(target_pointer_width = "64", not(windows)))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u64; -#[cfg_attr(bootstrap, doc(include = "os/raw/longlong.md"))] -#[cfg_attr(not(bootstrap), doc(include = "longlong.md"))] +#[doc(include = "longlong.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_longlong = i64; -#[cfg_attr(bootstrap, doc(include = "os/raw/ulonglong.md"))] -#[cfg_attr(not(bootstrap), doc(include = "ulonglong.md"))] +#[doc(include = "ulonglong.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulonglong = u64; -#[cfg_attr(bootstrap, doc(include = "os/raw/float.md"))] -#[cfg_attr(not(bootstrap), doc(include = "float.md"))] +#[doc(include = "float.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_float = f32; -#[cfg_attr(bootstrap, doc(include = "os/raw/double.md"))] -#[cfg_attr(not(bootstrap), doc(include = "double.md"))] +#[doc(include = "double.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64; #[stable(feature = "raw_os", since = "1.1.0")] diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 952fd9ebfdf07..638ce1679b8e9 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -15,10 +15,11 @@ use crate::intrinsics; use crate::mem; use crate::ptr; use crate::raw; +use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::stdio::panic_output; use crate::sys_common::rwlock::RWLock; -use crate::sys_common::thread_info; -use crate::sys_common::util; +use crate::sys_common::{thread_info, util}; +use crate::sys_common::backtrace::{self, RustBacktrace}; use crate::thread; #[cfg(not(test))] @@ -157,20 +158,12 @@ pub fn take_hook() -> Box) + 'static + Sync + Send> { } fn default_hook(info: &PanicInfo<'_>) { - #[cfg(feature = "backtrace")] - use crate::sys_common::backtrace; - // If this is a double panic, make sure that we print a backtrace // for this panic. Otherwise only print it if logging is enabled. - #[cfg(feature = "backtrace")] - let log_backtrace = { - let panics = update_panic_count(0); - - if panics >= 2 { - Some(backtrace::PrintFormat::Full) - } else { - backtrace::log_enabled() - } + let backtrace_env = if update_panic_count(0) >= 2 { + RustBacktrace::Print(backtrace_rs::PrintFmt::Full) + } else { + backtrace::rust_backtrace_env() }; // The current implementation always returns `Some`. @@ -190,17 +183,16 @@ fn default_hook(info: &PanicInfo<'_>) { let _ = writeln!(err, "thread '{}' panicked at '{}', {}", name, msg, location); - #[cfg(feature = "backtrace")] - { - use crate::sync::atomic::{AtomicBool, Ordering}; - - static FIRST_PANIC: AtomicBool = AtomicBool::new(true); + static FIRST_PANIC: AtomicBool = AtomicBool::new(true); - if let Some(format) = log_backtrace { - let _ = backtrace::print(err, format); - } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) { - let _ = writeln!(err, "note: run with `RUST_BACKTRACE=1` \ - environment variable to display a backtrace."); + match backtrace_env { + RustBacktrace::Print(format) => drop(backtrace::print(err, format)), + RustBacktrace::Disabled => {} + RustBacktrace::RuntimeDisabled => { + if FIRST_PANIC.swap(false, Ordering::SeqCst) { + let _ = writeln!(err, "note: run with `RUST_BACKTRACE=1` \ + environment variable to display a backtrace."); + } } } }; diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 87c071b512ac7..ca81044ee8560 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1123,6 +1123,12 @@ impl FusedIterator for Ancestors<'_> {} /// Which method works best depends on what kind of situation you're in. #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] +// FIXME: +// `PathBuf::as_mut_vec` current implementation relies +// on `PathBuf` being layout-compatible with `Vec`. +// When attribute privacy is implemented, `PathBuf` should be annotated as `#[repr(transparent)]`. +// Anyway, `PathBuf` representation and layout are considered implementation detail, are +// not documented and must not be relied upon. pub struct PathBuf { inner: OsString, } @@ -1621,7 +1627,7 @@ impl<'a> From> for PathBuf { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { - /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. + /// Converts a `PathBuf` into an `Arc` by moving the `PathBuf` data into a new `Arc` buffer. #[inline] fn from(s: PathBuf) -> Arc { let arc: Arc = Arc::from(s.into_os_string()); @@ -1631,7 +1637,7 @@ impl From for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&Path> for Arc { - /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. + /// Converts a `Path` into an `Arc` by copying the `Path` data into a new `Arc` buffer. #[inline] fn from(s: &Path) -> Arc { let arc: Arc = Arc::from(s.as_os_str()); @@ -1641,7 +1647,7 @@ impl From<&Path> for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { - /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. + /// Converts a `PathBuf` into an `Rc` by moving the `PathBuf` data into a new `Rc` buffer. #[inline] fn from(s: PathBuf) -> Rc { let rc: Rc = Rc::from(s.into_os_string()); @@ -1651,7 +1657,7 @@ impl From for Rc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&Path> for Rc { - /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. + /// Converts a `Path` into an `Rc` by copying the `Path` data into a new `Rc` buffer. #[inline] fn from(s: &Path) -> Rc { let rc: Rc = Rc::from(s.as_os_str()); @@ -1745,6 +1751,12 @@ impl AsRef for PathBuf { /// assert_eq!(extension, Some(OsStr::new("txt"))); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +// FIXME: +// `Path::new` current implementation relies +// on `Path` being layout-compatible with `OsStr`. +// When attribute privacy is implemented, `Path` should be annotated as `#[repr(transparent)]`. +// Anyway, `Path` representation and layout are considered implementation detail, are +// not documented and must not be relied upon. pub struct Path { inner: OsStr, } @@ -2207,6 +2219,7 @@ impl Path { /// assert_eq!(Path::new("/etc").join("passwd"), PathBuf::from("/etc/passwd")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub fn join>(&self, path: P) -> PathBuf { self._join(path.as_ref()) } diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index 1c61f21f7df4e..3e4cf91127fc5 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -7,10 +7,6 @@ #![stable(feature = "rust1", since = "1.0.0")] // Re-exported core operators -#[cfg(bootstrap)] -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use crate::marker::Copy; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use crate::marker::{Send, Sized, Sync, Unpin}; @@ -24,21 +20,9 @@ pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; pub use crate::mem::drop; // Re-exported types and traits -#[cfg(bootstrap)] -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use crate::clone::Clone; -#[cfg(bootstrap)] -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use crate::cmp::{PartialEq, PartialOrd, Eq, Ord}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use crate::convert::{AsRef, AsMut, Into, From}; -#[cfg(bootstrap)] -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use crate::default::Default; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use crate::iter::{Iterator, Extend, IntoIterator}; @@ -53,11 +37,9 @@ pub use crate::option::Option::{self, Some, None}; pub use crate::result::Result::{self, Ok, Err}; // Re-exported built-in macros -#[cfg(not(bootstrap))] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[doc(no_inline)] pub use core::prelude::v1::{ - __rust_unstable_column, asm, assert, cfg, @@ -83,7 +65,6 @@ pub use core::prelude::v1::{ // FIXME: Attribute and derive macros are not documented because for them rustdoc generates // dead links which fail link checker testing. -#[cfg(not(bootstrap))] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow(deprecated)] #[doc(hidden)] diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index d9a3da66a6786..a72951c034610 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -426,14 +426,12 @@ mod prim_unit { } /// /// use std::mem; /// -/// fn main() { -/// unsafe { -/// let my_num: *mut i32 = libc::malloc(mem::size_of::()) as *mut i32; -/// if my_num.is_null() { -/// panic!("failed to allocate memory"); -/// } -/// libc::free(my_num as *mut libc::c_void); +/// unsafe { +/// let my_num: *mut i32 = libc::malloc(mem::size_of::()) as *mut i32; +/// if my_num.is_null() { +/// panic!("failed to allocate memory"); /// } +/// libc::free(my_num as *mut libc::c_void); /// } /// ``` /// @@ -566,7 +564,9 @@ mod prim_array { } #[doc(alias = "[")] #[doc(alias = "]")] #[doc(alias = "[]")] -/// A dynamically-sized view into a contiguous sequence, `[T]`. +/// A dynamically-sized view into a contiguous sequence, `[T]`. Contiguous here +/// means that elements are laid out so that every element is the same +/// distance from its neighbors. /// /// *[See also the `std::slice` module](slice/index.html).* /// @@ -655,7 +655,7 @@ mod prim_slice { } /// [`len`]: #method.len /// /// Note: This example shows the internals of `&str`. `unsafe` should not be -/// used to get a string slice under normal circumstances. Use `as_slice` +/// used to get a string slice under normal circumstances. Use `as_str` /// instead. #[stable(feature = "rust1", since = "1.0.0")] mod prim_str { } diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 000f80f99e7a9..da136ca6bf68d 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -422,7 +422,7 @@ impl fmt::Debug for ChildStderr { /// // Execute `ls` in the current directory of the program. /// list_dir.status().expect("process failed to execute"); /// -/// println!(""); +/// println!(); /// /// // Change `ls` to execute in the root directory. /// list_dir.current_dir("/"); @@ -935,12 +935,12 @@ impl Stdio { /// .expect("Failed to spawn child process"); /// /// { - /// let mut stdin = child.stdin.as_mut().expect("Failed to open stdin"); + /// let stdin = child.stdin.as_mut().expect("Failed to open stdin"); /// stdin.write_all("Hello, world!".as_bytes()).expect("Failed to write to stdin"); /// } /// /// let output = child.wait_with_output().expect("Failed to read stdout"); - /// assert_eq!(String::from_utf8_lossy(&output.stdout), "!dlrow ,olleH\n"); + /// assert_eq!(String::from_utf8_lossy(&output.stdout), "!dlrow ,olleH"); /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn piped() -> Stdio { Stdio(imp::Stdio::MakePipe) } @@ -1595,7 +1595,7 @@ pub fn id() -> u32 { /// A trait for implementing arbitrary return types in the `main` function. /// -/// The c-main function only supports to return integers as return type. +/// The C-main function only supports to return integers as return type. /// So, every type implementing the `Termination` trait has to be converted /// to an integer. /// diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index cf45eb0daba39..63e35d5ed919a 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -44,12 +44,9 @@ fn lang_start_internal(main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindS sys::args::init(argc, argv); // Let's run some code! - #[cfg(feature = "backtrace")] let exit_code = panic::catch_unwind(|| { sys_common::backtrace::__rust_begin_short_backtrace(move || main()) }); - #[cfg(not(feature = "backtrace"))] - let exit_code = panic::catch_unwind(move || main()); sys_common::cleanup(); exit_code.unwrap_or(101) as isize diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index aeff57716e86b..65ce19f2a1b3a 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -28,14 +28,14 @@ impl WaitTimeoutResult { /// once the boolean has been updated and notified. /// /// ``` - /// use std::sync::{Arc, Mutex, Condvar}; + /// use std::sync::{Arc, Condvar, Mutex}; /// use std::thread; /// use std::time::Duration; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); /// let pair2 = pair.clone(); /// - /// thread::spawn(move|| { + /// thread::spawn(move || { /// let (lock, cvar) = &*pair2; /// /// // Let's wait 20 milliseconds before notifying the condvar. diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index e29faf18d83e5..fd6e46fd61dc5 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -163,7 +163,6 @@ pub use self::condvar::{Condvar, WaitTimeoutResult}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::mutex::{Mutex, MutexGuard}; #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(bootstrap, allow(deprecated_in_future))] #[allow(deprecated)] pub use self::once::{Once, OnceState, ONCE_INIT}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/cloudabi/abi/cloudabi.rs b/src/libstd/sys/cloudabi/abi/cloudabi.rs index 9addba8b6118e..38db4dd51657a 100644 --- a/src/libstd/sys/cloudabi/abi/cloudabi.rs +++ b/src/libstd/sys/cloudabi/abi/cloudabi.rs @@ -115,6 +115,7 @@ #![no_std] #![allow(non_camel_case_types)] +#![allow(deprecated)] // FIXME: using `mem::uninitialized()` include!("bitflags.rs"); diff --git a/src/libstd/sys/cloudabi/mod.rs b/src/libstd/sys/cloudabi/mod.rs index 6e147612eb4b7..2fb10cc370add 100644 --- a/src/libstd/sys/cloudabi/mod.rs +++ b/src/libstd/sys/cloudabi/mod.rs @@ -1,5 +1,3 @@ -#![allow(deprecated_in_future)] // mem::uninitialized; becomes `deprecated` when nightly is 1.39 - use crate::io::ErrorKind; use crate::mem; diff --git a/src/libstd/sys/cloudabi/mutex.rs b/src/libstd/sys/cloudabi/mutex.rs index d3ff0077b20e5..0e30d3a1c6cf1 100644 --- a/src/libstd/sys/cloudabi/mutex.rs +++ b/src/libstd/sys/cloudabi/mutex.rs @@ -104,10 +104,11 @@ impl ReentrantMutex { }, ..mem::zeroed() }; - let mut event: abi::event = mem::uninitialized(); - let mut nevents: usize = mem::uninitialized(); - let ret = abi::poll(&subscription, &mut event, 1, &mut nevents); + let mut event = MaybeUninit::::uninit(); + let mut nevents = MaybeUninit::::uninit(); + let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr()); assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire mutex"); + let event = event.assume_init(); assert_eq!(event.error, abi::errno::SUCCESS, "Failed to acquire mutex"); } } diff --git a/src/libstd/sys/cloudabi/rwlock.rs b/src/libstd/sys/cloudabi/rwlock.rs index 6da3f3841b6c6..73499d65a067f 100644 --- a/src/libstd/sys/cloudabi/rwlock.rs +++ b/src/libstd/sys/cloudabi/rwlock.rs @@ -1,5 +1,6 @@ use crate::cell::UnsafeCell; use crate::mem; +use crate::mem::MaybeUninit; use crate::sync::atomic::{AtomicU32, Ordering}; use crate::sys::cloudabi::abi; @@ -73,10 +74,11 @@ impl RWLock { }, ..mem::zeroed() }; - let mut event: abi::event = mem::uninitialized(); - let mut nevents: usize = mem::uninitialized(); - let ret = abi::poll(&subscription, &mut event, 1, &mut nevents); + let mut event = MaybeUninit::::uninit(); + let mut nevents = MaybeUninit::::uninit(); + let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr()); assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire read lock"); + let event = event.assume_init(); assert_eq!( event.error, abi::errno::SUCCESS, @@ -182,10 +184,11 @@ impl RWLock { }, ..mem::zeroed() }; - let mut event: abi::event = mem::uninitialized(); - let mut nevents: usize = mem::uninitialized(); - let ret = abi::poll(&subscription, &mut event, 1, &mut nevents); + let mut event = MaybeUninit::::uninit(); + let mut nevents = MaybeUninit::::uninit(); + let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr()); assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire write lock"); + let event = event.assume_init(); assert_eq!( event.error, abi::errno::SUCCESS, diff --git a/src/libstd/sys/cloudabi/shims/process.rs b/src/libstd/sys/cloudabi/shims/process.rs index e719b362cbf55..03a59d6d7c832 100644 --- a/src/libstd/sys/cloudabi/shims/process.rs +++ b/src/libstd/sys/cloudabi/shims/process.rs @@ -4,14 +4,16 @@ use crate::io; use crate::sys::fs::File; use crate::sys::pipe::AnonPipe; use crate::sys::{unsupported, Void}; -use crate::sys_common::process::{CommandEnv, DefaultEnvKey}; +use crate::sys_common::process::CommandEnv; + +pub use crate::ffi::OsString as EnvKey; //////////////////////////////////////////////////////////////////////////////// // Command //////////////////////////////////////////////////////////////////////////////// pub struct Command { - env: CommandEnv, + env: CommandEnv, } // passed back to std::process with the pipes connected to the child, if any @@ -37,7 +39,7 @@ impl Command { pub fn arg(&mut self, _arg: &OsStr) {} - pub fn env_mut(&mut self) -> &mut CommandEnv { + pub fn env_mut(&mut self) -> &mut CommandEnv { &mut self.env } diff --git a/src/libstd/sys/cloudabi/thread.rs b/src/libstd/sys/cloudabi/thread.rs index 7da16c4d247aa..240b6ea9e57f8 100644 --- a/src/libstd/sys/cloudabi/thread.rs +++ b/src/libstd/sys/cloudabi/thread.rs @@ -72,10 +72,11 @@ impl Thread { }, ..mem::zeroed() }; - let mut event: abi::event = mem::uninitialized(); - let mut nevents: usize = mem::uninitialized(); - let ret = abi::poll(&subscription, &mut event, 1, &mut nevents); + let mut event = mem::MaybeUninit::::uninit(); + let mut nevents = mem::MaybeUninit::::uninit(); + let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr()); assert_eq!(ret, abi::errno::SUCCESS); + let event = event.assume_init(); assert_eq!(event.error, abi::errno::SUCCESS); } } diff --git a/src/libstd/sys/sgx/abi/usercalls/alloc.rs b/src/libstd/sys/sgx/abi/usercalls/alloc.rs index c9ff53d0a4fd6..75dd0d429c214 100644 --- a/src/libstd/sys/sgx/abi/usercalls/alloc.rs +++ b/src/libstd/sys/sgx/abi/usercalls/alloc.rs @@ -522,7 +522,11 @@ impl Drop for User where T: UserSafe { impl, U> CoerceUnsized> for UserRef {} #[unstable(feature = "sgx_platform", issue = "56975")] -impl> Index for UserRef<[T]> where [T]: UserSafe, I::Output: UserSafe { +impl Index for UserRef<[T]> +where + [T]: UserSafe, + I: SliceIndex<[T], Output: UserSafe>, +{ type Output = UserRef; #[inline] @@ -538,7 +542,11 @@ impl> Index for UserRef<[T]> where [T]: UserSafe, I::Ou } #[unstable(feature = "sgx_platform", issue = "56975")] -impl> IndexMut for UserRef<[T]> where [T]: UserSafe, I::Output: UserSafe { +impl IndexMut for UserRef<[T]> +where + [T]: UserSafe, + I: SliceIndex<[T], Output: UserSafe>, +{ #[inline] fn index_mut(&mut self, index: I) -> &mut UserRef { unsafe { diff --git a/src/libstd/sys/sgx/condvar.rs b/src/libstd/sys/sgx/condvar.rs index 000bb19f2692a..cc1c04a83e752 100644 --- a/src/libstd/sys/sgx/condvar.rs +++ b/src/libstd/sys/sgx/condvar.rs @@ -27,8 +27,7 @@ impl Condvar { pub unsafe fn wait(&self, mutex: &Mutex) { let guard = self.inner.lock(); - mutex.unlock(); - WaitQueue::wait(guard); + WaitQueue::wait(guard, || mutex.unlock()); mutex.lock() } diff --git a/src/libstd/sys/sgx/mutex.rs b/src/libstd/sys/sgx/mutex.rs index f325fb1dd582f..662da8b3f6685 100644 --- a/src/libstd/sys/sgx/mutex.rs +++ b/src/libstd/sys/sgx/mutex.rs @@ -22,7 +22,7 @@ impl Mutex { let mut guard = self.inner.lock(); if *guard.lock_var() { // Another thread has the lock, wait - WaitQueue::wait(guard) + WaitQueue::wait(guard, ||{}) // Another thread has passed the lock to us } else { // We are just now obtaining the lock @@ -83,7 +83,7 @@ impl ReentrantMutex { match guard.lock_var().owner { Some(tcs) if tcs != thread::current() => { // Another thread has the lock, wait - WaitQueue::wait(guard); + WaitQueue::wait(guard, ||{}); // Another thread has passed the lock to us }, _ => { diff --git a/src/libstd/sys/sgx/process.rs b/src/libstd/sys/sgx/process.rs index a02e009d95356..edf933d10e074 100644 --- a/src/libstd/sys/sgx/process.rs +++ b/src/libstd/sys/sgx/process.rs @@ -4,14 +4,16 @@ use crate::io; use crate::sys::fs::File; use crate::sys::pipe::AnonPipe; use crate::sys::{unsupported, Void}; -use crate::sys_common::process::{CommandEnv, DefaultEnvKey}; +use crate::sys_common::process::CommandEnv; + +pub use crate::ffi::OsString as EnvKey; //////////////////////////////////////////////////////////////////////////////// // Command //////////////////////////////////////////////////////////////////////////////// pub struct Command { - env: CommandEnv + env: CommandEnv, } // passed back to std::process with the pipes connected to the child, if any @@ -38,7 +40,7 @@ impl Command { pub fn arg(&mut self, _arg: &OsStr) { } - pub fn env_mut(&mut self) -> &mut CommandEnv { + pub fn env_mut(&mut self) -> &mut CommandEnv { &mut self.env } diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs index 30c47e44eef8e..e2f94b1d928e1 100644 --- a/src/libstd/sys/sgx/rwlock.rs +++ b/src/libstd/sys/sgx/rwlock.rs @@ -31,7 +31,7 @@ impl RWLock { if *wguard.lock_var() || !wguard.queue_empty() { // Another thread has or is waiting for the write lock, wait drop(wguard); - WaitQueue::wait(rguard); + WaitQueue::wait(rguard, ||{}); // Another thread has passed the lock to us } else { // No waiting writers, acquire the read lock @@ -62,7 +62,7 @@ impl RWLock { if *wguard.lock_var() || rguard.lock_var().is_some() { // Another thread has the lock, wait drop(rguard); - WaitQueue::wait(wguard); + WaitQueue::wait(wguard, ||{}); // Another thread has passed the lock to us } else { // We are just now obtaining the lock @@ -97,6 +97,7 @@ impl RWLock { if let Ok(mut wguard) = WaitQueue::notify_one(wguard) { // A writer was waiting, pass the lock *wguard.lock_var_mut() = true; + wguard.drop_after(rguard); } else { // No writers were waiting, the lock is released rtassert!(rguard.queue_empty()); @@ -117,21 +118,26 @@ impl RWLock { rguard: SpinMutexGuard<'_, WaitVariable>>, wguard: SpinMutexGuard<'_, WaitVariable>, ) { - if let Err(mut wguard) = WaitQueue::notify_one(wguard) { - // No writers waiting, release the write lock - *wguard.lock_var_mut() = false; - if let Ok(mut rguard) = WaitQueue::notify_all(rguard) { - // One or more readers were waiting, pass the lock to them - if let NotifiedTcs::All { count } = rguard.notified_tcs() { - *rguard.lock_var_mut() = Some(count) + match WaitQueue::notify_one(wguard) { + Err(mut wguard) => { + // No writers waiting, release the write lock + *wguard.lock_var_mut() = false; + if let Ok(mut rguard) = WaitQueue::notify_all(rguard) { + // One or more readers were waiting, pass the lock to them + if let NotifiedTcs::All { count } = rguard.notified_tcs() { + *rguard.lock_var_mut() = Some(count) + } else { + unreachable!() // called notify_all + } + rguard.drop_after(wguard); } else { - unreachable!() // called notify_all + // No readers waiting, the lock is released } - } else { - // No readers waiting, the lock is released + }, + Ok(wguard) => { + // There was a thread waiting for write, just pass the lock + wguard.drop_after(rguard); } - } else { - // There was a thread waiting for write, just pass the lock } } diff --git a/src/libstd/sys/sgx/waitqueue.rs b/src/libstd/sys/sgx/waitqueue.rs index d542f9b410127..3cb40e509b6b2 100644 --- a/src/libstd/sys/sgx/waitqueue.rs +++ b/src/libstd/sys/sgx/waitqueue.rs @@ -98,6 +98,12 @@ impl<'a, T> WaitGuard<'a, T> { pub fn notified_tcs(&self) -> NotifiedTcs { self.notified_tcs } + + /// Drop this `WaitGuard`, after dropping another `guard`. + pub fn drop_after(self, guard: U) { + drop(guard); + drop(self); + } } impl<'a, T> Deref for WaitGuard<'a, T> { @@ -140,7 +146,7 @@ impl WaitQueue { /// until a wakeup event. /// /// This function does not return until this thread has been awoken. - pub fn wait(mut guard: SpinMutexGuard<'_, WaitVariable>) { + pub fn wait(mut guard: SpinMutexGuard<'_, WaitVariable>, before_wait: F) { // very unsafe: check requirements of UnsafeList::push unsafe { let mut entry = UnsafeListEntry::new(SpinMutex::new(WaitEntry { @@ -149,6 +155,7 @@ impl WaitQueue { })); let entry = guard.queue.inner.push(&mut entry); drop(guard); + before_wait(); while !entry.lock().wake { // don't panic, this would invalidate `entry` during unwinding let eventset = rtunwrap!(Ok, usercalls::wait(EV_UNPARK, WAIT_INDEFINITE)); @@ -545,7 +552,7 @@ mod tests { assert!(WaitQueue::notify_one(wq2.lock()).is_ok()); }); - WaitQueue::wait(locked); + WaitQueue::wait(locked, ||{}); t1.join().unwrap(); } diff --git a/src/libstd/sys/unix/process/mod.rs b/src/libstd/sys/unix/process/mod.rs index bba4b21c46232..553e980f08e97 100644 --- a/src/libstd/sys/unix/process/mod.rs +++ b/src/libstd/sys/unix/process/mod.rs @@ -1,5 +1,6 @@ -pub use self::process_common::{Command, ExitStatus, ExitCode, Stdio, StdioPipes}; -pub use self::process_inner::Process; +pub use self::process_common::{Command, ExitCode, Stdio, StdioPipes}; +pub use self::process_inner::{ExitStatus, Process}; +pub use crate::ffi::OsString as EnvKey; mod process_common; #[cfg(not(target_os = "fuchsia"))] diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index 6bb20bbe08794..4edd2ebf8c598 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -1,25 +1,57 @@ use crate::os::unix::prelude::*; -use crate::ffi::{OsString, OsStr, CString, CStr}; +use crate::ffi::{OsString, OsStr, CString}; use crate::fmt; use crate::io; use crate::ptr; use crate::sys::fd::FileDesc; -use crate::sys::fs::{File, OpenOptions}; +use crate::sys::fs::File; use crate::sys::pipe::{self, AnonPipe}; -use crate::sys_common::process::{CommandEnv, DefaultEnvKey}; +use crate::sys_common::process::CommandEnv; use crate::collections::BTreeMap; +#[cfg(not(target_os = "fuchsia"))] +use { + crate::ffi::CStr, + crate::sys::fs::OpenOptions, +}; + use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE}; cfg_if::cfg_if! { - if #[cfg(target_os = "redox")] { + if #[cfg(target_os = "fuchsia")] { + // fuchsia doesn't have /dev/null + } else if #[cfg(target_os = "redox")] { const DEV_NULL: &'static str = "null:\0"; } else { const DEV_NULL: &'static str = "/dev/null\0"; } } +// Android with api less than 21 define sig* functions inline, so it is not +// available for dynamic link. Implementing sigemptyset and sigaddset allow us +// to support older Android version (independent of libc version). +// The following implementations are based on https://git.io/vSkNf +cfg_if::cfg_if! { + if #[cfg(target_os = "android")] { + pub unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int { + set.write_bytes(0u8, 1); + return 0; + } + #[allow(dead_code)] + pub unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int { + use crate::{slice, mem}; + + let raw = slice::from_raw_parts_mut(set as *mut u8, mem::size_of::()); + let bit = (signum - 1) as usize; + raw[bit / 8] |= 1 << (bit % 8); + return 0; + } + } else { + pub use libc::{sigemptyset, sigaddset}; + } +} + //////////////////////////////////////////////////////////////////////////////// // Command //////////////////////////////////////////////////////////////////////////////// @@ -45,7 +77,7 @@ pub struct Command { program: CString, args: Vec, argv: Argv, - env: CommandEnv, + env: CommandEnv, cwd: Option, uid: Option, @@ -83,6 +115,11 @@ pub enum ChildStdio { Inherit, Explicit(c_int), Owned(FileDesc), + + // On Fuchsia, null stdio is the default, so we simply don't specify + // any actions at the time of spawning. + #[cfg(target_os = "fuchsia")] + Null, } pub enum Stdio { @@ -177,7 +214,7 @@ impl Command { self.stderr = Some(stderr); } - pub fn env_mut(&mut self) -> &mut CommandEnv { + pub fn env_mut(&mut self) -> &mut CommandEnv { &mut self.env } @@ -247,7 +284,7 @@ impl CStringArray { } } -fn construct_envp(env: BTreeMap, saw_nul: &mut bool) -> CStringArray { +fn construct_envp(env: BTreeMap, saw_nul: &mut bool) -> CStringArray { let mut result = CStringArray::with_capacity(env.len()); for (k, v) in env { let mut k: OsString = k.into(); @@ -301,6 +338,7 @@ impl Stdio { Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours))) } + #[cfg(not(target_os = "fuchsia"))] Stdio::Null => { let mut opts = OpenOptions::new(); opts.read(readable); @@ -311,6 +349,11 @@ impl Stdio { let fd = File::open_c(&path, &opts)?; Ok((ChildStdio::Owned(fd.into_fd()), None)) } + + #[cfg(target_os = "fuchsia")] + Stdio::Null => { + Ok((ChildStdio::Null, None)) + } } } } @@ -333,6 +376,9 @@ impl ChildStdio { ChildStdio::Inherit => None, ChildStdio::Explicit(fd) => Some(fd), ChildStdio::Owned(ref fd) => Some(fd.raw()), + + #[cfg(target_os = "fuchsia")] + ChildStdio::Null => None, } } } @@ -347,57 +393,6 @@ impl fmt::Debug for Command { } } -/// Unix exit statuses -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitStatus(c_int); - -impl ExitStatus { - pub fn new(status: c_int) -> ExitStatus { - ExitStatus(status) - } - - fn exited(&self) -> bool { - unsafe { libc::WIFEXITED(self.0) } - } - - pub fn success(&self) -> bool { - self.code() == Some(0) - } - - pub fn code(&self) -> Option { - if self.exited() { - Some(unsafe { libc::WEXITSTATUS(self.0) }) - } else { - None - } - } - - pub fn signal(&self) -> Option { - if !self.exited() { - Some(unsafe { libc::WTERMSIG(self.0) }) - } else { - None - } - } -} - -impl From for ExitStatus { - fn from(a: c_int) -> ExitStatus { - ExitStatus(a) - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(code) = self.code() { - write!(f, "exit code: {}", code) - } else { - let signal = self.signal().unwrap(); - write!(f, "signal: {}", signal) - } - } -} - #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub struct ExitCode(u8); @@ -429,36 +424,6 @@ mod tests { } } - // Android with api less than 21 define sig* functions inline, so it is not - // available for dynamic link. Implementing sigemptyset and sigaddset allow us - // to support older Android version (independent of libc version). - // The following implementations are based on https://git.io/vSkNf - - #[cfg(not(target_os = "android"))] - extern { - #[cfg_attr(target_os = "netbsd", link_name = "__sigemptyset14")] - fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int; - - #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")] - fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int; - } - - #[cfg(target_os = "android")] - unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int { - set.write_bytes(0u8, 1); - return 0; - } - - #[cfg(target_os = "android")] - unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int { - use crate::slice; - - let raw = slice::from_raw_parts_mut(set as *mut u8, mem::size_of::()); - let bit = (signum - 1) as usize; - raw[bit / 8] |= 1 << (bit % 8); - return 0; - } - // See #14232 for more information, but it appears that signal delivery to a // newly spawned process may just be raced in the macOS, so to prevent this // test from being flaky we ignore it on macOS. diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs index 7c6be9b0a6047..2b1a3ecfd70f5 100644 --- a/src/libstd/sys/unix/process/process_fuchsia.rs +++ b/src/libstd/sys/unix/process/process_fuchsia.rs @@ -1,11 +1,13 @@ +use crate::convert::TryInto; use crate::io; +use crate::fmt; use crate::mem; use crate::ptr; use crate::sys::process::zircon::{Handle, zx_handle_t}; use crate::sys::process::process_common::*; -use libc::size_t; +use libc::{c_int, size_t}; //////////////////////////////////////////////////////////////////////////////// // Command @@ -48,30 +50,51 @@ impl Command { use crate::sys::process::zircon::*; let envp = match maybe_envp { - Some(envp) => envp.as_ptr(), + // None means to clone the current environment, which is done in the + // flags below. None => ptr::null(), + Some(envp) => envp.as_ptr(), }; - let transfer_or_clone = |opt_fd, target_fd| if let Some(local_fd) = opt_fd { - fdio_spawn_action_t { - action: FDIO_SPAWN_ACTION_TRANSFER_FD, - local_fd, - target_fd, - ..Default::default() - } - } else { - fdio_spawn_action_t { - action: FDIO_SPAWN_ACTION_CLONE_FD, - local_fd: target_fd, - target_fd, - ..Default::default() + let make_action = |local_io: &ChildStdio, target_fd| -> io::Result { + if let Some(local_fd) = local_io.fd() { + Ok(fdio_spawn_action_t { + action: FDIO_SPAWN_ACTION_TRANSFER_FD, + local_fd, + target_fd, + ..Default::default() + }) + } else { + if let ChildStdio::Null = local_io { + // acts as no-op + return Ok(Default::default()); + } + + let mut handle = ZX_HANDLE_INVALID; + let status = fdio_fd_clone(target_fd, &mut handle); + if status == ERR_INVALID_ARGS || status == ERR_NOT_SUPPORTED { + // This descriptor is closed; skip it rather than generating an + // error. + return Ok(Default::default()); + } + zx_cvt(status)?; + + let mut cloned_fd = 0; + zx_cvt(fdio_fd_create(handle, &mut cloned_fd))?; + + Ok(fdio_spawn_action_t { + action: FDIO_SPAWN_ACTION_TRANSFER_FD, + local_fd: cloned_fd as i32, + target_fd, + ..Default::default() + }) } }; // Clone stdin, stdout, and stderr - let action1 = transfer_or_clone(stdio.stdin.fd(), 0); - let action2 = transfer_or_clone(stdio.stdout.fd(), 1); - let action3 = transfer_or_clone(stdio.stderr.fd(), 2); + let action1 = make_action(&stdio.stdin, 0)?; + let action2 = make_action(&stdio.stdout, 1)?; + let action3 = make_action(&stdio.stderr, 2)?; let actions = [action1, action2, action3]; // We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc @@ -84,9 +107,11 @@ impl Command { let mut process_handle: zx_handle_t = 0; zx_cvt(fdio_spawn_etc( - 0, - FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE, - self.get_argv()[0], self.get_argv().as_ptr(), envp, 3, actions.as_ptr(), + ZX_HANDLE_INVALID, + FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE + | FDIO_SPAWN_CLONE_ENVIRON, // this is ignored when envp is non-null + self.get_argv()[0], self.get_argv().as_ptr(), envp, + actions.len() as size_t, actions.as_ptr(), &mut process_handle, ptr::null_mut(), ))?; @@ -137,7 +162,7 @@ impl Process { return Err(io::Error::new(io::ErrorKind::InvalidData, "Failed to get exit status of process")); } - Ok(ExitStatus::new(proc_info.rec.return_code)) + Ok(ExitStatus(proc_info.return_code)) } pub fn try_wait(&mut self) -> io::Result> { @@ -167,6 +192,36 @@ impl Process { return Err(io::Error::new(io::ErrorKind::InvalidData, "Failed to get exit status of process")); } - Ok(Some(ExitStatus::new(proc_info.rec.return_code))) + Ok(Some(ExitStatus(proc_info.return_code))) + } +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitStatus(i64); + +impl ExitStatus { + pub fn success(&self) -> bool { + self.code() == Some(0) + } + + pub fn code(&self) -> Option { + // FIXME: support extracting return code as an i64 + self.0.try_into().ok() + } + + pub fn signal(&self) -> Option { + None + } +} + +impl From for ExitStatus { + fn from(a: c_int) -> ExitStatus { + ExitStatus(a as i64) + } +} + +impl fmt::Display for ExitStatus { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "exit code: {}", self.0) } } diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index 327d82e60cff3..507dc6892613a 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -1,3 +1,4 @@ +use crate::fmt; use crate::io::{self, Error, ErrorKind}; use crate::ptr; use crate::sys::cvt; @@ -178,23 +179,22 @@ impl Command { cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO))?; } - if cfg!(not(any(target_os = "l4re"))) { + #[cfg(not(target_os = "l4re"))] + { if let Some(u) = self.get_gid() { cvt(libc::setgid(u as gid_t))?; } if let Some(u) = self.get_uid() { + // When dropping privileges from root, the `setgroups` call + // will remove any extraneous groups. If we don't call this, + // then even though our uid has dropped, we may still have + // groups that enable us to do super-user things. This will + // fail if we aren't root, so don't bother checking the + // return value, this is just done as an optimistic + // privilege dropping function. //FIXME: Redox kernel does not support setgroups yet - if cfg!(not(target_os = "redox")) { - // When dropping privileges from root, the `setgroups` call - // will remove any extraneous groups. If we don't call this, - // then even though our uid has dropped, we may still have - // groups that enable us to do super-user things. This will - // fail if we aren't root, so don't bother checking the - // return value, this is just done as an optimistic - // privilege dropping function. - let _ = libc::setgroups(0, ptr::null()); - } - + #[cfg(not(target_os = "redox"))] + let _ = libc::setgroups(0, ptr::null()); cvt(libc::setuid(u as uid_t))?; } } @@ -203,7 +203,7 @@ impl Command { } // emscripten has no signal support. - #[cfg(not(any(target_os = "emscripten")))] + #[cfg(not(target_os = "emscripten"))] { use crate::mem::MaybeUninit; // Reset signal handling so the child process starts in a @@ -214,14 +214,7 @@ impl Command { // need to clean things up now to avoid confusing the program // we're about to run. let mut set = MaybeUninit::::uninit(); - if cfg!(target_os = "android") { - // Implementing sigemptyset allow us to support older Android - // versions. See the comment about Android and sig* functions in - // process_common.rs - set.as_mut_ptr().write_bytes(0u8, 1); - } else { - cvt(libc::sigemptyset(set.as_mut_ptr()))?; - } + cvt(sigemptyset(set.as_mut_ptr()))?; cvt(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), ptr::null_mut()))?; let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL); @@ -363,10 +356,10 @@ impl Command { } let mut set = MaybeUninit::::uninit(); - cvt(libc::sigemptyset(set.as_mut_ptr()))?; + cvt(sigemptyset(set.as_mut_ptr()))?; cvt(libc::posix_spawnattr_setsigmask(attrs.0.as_mut_ptr(), set.as_ptr()))?; - cvt(libc::sigaddset(set.as_mut_ptr(), libc::SIGPIPE))?; + cvt(sigaddset(set.as_mut_ptr(), libc::SIGPIPE))?; cvt(libc::posix_spawnattr_setsigdefault(attrs.0.as_mut_ptr(), set.as_ptr()))?; @@ -449,3 +442,54 @@ impl Process { } } } + +/// Unix exit statuses +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitStatus(c_int); + +impl ExitStatus { + pub fn new(status: c_int) -> ExitStatus { + ExitStatus(status) + } + + fn exited(&self) -> bool { + unsafe { libc::WIFEXITED(self.0) } + } + + pub fn success(&self) -> bool { + self.code() == Some(0) + } + + pub fn code(&self) -> Option { + if self.exited() { + Some(unsafe { libc::WEXITSTATUS(self.0) }) + } else { + None + } + } + + pub fn signal(&self) -> Option { + if !self.exited() { + Some(unsafe { libc::WTERMSIG(self.0) }) + } else { + None + } + } +} + +impl From for ExitStatus { + fn from(a: c_int) -> ExitStatus { + ExitStatus(a) + } +} + +impl fmt::Display for ExitStatus { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(code) = self.code() { + write!(f, "exit code: {}", code) + } else { + let signal = self.signal().unwrap(); + write!(f, "signal: {}", signal) + } + } +} diff --git a/src/libstd/sys/unix/process/zircon.rs b/src/libstd/sys/unix/process/zircon.rs index ec715d5490f6f..188a6b5f2da4a 100644 --- a/src/libstd/sys/unix/process/zircon.rs +++ b/src/libstd/sys/unix/process/zircon.rs @@ -2,8 +2,9 @@ use crate::convert::TryInto; use crate::io; +use crate::i64; +use crate::mem::MaybeUninit; use crate::os::raw::c_char; -use crate::u64; use libc::{c_int, c_void, size_t}; @@ -14,8 +15,8 @@ pub type zx_status_t = i32; pub const ZX_HANDLE_INVALID: zx_handle_t = 0; -pub type zx_time_t = u64; -pub const ZX_TIME_INFINITE : zx_time_t = u64::MAX; +pub type zx_time_t = i64; +pub const ZX_TIME_INFINITE : zx_time_t = i64::MAX; pub type zx_signals_t = u32; @@ -64,29 +65,14 @@ impl Drop for Handle { } } -// Common ZX_INFO header -#[derive(Default)] -#[repr(C)] -pub struct zx_info_header_t { - pub topic: u32, // identifies the info struct - pub avail_topic_size: u16, // “native” size of the struct - pub topic_size: u16, // size of the returned struct (<=topic_size) - pub avail_count: u32, // number of records the kernel has - pub count: u32, // number of records returned (limited by buffer size) -} - -#[derive(Default)] -#[repr(C)] -pub struct zx_record_process_t { - pub return_code: c_int, -} - // Returned for topic ZX_INFO_PROCESS #[derive(Default)] #[repr(C)] pub struct zx_info_process_t { - pub hdr: zx_info_header_t, - pub rec: zx_record_process_t, + pub return_code: i64, + pub started: bool, + pub exited: bool, + pub debugger_attached: bool, } extern { @@ -120,8 +106,11 @@ pub struct fdio_spawn_action_t { extern { pub fn fdio_spawn_etc(job: zx_handle_t, flags: u32, path: *const c_char, argv: *const *const c_char, envp: *const *const c_char, - action_count: u64, actions: *const fdio_spawn_action_t, + action_count: size_t, actions: *const fdio_spawn_action_t, process: *mut zx_handle_t, err_msg: *mut c_char) -> zx_status_t; + + pub fn fdio_fd_clone(fd: c_int, out_handle: *mut zx_handle_t) -> zx_status_t; + pub fn fdio_fd_create(handle: zx_handle_t, fd: *mut c_int) -> zx_status_t; } // fdio_spawn_etc flags diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index 02f377d55c919..fd6796ad22c12 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -311,6 +311,7 @@ mod inner { pub fn actually_monotonic() -> bool { (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64")) || (cfg!(target_os = "linux") && cfg!(target_arch = "x86")) || + cfg!(target_os = "fuchsia") || false // last clause, used so `||` is always trailing above } diff --git a/src/libstd/sys/vxworks/backtrace/mod.rs b/src/libstd/sys/vxworks/backtrace/mod.rs deleted file mode 100644 index 0887e5a4df937..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/mod.rs +++ /dev/null @@ -1,110 +0,0 @@ -/// Backtrace support built on libgcc with some extra OS-specific support -/// -/// Some methods of getting a backtrace: -/// -/// * The backtrace() functions on unix. It turns out this doesn't work very -/// well for green threads on macOS, and the address to symbol portion of it -/// suffers problems that are described below. -/// -/// * Using libunwind. This is more difficult than it sounds because libunwind -/// isn't installed everywhere by default. It's also a bit of a hefty library, -/// so possibly not the best option. When testing, libunwind was excellent at -/// getting both accurate backtraces and accurate symbols across platforms. -/// This route was not chosen in favor of the next option, however. -/// -/// * We're already using libgcc_s for exceptions in rust (triggering thread -/// unwinding and running destructors on the stack), and it turns out that it -/// conveniently comes with a function that also gives us a backtrace. All of -/// these functions look like _Unwind_*, but it's not quite the full -/// repertoire of the libunwind API. Due to it already being in use, this was -/// the chosen route of getting a backtrace. -/// -/// After choosing libgcc_s for backtraces, the sad part is that it will only -/// give us a stack trace of instruction pointers. Thankfully these instruction -/// pointers are accurate (they work for green and native threads), but it's -/// then up to us again to figure out how to translate these addresses to -/// symbols. As with before, we have a few options. Before, that, a little bit -/// of an interlude about symbols. This is my very limited knowledge about -/// symbol tables, and this information is likely slightly wrong, but the -/// general idea should be correct. -/// -/// When talking about symbols, it's helpful to know a few things about where -/// symbols are located. Some symbols are located in the dynamic symbol table -/// of the executable which in theory means that they're available for dynamic -/// linking and lookup. Other symbols end up only in the local symbol table of -/// the file. This loosely corresponds to pub and priv functions in Rust. -/// -/// Armed with this knowledge, we know that our solution for address to symbol -/// translation will need to consult both the local and dynamic symbol tables. -/// With that in mind, here's our options of translating an address to -/// a symbol. -/// -/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr() -/// behind the scenes to translate, and this is why backtrace() was not used. -/// Conveniently, this method works fantastically on macOS. It appears dladdr() -/// uses magic to consult the local symbol table, or we're putting everything -/// in the dynamic symbol table anyway. Regardless, for macOS, this is the -/// method used for translation. It's provided by the system and easy to do.o -/// -/// Sadly, all other systems have a dladdr() implementation that does not -/// consult the local symbol table. This means that most functions are blank -/// because they don't have symbols. This means that we need another solution. -/// -/// * Use unw_get_proc_name(). This is part of the libunwind api (not the -/// libgcc_s version of the libunwind api), but involves taking a dependency -/// to libunwind. We may pursue this route in the future if we bundle -/// libunwind, but libunwind was unwieldy enough that it was not chosen at -/// this time to provide this functionality. -/// -/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a -/// semi-reasonable solution. The stdlib already knows how to spawn processes, -/// so in theory it could invoke readelf, parse the output, and consult the -/// local/dynamic symbol tables from there. This ended up not getting chosen -/// due to the craziness of the idea plus the advent of the next option. -/// -/// * Use `libbacktrace`. It turns out that this is a small library bundled in -/// the gcc repository which provides backtrace and symbol translation -/// functionality. All we really need from it is the backtrace functionality, -/// and we only really need this on everything that's not macOS, so this is the -/// chosen route for now. -/// -/// In summary, the current situation uses libgcc_s to get a trace of stack -/// pointers, and we use dladdr() or libbacktrace to translate these addresses -/// to symbols. This is a bit of a hokey implementation as-is, but it works for -/// all unix platforms we support right now, so it at least gets the job done. - -pub use self::tracing::unwind_backtrace; -pub use self::printing::{foreach_symbol_fileline, resolve_symname}; - -// tracing impls: -mod tracing; -// symbol resolvers: -mod printing; - -#[cfg(not(target_os = "emscripten"))] -pub mod gnu { - use crate::io; - use crate::fs; - - use libc::c_char; - - #[cfg(not(any(target_os = "macos", target_os = "ios")))] - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) - } - - #[cfg(any(target_os = "macos", target_os = "ios"))] - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - use crate::env; - use crate::os::unix::ffi::OsStrExt; - - let filename = env::current_exe()?; - let file = fs::File::open(&filename)?; - let mut filename_cstr: Vec<_> = filename.as_os_str().as_bytes().iter() - .map(|&x| x as c_char).collect(); - filename_cstr.push(0); // Null terminate - Ok((filename_cstr, file)) - } -} - -pub struct BacktraceContext; diff --git a/src/libstd/sys/vxworks/backtrace/printing/dladdr.rs b/src/libstd/sys/vxworks/backtrace/printing/dladdr.rs deleted file mode 100644 index 202164dd3c4d7..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/printing/dladdr.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::io; -use crate::intrinsics; -use crate::ffi::CStr; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -pub fn resolve_symname(frame: Frame, - callback: F, - _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> -{ - unsafe { - let mut info: Dl_info = intrinsics::init(); - let symname = if dladdr(frame.exact_position as *mut _, &mut info) == 0 || - info.dli_sname.is_null() { - None - } else { - CStr::from_ptr(info.dli_sname).to_str().ok() - }; - callback(symname) - } -} - -#[repr(C)] -struct Dl_info { - dli_fname: *const libc::c_char, - dli_fbase: *mut libc::c_void, - dli_sname: *const libc::c_char, - dli_saddr: *mut libc::c_void, -} - -extern { - #[ link_name = "_rtld_dladdr" ] - fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int; -} diff --git a/src/libstd/sys/vxworks/backtrace/printing/mod.rs b/src/libstd/sys/vxworks/backtrace/printing/mod.rs deleted file mode 100644 index d090caede437a..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/printing/mod.rs +++ /dev/null @@ -1,33 +0,0 @@ -mod dladdr; - -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; -use crate::io; - -#[cfg(target_os = "emscripten")] -pub use self::dladdr::resolve_symname; - -#[cfg(target_os = "emscripten")] -pub fn foreach_symbol_fileline(_: Frame, _: F, _: &BacktraceContext) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()> -{ - Ok(false) -} - -#[cfg(not(target_os = "emscripten"))] -pub use crate::sys_common::gnu::libbacktrace::foreach_symbol_fileline; - -#[cfg(not(target_os = "emscripten"))] -pub fn resolve_symname(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()> -where - F: FnOnce(Option<&str>) -> io::Result<()> -{ - crate::sys_common::gnu::libbacktrace::resolve_symname(frame, |symname| { - if symname.is_some() { - callback(symname) - } else { - dladdr::resolve_symname(frame, callback, bc) - } - }, bc) -} diff --git a/src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs deleted file mode 100644 index a628d107ad6fb..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs +++ /dev/null @@ -1,39 +0,0 @@ -/// As always - iOS on arm uses SjLj exceptions and -/// _Unwind_Backtrace is even not available there. Still, -/// backtraces could be extracted using a backtrace function, -/// which thanks god is public -/// -/// As mentioned in a huge comment block in `super::super`, backtrace -/// doesn't play well with green threads, so while it is extremely nice and -/// simple to use it should be used only on iOS devices as the only viable -/// option. - -use crate::io; -use crate::ptr; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -#[inline(never)] // if we know this is a function call, we can skip it when - // tracing -pub fn unwind_backtrace(frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - const FRAME_LEN: usize = 100; - assert!(FRAME_LEN >= frames.len()); - let mut raw_frames = [ptr::null_mut(); FRAME_LEN]; - let nb_frames = unsafe { - backtrace(raw_frames.as_mut_ptr(), raw_frames.len() as libc::c_int) - } as usize; - for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) { - *to = Frame { - exact_position: *from as *mut u8, - symbol_addr: *from as *mut u8, - inline_context: 0, - }; - } - Ok((nb_frames as usize, BacktraceContext)) -} - -extern { - fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int; -} diff --git a/src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs b/src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs deleted file mode 100644 index e6379132bafbe..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::error::Error; -use crate::fmt; -use crate::io; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -use unwind as uw; - -struct Context<'a> { - idx: usize, - frames: &'a mut [Frame], -} - -#[derive(Debug)] -struct UnwindError(uw::_Unwind_Reason_Code); - -impl Error for UnwindError { - fn description(&self) -> &'static str { - "unexpected return value while unwinding" - } -} - -impl fmt::Display for UnwindError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {:?}", self.description(), self.0) - } -} - -#[inline(never)] // if we know this is a function call, we can skip it when - // tracing -pub fn unwind_backtrace(frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - let mut cx = Context { - idx: 0, - frames, - }; - let result_unwind = unsafe { - uw::_Unwind_Backtrace(trace_fn, - &mut cx as *mut Context<'_> - as *mut libc::c_void) - }; - // See libunwind:src/unwind/Backtrace.c for the return values. - // No, there is no doc. - match result_unwind { - // These return codes seem to be benign and need to be ignored for backtraces - // to show up properly on all tested platforms. - uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { - Ok((cx.idx, BacktraceContext)) - } - _ => { - Err(io::Error::new(io::ErrorKind::Other, - UnwindError(result_unwind))) - } - } -} - -extern fn trace_fn(ctx: *mut uw::_Unwind_Context, - arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { - let cx = unsafe { &mut *(arg as *mut Context<'_>) }; - if cx.idx >= cx.frames.len() { - return uw::_URC_NORMAL_STOP; - } - - let mut ip_before_insn = 0; - let mut ip = unsafe { - uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void - }; - if !ip.is_null() && ip_before_insn == 0 { - // this is a non-signaling frame, so `ip` refers to the address - // after the calling instruction. account for that. - ip = (ip as usize - 1) as *mut _; - } - - // dladdr() on osx gets whiny when we use FindEnclosingFunction, and - // it appears to work fine without it, so we only use - // FindEnclosingFunction on non-osx platforms. In doing so, we get a - // slightly more accurate stack trace in the process. - // - // This is often because panic involves the last instruction of a - // function being "call std::rt::begin_unwind", with no ret - // instructions after it. This means that the return instruction - // pointer points *outside* of the calling function, and by - // unwinding it we go back to the original function. - let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") { - ip - } else { - unsafe { uw::_Unwind_FindEnclosingFunction(ip) } - }; - - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - - uw::_URC_NO_REASON -} diff --git a/src/libstd/sys/vxworks/backtrace/tracing/mod.rs b/src/libstd/sys/vxworks/backtrace/tracing/mod.rs deleted file mode 100644 index 11863e6454525..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/tracing/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub use self::imp::*; - -#[cfg(not(all(target_os = "ios", target_arch = "arm")))] -#[path = "gcc_s.rs"] -mod imp; -#[cfg(all(target_os = "ios", target_arch = "arm"))] -#[path = "backtrace_fn.rs"] -mod imp; diff --git a/src/libstd/sys/vxworks/fast_thread_local.rs b/src/libstd/sys/vxworks/fast_thread_local.rs index f5a2e263d25e7..8b55939b8e54a 100644 --- a/src/libstd/sys/vxworks/fast_thread_local.rs +++ b/src/libstd/sys/vxworks/fast_thread_local.rs @@ -1,33 +1,8 @@ #![cfg(target_thread_local)] #![unstable(feature = "thread_local_internals", issue = "0")] -// Since what appears to be glibc 2.18 this symbol has been shipped which -// GCC and clang both use to invoke destructors in thread_local globals, so -// let's do the same! -// -// Note, however, that we run on lots older linuxes, as well as cross -// compiling from a newer linux to an older linux, so we also have a -// fallback implementation to use as well. -// -// Due to rust-lang/rust#18804, make sure this is not generic! pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { - use crate::mem; use crate::sys_common::thread_local::register_dtor_fallback; - - extern { - #[linkage = "extern_weak"] - static __dso_handle: *mut u8; - #[linkage = "extern_weak"] - static __cxa_thread_atexit_impl: *const libc::c_void; - } - if !__cxa_thread_atexit_impl.is_null() { - type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8), - arg: *mut u8, - dso_handle: *mut u8) -> libc::c_int; - mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl) - (dtor, t, &__dso_handle as *const _ as *mut _); - return - } register_dtor_fallback(t, dtor); } diff --git a/src/libstd/sys/vxworks/fs.rs b/src/libstd/sys/vxworks/fs.rs index d537d2258fda7..51fdb1c0e55ec 100644 --- a/src/libstd/sys/vxworks/fs.rs +++ b/src/libstd/sys/vxworks/fs.rs @@ -529,7 +529,7 @@ pub fn stat(p: &Path) -> io::Result { let p = cstr(p)?; let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { - libc::lstat(p.as_ptr(), &mut stat as *mut _ as *mut _) + libc::stat(p.as_ptr(), &mut stat as *mut _ as *mut _) })?; Ok(FileAttr { stat }) } diff --git a/src/libstd/sys/vxworks/os.rs b/src/libstd/sys/vxworks/os.rs index 5dc35a6176bce..f4798da1876cf 100644 --- a/src/libstd/sys/vxworks/os.rs +++ b/src/libstd/sys/vxworks/os.rs @@ -287,28 +287,7 @@ pub fn temp_dir() -> PathBuf { } pub fn home_dir() -> Option { - return crate::env::var_os("HOME").or_else(|| unsafe { - fallback() - }).map(PathBuf::from); - - unsafe fn fallback() -> Option { - let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) { - n if n < 0 => 512 as usize, - n => n as usize, - }; - let mut buf = Vec::with_capacity(amt); - let mut passwd: libc::passwd = mem::zeroed(); - let mut result = ptr::null_mut(); - match libc::getpwuid_r(libc::getuid(), &mut passwd, buf.as_mut_ptr(), - buf.capacity(), &mut result) { - 0 if !result.is_null() => { - let ptr = passwd.pw_dir as *const _; - let bytes = CStr::from_ptr(ptr).to_bytes().to_vec(); - Some(OsStringExt::from_vec(bytes)) - }, - _ => None, - } - } + None } pub fn exit(code: i32) -> ! { diff --git a/src/libstd/sys/vxworks/process/mod.rs b/src/libstd/sys/vxworks/process/mod.rs index 4dc706006f4ce..3ecbe4e3b28ba 100644 --- a/src/libstd/sys/vxworks/process/mod.rs +++ b/src/libstd/sys/vxworks/process/mod.rs @@ -1,7 +1,7 @@ pub use self::process_common::{Command, ExitStatus, ExitCode, Stdio, StdioPipes}; pub use self::process_inner::Process; +pub use crate::ffi::OsString as EnvKey; mod process_common; #[path = "process_vxworks.rs"] mod process_inner; -mod rtp; diff --git a/src/libstd/sys/vxworks/process/process_common.rs b/src/libstd/sys/vxworks/process/process_common.rs index 397200c39c2d7..13648abd1e447 100644 --- a/src/libstd/sys/vxworks/process/process_common.rs +++ b/src/libstd/sys/vxworks/process/process_common.rs @@ -7,7 +7,7 @@ use crate::ptr; use crate::sys::fd::FileDesc; use crate::sys::fs::{File, OpenOptions}; use crate::sys::pipe::{self, AnonPipe}; -use crate::sys_common::process::{CommandEnv, DefaultEnvKey}; +use crate::sys_common::process::CommandEnv; use crate::collections::BTreeMap; use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE}; @@ -37,7 +37,7 @@ pub struct Command { program: CString, args: Vec, argv: Argv, - env: CommandEnv, + env: CommandEnv, cwd: Option, uid: Option, @@ -155,7 +155,7 @@ impl Command { _f: Box io::Result<()> + Send + Sync>, ) { // Fork() is not supported in vxWorks so no way to run the closure in the new procecss. - unimplemented!();; + unimplemented!(); } pub fn stdin(&mut self, stdin: Stdio) { @@ -170,7 +170,7 @@ impl Command { self.stderr = Some(stderr); } - pub fn env_mut(&mut self) -> &mut CommandEnv { + pub fn env_mut(&mut self) -> &mut CommandEnv { &mut self.env } @@ -240,7 +240,7 @@ impl CStringArray { } } -fn construct_envp(env: BTreeMap, saw_nul: &mut bool) -> CStringArray { +fn construct_envp(env: BTreeMap, saw_nul: &mut bool) -> CStringArray { let mut result = CStringArray::with_capacity(env.len()); for (k, v) in env { let mut k: OsString = k.into(); diff --git a/src/libstd/sys/vxworks/process/process_vxworks.rs b/src/libstd/sys/vxworks/process/process_vxworks.rs index b07966fa20626..7446471ae3122 100644 --- a/src/libstd/sys/vxworks/process/process_vxworks.rs +++ b/src/libstd/sys/vxworks/process/process_vxworks.rs @@ -3,8 +3,8 @@ use libc::{self, c_int, c_char}; use libc::{RTP_ID}; use crate::sys; use crate::sys::cvt; -use crate::sys::process::rtp; use crate::sys::process::process_common::*; +use crate::sys_common::thread; //////////////////////////////////////////////////////////////////////////////// // Command @@ -52,13 +52,12 @@ impl Command { t!(cvt(libc::chdir(cwd.as_ptr()))); } - let ret = rtp::rtpSpawn( + let ret = libc::rtpSpawn( self.get_argv()[0], // executing program - self.get_argv().as_ptr() as *const _, // argv - *sys::os::environ() as *const *const c_char, + self.get_argv().as_ptr() as *mut *const c_char, // argv + *sys::os::environ() as *mut *const c_char, 100 as c_int, // initial priority - 0x16000, // initial stack size. 0 defaults - // to 0x4000 in 32 bit and 0x8000 in 64 bit + thread::min_stack(), // initial stack size. 0, // options 0 // task options ); @@ -78,7 +77,7 @@ impl Command { libc::close(orig_stderr); } - if ret != rtp::RTP_ID_ERROR { + if ret != libc::RTP_ID_ERROR { p.pid = ret; Ok((p, ours)) } else { diff --git a/src/libstd/sys/vxworks/process/rtp.rs b/src/libstd/sys/vxworks/process/rtp.rs deleted file mode 100644 index 3e6e0017abcb5..0000000000000 --- a/src/libstd/sys/vxworks/process/rtp.rs +++ /dev/null @@ -1,298 +0,0 @@ -#![allow(non_camel_case_types, unused)] - -use libc::{self, c_int, size_t, c_char, BOOL, RTP_DESC, RTP_ID, TASK_ID}; - - -// Copied directly from rtpLibCommon.h, rtpLib.h, signal.h and taskLibCommon.h (for task options) - -// **** definitions for rtpLibCommon.h **** - -pub const RTP_GLOBAL_SYMBOLS : c_int = 0x01; // register global symbols for RTP -pub const RTP_LOCAL_SYMBOLS : c_int = 0x02; // idem for local symbols -pub const RTP_ALL_SYMBOLS : c_int = (RTP_GLOBAL_SYMBOLS | RTP_LOCAL_SYMBOLS); -pub const RTP_DEBUG : c_int = 0x10; // set RTP in debug mode when created -pub const RTP_BUFFER_VAL_OFF : c_int = 0x20; // disable buffer validation for all - // system calls issued from the RTP -pub const RTP_LOADED_WAIT : c_int = 0x40; // Wait until the RTP is loaded -pub const RTP_CPU_AFFINITY_NONE : c_int = 0x80; // Remove any CPU affinity (SMP) - -// Error Status codes - -pub const M_rtpLib : c_int = 178 << 16; - -pub const S_rtpLib_INVALID_FILE : c_int = (M_rtpLib | 1); -pub const S_rtpLib_INVALID_OPTION : c_int = (M_rtpLib | 2); -pub const S_rtpLib_ACCESS_DENIED : c_int = (M_rtpLib | 3); -pub const S_rtpLib_INVALID_RTP_ID : c_int = (M_rtpLib | 4); -pub const S_rtpLib_NO_SYMBOL_TABLE : c_int = (M_rtpLib | 5); -pub const S_rtpLib_INVALID_SEGMENT_START_ADDRESS : c_int = (M_rtpLib | 6); -pub const S_rtpLib_INVALID_SYMBOL_REGISTR_POLICY : c_int = (M_rtpLib | 7); -pub const S_rtpLib_INSTANTIATE_FAILED : c_int = (M_rtpLib | 8); -pub const S_rtpLib_INVALID_TASK_OPTION : c_int = (M_rtpLib | 9); -pub const S_rtpLib_RTP_NAME_LENGTH_EXCEEDED : c_int = (M_rtpLib | 10); // rtpInfoGet - -pub const VX_RTP_NAME_LENGTH : c_int = 255; // max name length for diplay - - -// The 'status' field (32 bit integer) of a RTP holds the RTP state and status. -// -// NOTE: RTP_STATE_GET() : read the RTP state(s) -// RTP_STATE_PUT() : write the RTP state(s) -// RTP_STATE_SET() : set a RTP state -// RTP_STATE_UNSET() : unset a RTP state -// -// RTP_STATUS_GET() : read the RTP status -// RTP_STATUS_PUT() : write the RTP status -// RTP_STATUS_SET() : set a RTP status -// RTP_STATUS_UNSET() : unset a RTP status -// -// The PUT/SET/UNSET macros are available only in the kernel headers. - - -// RTP states - -pub const RTP_STATE_CREATE : c_int = 0x0001; // RrtpStructTP is under construction -pub const RTP_STATE_NORMAL : c_int = 0x0002; // RrtpStructTP is ready -pub const RTP_STATE_DELETE : c_int = 0x0004; // RrtpStructTP is being deleted - -pub const RTP_STATUS_STOP : c_int = 0x0100; // RTP hrtpStructas recieved stopped signal -pub const RTP_STATUS_ELECTED_DELETER : c_int = 0x0200; // RTP drtpStructelete has started - -pub const RTP_STATE_MASK : c_int = (RTP_STATE_CREATE | RTP_STATE_NORMAL | - RTP_STATE_DELETE); -pub const RTP_STATUS_MASK : c_int = (RTP_STATUS_STOP | RTP_STATUS_ELECTED_DELETER); - -pub fn RTP_STATE_GET (value : c_int) -> c_int { - value & RTP_STATE_MASK -} -pub fn RTP_STATUS_GET (value : c_int) -> c_int { - value & RTP_STATUS_MASK -} - -// Indicates that the RTP_ID returned is not valid. - -// RTP_ID_ERROR is supposed to be set to -1, but you can't set -// an unsigned value to a negative without casting, and you -// can't cast unless the size of the integer types are the same, -// but the size of RTP_ID may differ between kernel and user space. -// Bitwise or-ing min and max should get the same result. -pub const RTP_ID_ERROR : RTP_ID = RTP_ID::min_value() | RTP_ID::max_value(); - -// IS_RTP_ C macros - -pub fn IS_RTP_STATE_NORMAL (value : c_int) -> bool { - (RTP_STATE_GET(value) & RTP_STATE_NORMAL) == RTP_STATE_NORMAL -} -pub fn IS_RTP_STATE_CREATE (value : c_int) -> bool { - (RTP_STATE_GET(value) & RTP_STATE_CREATE) == RTP_STATE_CREATE -} -pub fn IS_RTP_STATE_DELETE (value : c_int) -> bool { - (RTP_STATE_GET(value) & RTP_STATE_DELETE) == RTP_STATE_DELETE -} -pub fn IS_RTP_STATUS_STOP (value : c_int) -> bool { - (RTP_STATUS_GET(value) & RTP_STATUS_STOP ) == RTP_STATUS_STOP -} -pub fn IS_RTP_STATUS_ELECTED_DELETER (value : c_int) -> bool { - (RTP_STATUS_GET(value) & RTP_STATUS_ELECTED_DELETER) == RTP_STATUS_ELECTED_DELETER -} - -// **** end of definitions for rtpLibCommon.h **** - - - - -// **** definitions for rtpLib.h **** - -pub fn rtpExit(exitCode : c_int) -> ! { - unsafe{ libc::exit (exitCode) } -} - -/* rtpLib.h in the kernel -pub const RTP_DEL_VIA_TASK_DELETE : c_int = 0x1; // rtpDelete() via taskDestroy() -pub const RTP_DEL_FORCE : c_int = 0x2; // Forceful rtpDelete() -pub const RTP_ID_ANY : RTP_ID = 0; // used for when a kernel task - // wants to wait for the next - // RTP to finish - - -// Function pointers - -pub type RTP_PRE_CREATE_HOOK = size_t; -pub type RTP_POST_CREATE_HOOK = size_t; -pub type RTP_INIT_COMPLETE_HOOK = size_t; -pub type RTP_DELETE_HOOK = size_t; -*/ - -// **** end of definitions for rtpLib.h **** - - - - - -// **** definitions for signal.h **** -pub fn rtpKill(rtpId : RTP_ID, signo : c_int) -> c_int { - unsafe{ libc::kill(rtpId as c_int, signo) } -} - -pub fn rtpSigqueue(rtpId : RTP_ID, signo : c_int, value : size_t) -> c_int { - unsafe{ libc::sigqueue(rtpId as c_int, signo, value) } -} - -pub fn _rtpSigqueue(rtpId : RTP_ID, signo : c_int, value : *mut size_t, code : c_int) -> c_int { - unsafe{ libc::_sigqueue(rtpId, signo, value, code) } -} - -pub fn taskRaise(signo : c_int) -> c_int { - unsafe{ libc::taskKill(libc::taskIdSelf(), signo) } -} -pub fn rtpRaise(signo : c_int) -> c_int { - unsafe{ libc::raise(signo) } -} - -// **** end of definitions for signal.h **** - - - -// **** definitions for taskLibCommon.h **** -pub const VX_PRIVATE_ENV : c_int = 0x0080; // 1 = private environment variables -pub const VX_NO_STACK_FILL : c_int = 0x0100; // 1 = avoid stack fill of 0xee -pub const VX_PRIVATE_UMASK : c_int = 0x0400; // 1 = private file creation mode mask -pub const VX_TASK_NOACTIVATE : c_int = 0x2000; // taskOpen() does not taskActivate() -pub const VX_NO_STACK_PROTECT : c_int = 0x4000; // no over/underflow stack protection, - // stack space remains executable - -// define for all valid user task options - -pub const VX_USR_TASK_OPTIONS_BASE: c_int = (VX_PRIVATE_ENV | - VX_NO_STACK_FILL | - VX_TASK_NOACTIVATE | - VX_NO_STACK_PROTECT | - VX_PRIVATE_UMASK); - -// **** end of definitions for taskLibCommon.h **** - - - -extern "C" { -// functions in rtpLibCommon.h - -// forward declarations - pub fn rtpSpawn ( - pubrtpFileName : *const c_char, - argv : *const *const c_char, - envp : *const *const c_char, - priority : c_int, - uStackSize : size_t, - options : c_int, - taskOptions : c_int, - ) -> RTP_ID; - - pub fn rtpInfoGet ( - rtpId : RTP_ID, - rtpStruct : *mut RTP_DESC, - ) -> c_int; - -/* functions in rtpLib.h for kernel - - - // function declarations - - pub fn rtpDelete ( - id : RTP_ID, - options : c_int, - status : c_int, - ) -> c_int; - - pub fn rtpDeleteForce ( - rtpId : RTP_ID - ) -> c_int; - - pub fn rtpShow ( - rtpNameOrId : *mut c_char, - level : c_int, - ) -> BOOL; - - // RTP signals are always present when RTPs are included. The public RTP - // signal APIs are declared here. - - - pub fn rtpKill ( - rtpId : RTP_ID, - signo : c_int, - ) -> c_int; - - pub fn rtpSigqueue ( - rtpId : RTP_ID, - signo : c_int, - value : size_t, // Actual type is const union sigval value, - // which is a union of int and void * - ) -> c_int; - - pub fn rtpTaskKill ( - tid : TASK_ID, - signo : c_int, - ) -> c_int; - - pub fn rtpTaskSigqueue ( - tid : TASK_ID, - signo : c_int, - value : const size_t, // Actual type is const union sigval, - // which is a union of int and void * - ) -> c_int; - - pub fn rtpWait ( - rtpWaitId : RTP_ID, - timeout : libc::alloc_jemalloc_Vx_ticks_t, - pRtpId : *mut RTP_ID, - pStatus : *mut c_int, - ) -> c_int; - - // Other public functions - - - pub fn rtpPreCreateHookAdd ( - hook : RTP_PRE_CREATE_HOOK, - addToHead : BOOL, - ) -> c_int; - - pub fn rtpPreCreateHookDelete ( - hook : RTP_POST_CREATE_HOOK, - ) -> c_int; - - pub fn rtpPostCreateHookAdd ( - hook : RTP_POST_CREATE_HOOK, - addToHead : BOOL, - ) -> c_int; - - pub fn rtpPostCreateHookDelete ( - hook : RTP_POST_CREATE_HOOK, - ) -> c_int; - - pub fn rtpInitCompleteHookAdd ( - hook : RTP_INIT_COMPLETE_HOOK, - addToHead : BOOL, - ) -> c_int; - - pub fn rtpInitCompleteHookDelete ( - hook : RTP_INIT_COMPLETE_HOOK, - ) -> c_int; - - pub fn rtpDeleteHookAdd ( - hook : RTP_DELETE_HOOK, - addToHead : BOOL, - ) -> c_int; - - pub fn rtpDeleteHookDelete ( - hook : RTP_DELETE_HOOK, - ) -> c_int; - - pub fn rtpMemShow ( - rtpNameOrId : *mut c_char, - level : c_int, - ) -> c_int; - - pub fn rtpHookShow ( - - ); -*/ -} diff --git a/src/libstd/sys/vxworks/rand.rs b/src/libstd/sys/vxworks/rand.rs index 1ec0cbe4dcf5b..c22880db2bf03 100644 --- a/src/libstd/sys/vxworks/rand.rs +++ b/src/libstd/sys/vxworks/rand.rs @@ -14,17 +14,24 @@ pub fn hashmap_random_keys() -> (u64, u64) { mod imp { use libc; use crate::io; - - extern "C" { - fn randBytes (randBuf: *mut libc::c_uchar, - numOfBytes: libc::c_int) -> libc::c_int; - } + use core::sync::atomic::{AtomicBool, Ordering::Relaxed}; pub fn fill_bytes(v: &mut [u8]) { + static RNG_INIT: AtomicBool = AtomicBool::new(false); + while !RNG_INIT.load(Relaxed) { + let ret = unsafe { libc::randSecure() }; + if ret < 0 { + panic!("couldn't generate random bytes: {}", io::Error::last_os_error()); + } else if ret > 0 { + RNG_INIT.store(true, Relaxed); + break; + } + unsafe { libc::usleep(10) }; + } let ret = unsafe { - randBytes(v.as_mut_ptr() as *mut libc::c_uchar, v.len() as libc::c_int) + libc::randABytes(v.as_mut_ptr() as *mut libc::c_uchar, v.len() as libc::c_int) }; - if ret == -1 { + if ret < 0 { panic!("couldn't generate random bytes: {}", io::Error::last_os_error()); } } diff --git a/src/libstd/sys/vxworks/rwlock.rs b/src/libstd/sys/vxworks/rwlock.rs index 718f422ed11e6..19b123f2b6131 100644 --- a/src/libstd/sys/vxworks/rwlock.rs +++ b/src/libstd/sys/vxworks/rwlock.rs @@ -25,7 +25,7 @@ impl RWLock { let r = libc::pthread_rwlock_rdlock(self.inner.get()); if r == libc::EAGAIN { panic!("rwlock maximum reader count exceeded"); - } else if r == libc::EDEADLK || *self.write_locked.get() { + } else if r == libc::EDEADLK || (r == 0 && *self.write_locked.get()) { if r == 0 { self.raw_unlock(); } diff --git a/src/libstd/sys/vxworks/thread.rs b/src/libstd/sys/vxworks/thread.rs index 58af8cbe48e36..e4396b05c0065 100644 --- a/src/libstd/sys/vxworks/thread.rs +++ b/src/libstd/sys/vxworks/thread.rs @@ -8,7 +8,7 @@ use crate::time::Duration; use crate::sys_common::thread::*; -pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; +pub const DEFAULT_MIN_STACK_SIZE: usize = 0x40000; // 256K pub struct Thread { id: libc::pthread_t, @@ -77,7 +77,7 @@ impl Thread { } pub fn set_name(_name: &CStr) { - assert!(false, "FIXME: set_name"); + // VxWorks does not provide a way to set the task name except at creation time } pub fn sleep(dur: Duration) { diff --git a/src/libstd/sys/wasi/args.rs b/src/libstd/sys/wasi/args.rs index 8b4b354d9fc20..3280c4990dc66 100644 --- a/src/libstd/sys/wasi/args.rs +++ b/src/libstd/sys/wasi/args.rs @@ -1,11 +1,10 @@ -use crate::ffi::CStr; -use crate::io; -use crate::sys::cvt_wasi; use crate::ffi::OsString; use crate::marker::PhantomData; use crate::os::wasi::ffi::OsStringExt; use crate::vec; +use ::wasi::wasi_unstable as wasi; + pub unsafe fn init(_argc: isize, _argv: *const *const u8) { } @@ -19,31 +18,17 @@ pub struct Args { /// Returns the command line arguments pub fn args() -> Args { - maybe_args().unwrap_or_else(|_| { - Args { - iter: Vec::new().into_iter(), - _dont_send_or_sync_me: PhantomData - } - }) -} - -fn maybe_args() -> io::Result { - unsafe { - let (mut argc, mut argv_buf_size) = (0, 0); - cvt_wasi(libc::__wasi_args_sizes_get(&mut argc, &mut argv_buf_size))?; - - let mut argc = vec![core::ptr::null_mut::(); argc]; - let mut argv_buf = vec![0; argv_buf_size]; - cvt_wasi(libc::__wasi_args_get(argc.as_mut_ptr(), argv_buf.as_mut_ptr()))?; - - let args = argc.into_iter() - .map(|ptr| CStr::from_ptr(ptr).to_bytes().to_vec()) - .map(|bytes| OsString::from_vec(bytes)) - .collect::>(); - Ok(Args { - iter: args.into_iter(), - _dont_send_or_sync_me: PhantomData, - }) + let buf = wasi::args_sizes_get().and_then(|args_sizes| { + let mut buf = Vec::with_capacity(args_sizes.get_count()); + wasi::args_get(args_sizes, |arg| { + let arg = OsString::from_vec(arg.to_vec()); + buf.push(arg); + })?; + Ok(buf) + }).unwrap_or(vec![]); + Args { + iter: buf.into_iter(), + _dont_send_or_sync_me: PhantomData } } diff --git a/src/libstd/sys/wasi/ext/fs.rs b/src/libstd/sys/wasi/ext/fs.rs index 0ec4122f385da..9fa4abfd171b5 100644 --- a/src/libstd/sys/wasi/ext/fs.rs +++ b/src/libstd/sys/wasi/ext/fs.rs @@ -8,6 +8,8 @@ use crate::os::wasi::ffi::OsStrExt; use crate::path::{Path, PathBuf}; use crate::sys_common::{AsInner, AsInnerMut, FromInner}; +use ::wasi::wasi_unstable as wasi; + /// WASI-specific extensions to [`File`]. /// /// [`File`]: ../../../../std/fs/struct.File.html @@ -336,16 +338,16 @@ pub trait FileTypeExt { impl FileTypeExt for fs::FileType { fn is_block_device(&self) -> bool { - self.as_inner().bits() == libc::__WASI_FILETYPE_BLOCK_DEVICE + self.as_inner().bits() == wasi::FILETYPE_BLOCK_DEVICE } fn is_character_device(&self) -> bool { - self.as_inner().bits() == libc::__WASI_FILETYPE_CHARACTER_DEVICE + self.as_inner().bits() == wasi::FILETYPE_CHARACTER_DEVICE } fn is_socket_dgram(&self) -> bool { - self.as_inner().bits() == libc::__WASI_FILETYPE_SOCKET_DGRAM + self.as_inner().bits() == wasi::FILETYPE_SOCKET_DGRAM } fn is_socket_stream(&self) -> bool { - self.as_inner().bits() == libc::__WASI_FILETYPE_SOCKET_STREAM + self.as_inner().bits() == wasi::FILETYPE_SOCKET_STREAM } } diff --git a/src/libstd/sys/wasi/ext/io.rs b/src/libstd/sys/wasi/ext/io.rs index 12afd1d42dc19..f1839df380112 100644 --- a/src/libstd/sys/wasi/ext/io.rs +++ b/src/libstd/sys/wasi/ext/io.rs @@ -8,6 +8,8 @@ use crate::sys; use crate::net; use crate::sys_common::{AsInner, FromInner, IntoInner}; +use ::wasi::wasi_unstable as wasi; + /// Raw file descriptors. pub type RawFd = u32; @@ -125,18 +127,18 @@ impl IntoRawFd for fs::File { impl AsRawFd for io::Stdin { fn as_raw_fd(&self) -> RawFd { - libc::STDIN_FILENO as u32 + wasi::STDIN_FD } } impl AsRawFd for io::Stdout { fn as_raw_fd(&self) -> RawFd { - libc::STDOUT_FILENO as u32 + wasi::STDOUT_FD } } impl AsRawFd for io::Stderr { fn as_raw_fd(&self) -> RawFd { - libc::STDERR_FILENO as u32 + wasi::STDERR_FD } } diff --git a/src/libstd/sys/wasi/fd.rs b/src/libstd/sys/wasi/fd.rs index 25692ec086801..5b7a8678b66ea 100644 --- a/src/libstd/sys/wasi/fd.rs +++ b/src/libstd/sys/wasi/fd.rs @@ -3,348 +3,248 @@ use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; use crate::mem; use crate::net::Shutdown; -use crate::sys::cvt_wasi; -use libc::{self, c_char, c_void}; +use super::err2io; +use ::wasi::wasi_unstable as wasi; #[derive(Debug)] pub struct WasiFd { - fd: libc::__wasi_fd_t, + fd: wasi::Fd, } -// FIXME: these should probably all be fancier structs, builders, enums, etc -pub type LookupFlags = u32; -pub type FdFlags = u16; -pub type Advice = u8; -pub type Rights = u64; -pub type Oflags = u16; -pub type DirCookie = u64; -pub type Timestamp = u64; -pub type FstFlags = u16; -pub type RiFlags = u16; -pub type RoFlags = u16; -pub type SiFlags = u16; - -fn iovec(a: &mut [IoSliceMut<'_>]) -> (*const libc::__wasi_iovec_t, usize) { +fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::IoVec] { assert_eq!( mem::size_of::>(), - mem::size_of::() + mem::size_of::() ); assert_eq!( mem::align_of::>(), - mem::align_of::() + mem::align_of::() ); - (a.as_ptr() as *const libc::__wasi_iovec_t, a.len()) + /// SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout + unsafe { mem::transmute(a) } } -fn ciovec(a: &[IoSlice<'_>]) -> (*const libc::__wasi_ciovec_t, usize) { +fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::CIoVec] { assert_eq!( mem::size_of::>(), - mem::size_of::() + mem::size_of::() ); assert_eq!( mem::align_of::>(), - mem::align_of::() + mem::align_of::() ); - (a.as_ptr() as *const libc::__wasi_ciovec_t, a.len()) + /// SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout + unsafe { mem::transmute(a) } } impl WasiFd { - pub unsafe fn from_raw(fd: libc::__wasi_fd_t) -> WasiFd { + pub unsafe fn from_raw(fd: wasi::Fd) -> WasiFd { WasiFd { fd } } - pub fn into_raw(self) -> libc::__wasi_fd_t { + pub fn into_raw(self) -> wasi::Fd { let ret = self.fd; mem::forget(self); ret } - pub fn as_raw(&self) -> libc::__wasi_fd_t { + pub fn as_raw(&self) -> wasi::Fd { self.fd } pub fn datasync(&self) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_datasync(self.fd) }) + unsafe { wasi::fd_datasync(self.fd).map_err(err2io) } } pub fn pread(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { - let mut read = 0; - let (ptr, len) = iovec(bufs); - cvt_wasi(unsafe { libc::__wasi_fd_pread(self.fd, ptr, len, offset, &mut read) })?; - Ok(read) + unsafe { wasi::fd_pread(self.fd, iovec(bufs), offset).map_err(err2io) } } pub fn pwrite(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { - let mut read = 0; - let (ptr, len) = ciovec(bufs); - cvt_wasi(unsafe { libc::__wasi_fd_pwrite(self.fd, ptr, len, offset, &mut read) })?; - Ok(read) + unsafe { wasi::fd_pwrite(self.fd, ciovec(bufs), offset).map_err(err2io) } } pub fn read(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - let mut read = 0; - let (ptr, len) = iovec(bufs); - cvt_wasi(unsafe { libc::__wasi_fd_read(self.fd, ptr, len, &mut read) })?; - Ok(read) + unsafe { wasi::fd_read(self.fd, iovec(bufs)).map_err(err2io) } } pub fn write(&self, bufs: &[IoSlice<'_>]) -> io::Result { - let mut read = 0; - let (ptr, len) = ciovec(bufs); - cvt_wasi(unsafe { libc::__wasi_fd_write(self.fd, ptr, len, &mut read) })?; - Ok(read) + unsafe { wasi::fd_write(self.fd, ciovec(bufs)).map_err(err2io) } } pub fn seek(&self, pos: SeekFrom) -> io::Result { let (whence, offset) = match pos { - SeekFrom::Start(pos) => (libc::__WASI_WHENCE_SET, pos as i64), - SeekFrom::End(pos) => (libc::__WASI_WHENCE_END, pos), - SeekFrom::Current(pos) => (libc::__WASI_WHENCE_CUR, pos), + SeekFrom::Start(pos) => (wasi::WHENCE_SET, pos as i64), + SeekFrom::End(pos) => (wasi::WHENCE_END, pos), + SeekFrom::Current(pos) => (wasi::WHENCE_CUR, pos), }; - let mut pos = 0; - cvt_wasi(unsafe { libc::__wasi_fd_seek(self.fd, offset, whence, &mut pos) })?; - Ok(pos) + unsafe { wasi::fd_seek(self.fd, offset, whence).map_err(err2io) } } pub fn tell(&self) -> io::Result { - let mut pos = 0; - cvt_wasi(unsafe { libc::__wasi_fd_tell(self.fd, &mut pos) })?; - Ok(pos) + unsafe { wasi::fd_tell(self.fd).map_err(err2io) } } // FIXME: __wasi_fd_fdstat_get - pub fn set_flags(&self, flags: FdFlags) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_fdstat_set_flags(self.fd, flags) }) + pub fn set_flags(&self, flags: wasi::FdFlags) -> io::Result<()> { + unsafe { wasi::fd_fdstat_set_flags(self.fd, flags).map_err(err2io) } } - pub fn set_rights(&self, base: Rights, inheriting: Rights) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_fdstat_set_rights(self.fd, base, inheriting) }) + pub fn set_rights(&self, base: wasi::Rights, inheriting: wasi::Rights) -> io::Result<()> { + unsafe { wasi::fd_fdstat_set_rights(self.fd, base, inheriting).map_err(err2io) } } pub fn sync(&self) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_sync(self.fd) }) + unsafe { wasi::fd_sync(self.fd).map_err(err2io) } } - pub fn advise(&self, offset: u64, len: u64, advice: Advice) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_advise(self.fd, offset, len, advice as u8) }) + pub fn advise(&self, offset: u64, len: u64, advice: wasi::Advice) -> io::Result<()> { + unsafe { wasi::fd_advise(self.fd, offset, len, advice).map_err(err2io) } } pub fn allocate(&self, offset: u64, len: u64) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_allocate(self.fd, offset, len) }) + unsafe { wasi::fd_allocate(self.fd, offset, len).map_err(err2io) } } pub fn create_directory(&self, path: &[u8]) -> io::Result<()> { - cvt_wasi(unsafe { - libc::__wasi_path_create_directory(self.fd, path.as_ptr() as *const c_char, path.len()) - }) + unsafe { wasi::path_create_directory(self.fd, path).map_err(err2io) } } pub fn link( &self, - old_flags: LookupFlags, + old_flags: wasi::LookupFlags, old_path: &[u8], new_fd: &WasiFd, new_path: &[u8], ) -> io::Result<()> { - cvt_wasi(unsafe { - libc::__wasi_path_link( - self.fd, - old_flags, - old_path.as_ptr() as *const c_char, - old_path.len(), - new_fd.fd, - new_path.as_ptr() as *const c_char, - new_path.len(), - ) - }) + unsafe { + wasi::path_link(self.fd, old_flags, old_path, new_fd.fd, new_path) + .map_err(err2io) + } } pub fn open( &self, - dirflags: LookupFlags, + dirflags: wasi::LookupFlags, path: &[u8], - oflags: Oflags, - fs_rights_base: Rights, - fs_rights_inheriting: Rights, - fs_flags: FdFlags, + oflags: wasi::OFlags, + fs_rights_base: wasi::Rights, + fs_rights_inheriting: wasi::Rights, + fs_flags: wasi::FdFlags, ) -> io::Result { unsafe { - let mut fd = 0; - cvt_wasi(libc::__wasi_path_open( + wasi::path_open( self.fd, dirflags, - path.as_ptr() as *const c_char, - path.len(), + path, oflags, fs_rights_base, fs_rights_inheriting, fs_flags, - &mut fd, - ))?; - Ok(WasiFd::from_raw(fd)) + ).map(|fd| WasiFd::from_raw(fd)).map_err(err2io) } } - pub fn readdir(&self, buf: &mut [u8], cookie: DirCookie) -> io::Result { - let mut used = 0; - cvt_wasi(unsafe { - libc::__wasi_fd_readdir( - self.fd, - buf.as_mut_ptr() as *mut c_void, - buf.len(), - cookie, - &mut used, - ) - })?; - Ok(used) + pub fn readdir(&self, buf: &mut [u8], cookie: wasi::DirCookie) -> io::Result { + unsafe { wasi::fd_readdir(self.fd, buf, cookie).map_err(err2io) } } pub fn readlink(&self, path: &[u8], buf: &mut [u8]) -> io::Result { - let mut used = 0; - cvt_wasi(unsafe { - libc::__wasi_path_readlink( - self.fd, - path.as_ptr() as *const c_char, - path.len(), - buf.as_mut_ptr() as *mut c_char, - buf.len(), - &mut used, - ) - })?; - Ok(used) + unsafe { wasi::path_readlink(self.fd, path, buf).map_err(err2io) } } pub fn rename(&self, old_path: &[u8], new_fd: &WasiFd, new_path: &[u8]) -> io::Result<()> { - cvt_wasi(unsafe { - libc::__wasi_path_rename( - self.fd, - old_path.as_ptr() as *const c_char, - old_path.len(), - new_fd.fd, - new_path.as_ptr() as *const c_char, - new_path.len(), - ) - }) + unsafe { + wasi::path_rename(self.fd, old_path, new_fd.fd, new_path).map_err(err2io) + } } - pub fn filestat_get(&self, buf: *mut libc::__wasi_filestat_t) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_filestat_get(self.fd, buf) }) + pub fn filestat_get(&self) -> io::Result { + unsafe { wasi::fd_filestat_get(self.fd).map_err(err2io) } } pub fn filestat_set_times( &self, - atim: Timestamp, - mtim: Timestamp, - fstflags: FstFlags, + atim: wasi::Timestamp, + mtim: wasi::Timestamp, + fstflags: wasi::FstFlags, ) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_filestat_set_times(self.fd, atim, mtim, fstflags) }) + unsafe { + wasi::fd_filestat_set_times(self.fd, atim, mtim, fstflags).map_err(err2io) + } } pub fn filestat_set_size(&self, size: u64) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_filestat_set_size(self.fd, size) }) + unsafe { wasi::fd_filestat_set_size(self.fd, size).map_err(err2io) } } pub fn path_filestat_get( &self, - flags: LookupFlags, + flags: wasi::LookupFlags, path: &[u8], - buf: *mut libc::__wasi_filestat_t, - ) -> io::Result<()> { - cvt_wasi(unsafe { - libc::__wasi_path_filestat_get( - self.fd, - flags, - path.as_ptr() as *const c_char, - path.len(), - buf, - ) - }) + ) -> io::Result { + unsafe { wasi::path_filestat_get(self.fd, flags, path).map_err(err2io) } } pub fn path_filestat_set_times( &self, - flags: LookupFlags, + flags: wasi::LookupFlags, path: &[u8], - atim: Timestamp, - mtim: Timestamp, - fstflags: FstFlags, + atim: wasi::Timestamp, + mtim: wasi::Timestamp, + fstflags: wasi::FstFlags, ) -> io::Result<()> { - cvt_wasi(unsafe { - libc::__wasi_path_filestat_set_times( + unsafe { + wasi::path_filestat_set_times( self.fd, flags, - path.as_ptr() as *const c_char, - path.len(), + path, atim, mtim, fstflags, - ) - }) + ).map_err(err2io) + } } pub fn symlink(&self, old_path: &[u8], new_path: &[u8]) -> io::Result<()> { - cvt_wasi(unsafe { - libc::__wasi_path_symlink( - old_path.as_ptr() as *const c_char, - old_path.len(), - self.fd, - new_path.as_ptr() as *const c_char, - new_path.len(), - ) - }) + unsafe { wasi::path_symlink(old_path, self.fd, new_path).map_err(err2io) } } pub fn unlink_file(&self, path: &[u8]) -> io::Result<()> { - cvt_wasi(unsafe { - libc::__wasi_path_unlink_file(self.fd, path.as_ptr() as *const c_char, path.len()) - }) + unsafe { wasi::path_unlink_file(self.fd, path).map_err(err2io) } } pub fn remove_directory(&self, path: &[u8]) -> io::Result<()> { - cvt_wasi(unsafe { - libc::__wasi_path_remove_directory(self.fd, path.as_ptr() as *const c_char, path.len()) - }) + unsafe { wasi::path_remove_directory(self.fd, path).map_err(err2io) } } pub fn sock_recv( &self, ri_data: &mut [IoSliceMut<'_>], - ri_flags: RiFlags, - ) -> io::Result<(usize, RoFlags)> { - let mut ro_datalen = 0; - let mut ro_flags = 0; - let (ptr, len) = iovec(ri_data); - cvt_wasi(unsafe { - libc::__wasi_sock_recv(self.fd, ptr, len, ri_flags, &mut ro_datalen, &mut ro_flags) - })?; - Ok((ro_datalen, ro_flags)) + ri_flags: wasi::RiFlags, + ) -> io::Result<(usize, wasi::RoFlags)> { + unsafe { wasi::sock_recv(self.fd, iovec(ri_data), ri_flags).map_err(err2io) } } - pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: SiFlags) -> io::Result { - let mut so_datalen = 0; - let (ptr, len) = ciovec(si_data); - cvt_wasi(unsafe { libc::__wasi_sock_send(self.fd, ptr, len, si_flags, &mut so_datalen) })?; - Ok(so_datalen) + pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: wasi::SiFlags) -> io::Result { + unsafe { wasi::sock_send(self.fd, ciovec(si_data), si_flags).map_err(err2io) } } pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> { let how = match how { - Shutdown::Read => libc::__WASI_SHUT_RD, - Shutdown::Write => libc::__WASI_SHUT_WR, - Shutdown::Both => libc::__WASI_SHUT_WR | libc::__WASI_SHUT_RD, + Shutdown::Read => wasi::SHUT_RD, + Shutdown::Write => wasi::SHUT_WR, + Shutdown::Both => wasi::SHUT_WR | wasi::SHUT_RD, }; - cvt_wasi(unsafe { libc::__wasi_sock_shutdown(self.fd, how) })?; - Ok(()) + unsafe { wasi::sock_shutdown(self.fd, how).map_err(err2io) } } } impl Drop for WasiFd { fn drop(&mut self) { - unsafe { - // FIXME: can we handle the return code here even though we can't on - // unix? - libc::__wasi_fd_close(self.fd); - } + // FIXME: can we handle the return code here even though we can't on + // unix? + let _ = unsafe { wasi::fd_close(self.fd) }; } } diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs index 172c60385b317..4113f6a2e09c0 100644 --- a/src/libstd/sys/wasi/fs.rs +++ b/src/libstd/sys/wasi/fs.rs @@ -7,7 +7,7 @@ use crate::os::wasi::ffi::{OsStrExt, OsStringExt}; use crate::path::{Path, PathBuf}; use crate::ptr; use crate::sync::Arc; -use crate::sys::fd::{DirCookie, WasiFd}; +use crate::sys::fd::WasiFd; use crate::sys::time::SystemTime; use crate::sys::unsupported; use crate::sys_common::FromInner; @@ -15,18 +15,20 @@ use crate::sys_common::FromInner; pub use crate::sys_common::fs::copy; pub use crate::sys_common::fs::remove_dir_all; +use ::wasi::wasi_unstable as wasi; + pub struct File { fd: WasiFd, } #[derive(Clone)] pub struct FileAttr { - meta: libc::__wasi_filestat_t, + meta: wasi::FileStat, } pub struct ReadDir { inner: Arc, - cookie: Option, + cookie: Option, buf: Vec, offset: usize, cap: usize, @@ -38,7 +40,7 @@ struct ReadDirInner { } pub struct DirEntry { - meta: libc::__wasi_dirent_t, + meta: wasi::Dirent, name: Vec, inner: Arc, } @@ -47,11 +49,11 @@ pub struct DirEntry { pub struct OpenOptions { read: bool, write: bool, - dirflags: libc::__wasi_lookupflags_t, - fdflags: libc::__wasi_fdflags_t, - oflags: libc::__wasi_oflags_t, - rights_base: Option, - rights_inheriting: Option, + dirflags: wasi::LookupFlags, + fdflags: wasi::FdFlags, + oflags: wasi::OFlags, + rights_base: Option, + rights_inheriting: Option, } #[derive(Clone, PartialEq, Eq, Debug)] @@ -61,19 +63,13 @@ pub struct FilePermissions { #[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] pub struct FileType { - bits: libc::__wasi_filetype_t, + bits: wasi::FileType, } #[derive(Debug)] pub struct DirBuilder {} impl FileAttr { - fn zero() -> FileAttr { - FileAttr { - meta: unsafe { mem::zeroed() }, - } - } - pub fn size(&self) -> u64 { self.meta.st_size } @@ -101,7 +97,7 @@ impl FileAttr { Ok(SystemTime::from_wasi_timestamp(self.meta.st_ctim)) } - pub fn as_wasi(&self) -> &libc::__wasi_filestat_t { + pub fn as_wasi(&self) -> &wasi::FileStat { &self.meta } } @@ -118,18 +114,18 @@ impl FilePermissions { impl FileType { pub fn is_dir(&self) -> bool { - self.bits == libc::__WASI_FILETYPE_DIRECTORY + self.bits == wasi::FILETYPE_DIRECTORY } pub fn is_file(&self) -> bool { - self.bits == libc::__WASI_FILETYPE_REGULAR_FILE + self.bits == wasi::FILETYPE_REGULAR_FILE } pub fn is_symlink(&self) -> bool { - self.bits == libc::__WASI_FILETYPE_SYMBOLIC_LINK + self.bits == wasi::FILETYPE_SYMBOLIC_LINK } - pub fn bits(&self) -> libc::__wasi_filetype_t { + pub fn bits(&self) -> wasi::FileType { self.bits } } @@ -173,7 +169,7 @@ impl Iterator for ReadDir { // must have been truncated at the end of the buffer, so reset our // offset so we can go back and reread into the buffer, picking up // where we last left off. - let dirent_size = mem::size_of::(); + let dirent_size = mem::size_of::(); if data.len() < dirent_size { assert!(self.cookie.is_some()); assert!(self.buf.len() >= dirent_size); @@ -182,7 +178,7 @@ impl Iterator for ReadDir { } let (dirent, data) = data.split_at(dirent_size); let dirent = - unsafe { ptr::read_unaligned(dirent.as_ptr() as *const libc::__wasi_dirent_t) }; + unsafe { ptr::read_unaligned(dirent.as_ptr() as *const wasi::Dirent) }; // If the file name was truncated, then we need to reinvoke // `readdir` so we truncate our buffer to start over and reread this @@ -241,7 +237,7 @@ impl DirEntry { }) } - pub fn ino(&self) -> libc::__wasi_inode_t { + pub fn ino(&self) -> wasi::Inode { self.meta.d_ino } } @@ -249,7 +245,7 @@ impl DirEntry { impl OpenOptions { pub fn new() -> OpenOptions { let mut base = OpenOptions::default(); - base.dirflags = libc::__WASI_LOOKUP_SYMLINK_FOLLOW; + base.dirflags = wasi::LOOKUP_SYMLINK_FOLLOW; return base; } @@ -262,23 +258,23 @@ impl OpenOptions { } pub fn truncate(&mut self, truncate: bool) { - self.oflag(libc::__WASI_O_TRUNC, truncate); + self.oflag(wasi::O_TRUNC, truncate); } pub fn create(&mut self, create: bool) { - self.oflag(libc::__WASI_O_CREAT, create); + self.oflag(wasi::O_CREAT, create); } pub fn create_new(&mut self, create_new: bool) { - self.oflag(libc::__WASI_O_EXCL, create_new); - self.oflag(libc::__WASI_O_CREAT, create_new); + self.oflag(wasi::O_EXCL, create_new); + self.oflag(wasi::O_CREAT, create_new); } pub fn directory(&mut self, directory: bool) { - self.oflag(libc::__WASI_O_DIRECTORY, directory); + self.oflag(wasi::O_DIRECTORY, directory); } - fn oflag(&mut self, bit: libc::__wasi_oflags_t, set: bool) { + fn oflag(&mut self, bit: wasi::OFlags, set: bool) { if set { self.oflags |= bit; } else { @@ -287,26 +283,26 @@ impl OpenOptions { } pub fn append(&mut self, set: bool) { - self.fdflag(libc::__WASI_FDFLAG_APPEND, set); + self.fdflag(wasi::FDFLAG_APPEND, set); } pub fn dsync(&mut self, set: bool) { - self.fdflag(libc::__WASI_FDFLAG_DSYNC, set); + self.fdflag(wasi::FDFLAG_DSYNC, set); } pub fn nonblock(&mut self, set: bool) { - self.fdflag(libc::__WASI_FDFLAG_NONBLOCK, set); + self.fdflag(wasi::FDFLAG_NONBLOCK, set); } pub fn rsync(&mut self, set: bool) { - self.fdflag(libc::__WASI_FDFLAG_RSYNC, set); + self.fdflag(wasi::FDFLAG_RSYNC, set); } pub fn sync(&mut self, set: bool) { - self.fdflag(libc::__WASI_FDFLAG_SYNC, set); + self.fdflag(wasi::FDFLAG_SYNC, set); } - fn fdflag(&mut self, bit: libc::__wasi_fdflags_t, set: bool) { + fn fdflag(&mut self, bit: wasi::FdFlags, set: bool) { if set { self.fdflags |= bit; } else { @@ -314,15 +310,15 @@ impl OpenOptions { } } - pub fn fs_rights_base(&mut self, rights: libc::__wasi_rights_t) { + pub fn fs_rights_base(&mut self, rights: wasi::Rights) { self.rights_base = Some(rights); } - pub fn fs_rights_inheriting(&mut self, rights: libc::__wasi_rights_t) { + pub fn fs_rights_inheriting(&mut self, rights: wasi::Rights) { self.rights_inheriting = Some(rights); } - fn rights_base(&self) -> libc::__wasi_rights_t { + fn rights_base(&self) -> wasi::Rights { if let Some(rights) = self.rights_base { return rights; } @@ -334,52 +330,52 @@ impl OpenOptions { // based on that. let mut base = 0; if self.read { - base |= libc::__WASI_RIGHT_FD_READ; - base |= libc::__WASI_RIGHT_FD_READDIR; + base |= wasi::RIGHT_FD_READ; + base |= wasi::RIGHT_FD_READDIR; } if self.write { - base |= libc::__WASI_RIGHT_FD_WRITE; - base |= libc::__WASI_RIGHT_FD_DATASYNC; - base |= libc::__WASI_RIGHT_FD_ALLOCATE; - base |= libc::__WASI_RIGHT_FD_FILESTAT_SET_SIZE; + base |= wasi::RIGHT_FD_WRITE; + base |= wasi::RIGHT_FD_DATASYNC; + base |= wasi::RIGHT_FD_ALLOCATE; + base |= wasi::RIGHT_FD_FILESTAT_SET_SIZE; } // FIXME: some of these should probably be read-only or write-only... - base |= libc::__WASI_RIGHT_FD_ADVISE; - base |= libc::__WASI_RIGHT_FD_FDSTAT_SET_FLAGS; - base |= libc::__WASI_RIGHT_FD_FILESTAT_SET_TIMES; - base |= libc::__WASI_RIGHT_FD_SEEK; - base |= libc::__WASI_RIGHT_FD_SYNC; - base |= libc::__WASI_RIGHT_FD_TELL; - base |= libc::__WASI_RIGHT_PATH_CREATE_DIRECTORY; - base |= libc::__WASI_RIGHT_PATH_CREATE_FILE; - base |= libc::__WASI_RIGHT_PATH_FILESTAT_GET; - base |= libc::__WASI_RIGHT_PATH_LINK_SOURCE; - base |= libc::__WASI_RIGHT_PATH_LINK_TARGET; - base |= libc::__WASI_RIGHT_PATH_OPEN; - base |= libc::__WASI_RIGHT_PATH_READLINK; - base |= libc::__WASI_RIGHT_PATH_REMOVE_DIRECTORY; - base |= libc::__WASI_RIGHT_PATH_RENAME_SOURCE; - base |= libc::__WASI_RIGHT_PATH_RENAME_TARGET; - base |= libc::__WASI_RIGHT_PATH_SYMLINK; - base |= libc::__WASI_RIGHT_PATH_UNLINK_FILE; - base |= libc::__WASI_RIGHT_POLL_FD_READWRITE; + base |= wasi::RIGHT_FD_ADVISE; + base |= wasi::RIGHT_FD_FDSTAT_SET_FLAGS; + base |= wasi::RIGHT_FD_FILESTAT_SET_TIMES; + base |= wasi::RIGHT_FD_SEEK; + base |= wasi::RIGHT_FD_SYNC; + base |= wasi::RIGHT_FD_TELL; + base |= wasi::RIGHT_PATH_CREATE_DIRECTORY; + base |= wasi::RIGHT_PATH_CREATE_FILE; + base |= wasi::RIGHT_PATH_FILESTAT_GET; + base |= wasi::RIGHT_PATH_LINK_SOURCE; + base |= wasi::RIGHT_PATH_LINK_TARGET; + base |= wasi::RIGHT_PATH_OPEN; + base |= wasi::RIGHT_PATH_READLINK; + base |= wasi::RIGHT_PATH_REMOVE_DIRECTORY; + base |= wasi::RIGHT_PATH_RENAME_SOURCE; + base |= wasi::RIGHT_PATH_RENAME_TARGET; + base |= wasi::RIGHT_PATH_SYMLINK; + base |= wasi::RIGHT_PATH_UNLINK_FILE; + base |= wasi::RIGHT_POLL_FD_READWRITE; return base; } - fn rights_inheriting(&self) -> libc::__wasi_rights_t { + fn rights_inheriting(&self) -> wasi::Rights { self.rights_inheriting.unwrap_or_else(|| self.rights_base()) } - pub fn lookup_flags(&mut self, flags: libc::__wasi_lookupflags_t) { + pub fn lookup_flags(&mut self, flags: wasi::LookupFlags) { self.dirflags = flags; } } impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { - let (dir, file) = open_parent(path, libc::__WASI_RIGHT_PATH_OPEN)?; + let (dir, file) = open_parent(path, wasi::RIGHT_PATH_OPEN)?; open_at(&dir, &file, opts) } @@ -388,14 +384,12 @@ impl File { } pub fn file_attr(&self) -> io::Result { - let mut ret = FileAttr::zero(); - self.fd.filestat_get(&mut ret.meta)?; - Ok(ret) + self.fd.filestat_get().map(|meta| FileAttr { meta }) } pub fn metadata_at( &self, - flags: libc::__wasi_lookupflags_t, + flags: wasi::LookupFlags, path: &Path, ) -> io::Result { metadata_at(&self.fd, flags, path) @@ -477,7 +471,7 @@ impl DirBuilder { } pub fn mkdir(&self, p: &Path) -> io::Result<()> { - let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_CREATE_DIRECTORY)?; + let (dir, file) = open_parent(p, wasi::RIGHT_PATH_CREATE_DIRECTORY)?; dir.create_directory(file.as_os_str().as_bytes()) } } @@ -508,13 +502,13 @@ pub fn readdir(p: &Path) -> io::Result { } pub fn unlink(p: &Path) -> io::Result<()> { - let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_UNLINK_FILE)?; + let (dir, file) = open_parent(p, wasi::RIGHT_PATH_UNLINK_FILE)?; dir.unlink_file(file.as_os_str().as_bytes()) } pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let (old, old_file) = open_parent(old, libc::__WASI_RIGHT_PATH_RENAME_SOURCE)?; - let (new, new_file) = open_parent(new, libc::__WASI_RIGHT_PATH_RENAME_TARGET)?; + let (old, old_file) = open_parent(old, wasi::RIGHT_PATH_RENAME_SOURCE)?; + let (new, new_file) = open_parent(new, wasi::RIGHT_PATH_RENAME_TARGET)?; old.rename( old_file.as_os_str().as_bytes(), &new, @@ -529,12 +523,12 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { } pub fn rmdir(p: &Path) -> io::Result<()> { - let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_REMOVE_DIRECTORY)?; + let (dir, file) = open_parent(p, wasi::RIGHT_PATH_REMOVE_DIRECTORY)?; dir.remove_directory(file.as_os_str().as_bytes()) } pub fn readlink(p: &Path) -> io::Result { - let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_READLINK)?; + let (dir, file) = open_parent(p, wasi::RIGHT_PATH_READLINK)?; read_link(&dir, &file) } @@ -570,15 +564,15 @@ fn read_link(fd: &WasiFd, file: &Path) -> io::Result { } pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { - let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_SYMLINK)?; + let (dst, dst_file) = open_parent(dst, wasi::RIGHT_PATH_SYMLINK)?; dst.symlink(src.as_os_str().as_bytes(), dst_file.as_os_str().as_bytes()) } pub fn link(src: &Path, dst: &Path) -> io::Result<()> { - let (src, src_file) = open_parent(src, libc::__WASI_RIGHT_PATH_LINK_SOURCE)?; - let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_LINK_TARGET)?; + let (src, src_file) = open_parent(src, wasi::RIGHT_PATH_LINK_SOURCE)?; + let (dst, dst_file) = open_parent(dst, wasi::RIGHT_PATH_LINK_TARGET)?; src.link( - libc::__WASI_LOOKUP_SYMLINK_FOLLOW, + wasi::LOOKUP_SYMLINK_FOLLOW, src_file.as_os_str().as_bytes(), &dst, dst_file.as_os_str().as_bytes(), @@ -586,23 +580,22 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> { } pub fn stat(p: &Path) -> io::Result { - let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?; - metadata_at(&dir, libc::__WASI_LOOKUP_SYMLINK_FOLLOW, &file) + let (dir, file) = open_parent(p, wasi::RIGHT_PATH_FILESTAT_GET)?; + metadata_at(&dir, wasi::LOOKUP_SYMLINK_FOLLOW, &file) } pub fn lstat(p: &Path) -> io::Result { - let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?; + let (dir, file) = open_parent(p, wasi::RIGHT_PATH_FILESTAT_GET)?; metadata_at(&dir, 0, &file) } fn metadata_at( fd: &WasiFd, - flags: libc::__wasi_lookupflags_t, + flags: wasi::LookupFlags, path: &Path, ) -> io::Result { - let mut ret = FileAttr::zero(); - fd.path_filestat_get(flags, path.as_os_str().as_bytes(), &mut ret.meta)?; - Ok(ret) + fd.path_filestat_get(flags, path.as_os_str().as_bytes()) + .map(|meta| FileAttr { meta }) } pub fn canonicalize(_p: &Path) -> io::Result { @@ -652,12 +645,12 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result { /// to any preopened file descriptor. fn open_parent( p: &Path, - rights: libc::__wasi_rights_t, + rights: wasi::Rights, ) -> io::Result<(ManuallyDrop, PathBuf)> { let p = CString::new(p.as_os_str().as_bytes())?; unsafe { let mut ret = ptr::null(); - let fd = __wasilibc_find_relpath(p.as_ptr(), rights, 0, &mut ret); + let fd = libc::__wasilibc_find_relpath(p.as_ptr(), rights, 0, &mut ret); if fd == -1 { let msg = format!( "failed to find a preopened file descriptor \ @@ -677,15 +670,4 @@ fn open_parent( return Ok((ManuallyDrop::new(WasiFd::from_raw(fd as u32)), path)); } - - // FIXME(rust-lang/libc#1314) use the `libc` crate for this when the API - // there is published - extern "C" { - pub fn __wasilibc_find_relpath( - path: *const libc::c_char, - rights_base: libc::__wasi_rights_t, - rights_inheriting: libc::__wasi_rights_t, - relative_path: *mut *const libc::c_char, - ) -> libc::c_int; - } } diff --git a/src/libstd/sys/wasi/io.rs b/src/libstd/sys/wasi/io.rs index ffecca5d1b6ff..4be92faed308f 100644 --- a/src/libstd/sys/wasi/io.rs +++ b/src/libstd/sys/wasi/io.rs @@ -1,11 +1,12 @@ use crate::marker::PhantomData; use crate::slice; -use libc::{__wasi_ciovec_t, __wasi_iovec_t, c_void}; +use ::wasi::wasi_unstable as wasi; +use core::ffi::c_void; #[repr(transparent)] pub struct IoSlice<'a> { - vec: __wasi_ciovec_t, + vec: wasi::CIoVec, _p: PhantomData<&'a [u8]>, } @@ -13,7 +14,7 @@ impl<'a> IoSlice<'a> { #[inline] pub fn new(buf: &'a [u8]) -> IoSlice<'a> { IoSlice { - vec: __wasi_ciovec_t { + vec: wasi::CIoVec { buf: buf.as_ptr() as *const c_void, buf_len: buf.len(), }, @@ -43,7 +44,7 @@ impl<'a> IoSlice<'a> { #[repr(transparent)] pub struct IoSliceMut<'a> { - vec: __wasi_iovec_t, + vec: wasi::IoVec, _p: PhantomData<&'a mut [u8]>, } @@ -51,7 +52,7 @@ impl<'a> IoSliceMut<'a> { #[inline] pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { IoSliceMut { - vec: __wasi_iovec_t { + vec: wasi::IoVec { buf: buf.as_mut_ptr() as *mut c_void, buf_len: buf.len() }, diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs index f842869e08ee6..517e3be9cb58c 100644 --- a/src/libstd/sys/wasi/mod.rs +++ b/src/libstd/sys/wasi/mod.rs @@ -14,10 +14,10 @@ //! compiling for wasm. That way it's a compile time error for something that's //! guaranteed to be a runtime error! -use libc; -use crate::io::{Error, ErrorKind}; +use crate::io as std_io; use crate::mem; use crate::os::raw::c_char; +use ::wasi::wasi_unstable as wasi; pub mod alloc; pub mod args; @@ -56,16 +56,43 @@ pub mod ext; pub fn init() { } -pub fn unsupported() -> crate::io::Result { +pub fn unsupported() -> std_io::Result { Err(unsupported_err()) } -pub fn unsupported_err() -> Error { - Error::new(ErrorKind::Other, "operation not supported on wasm yet") +pub fn unsupported_err() -> std_io::Error { + std_io::Error::new( + std_io::ErrorKind::Other, + "operation not supported on wasm yet", + ) } -pub fn decode_error_kind(_code: i32) -> ErrorKind { - ErrorKind::Other +pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind { + use std_io::ErrorKind::*; + if errno > u16::max_value() as i32 || errno < 0 { + return Other; + } + let code = match wasi::Error::new(errno as u16) { + Some(code) => code, + None => return Other, + }; + match code { + wasi::ECONNREFUSED => ConnectionRefused, + wasi::ECONNRESET => ConnectionReset, + wasi::EPERM | wasi::EACCES => PermissionDenied, + wasi::EPIPE => BrokenPipe, + wasi::ENOTCONN => NotConnected, + wasi::ECONNABORTED => ConnectionAborted, + wasi::EADDRNOTAVAIL => AddrNotAvailable, + wasi::EADDRINUSE => AddrInUse, + wasi::ENOENT => NotFound, + wasi::EINTR => Interrupted, + wasi::EINVAL => InvalidInput, + wasi::ETIMEDOUT => TimedOut, + wasi::EEXIST => AlreadyExists, + wasi::EAGAIN => WouldBlock, + _ => Other, + } } // This enum is used as the storage for a bunch of types which can't actually @@ -89,40 +116,16 @@ pub unsafe fn abort_internal() -> ! { pub fn hashmap_random_keys() -> (u64, u64) { let mut ret = (0u64, 0u64); unsafe { - let base = &mut ret as *mut (u64, u64) as *mut libc::c_void; + let base = &mut ret as *mut (u64, u64) as *mut core::ffi::c_void; let len = mem::size_of_val(&ret); - cvt_wasi(libc::__wasi_random_get(base, len)).unwrap(); - } - return ret -} - -#[doc(hidden)] -pub trait IsMinusOne { - fn is_minus_one(&self) -> bool; -} - -macro_rules! impl_is_minus_one { - ($($t:ident)*) => ($(impl IsMinusOne for $t { - fn is_minus_one(&self) -> bool { - *self == -1 + let ret = wasi::raw::__wasi_random_get(base, len); + if ret != 0 { + panic!("__wasi_random_get failure") } - })*) -} - -impl_is_minus_one! { i8 i16 i32 i64 isize } - -pub fn cvt(t: T) -> crate::io::Result { - if t.is_minus_one() { - Err(Error::last_os_error()) - } else { - Ok(t) } + return ret } -pub fn cvt_wasi(r: u16) -> crate::io::Result<()> { - if r != libc::__WASI_ESUCCESS { - Err(Error::from_raw_os_error(r as i32)) - } else { - Ok(()) - } +fn err2io(err: wasi::Error) -> std_io::Error { + std_io::Error::from_raw_os_error(err.get() as i32) } diff --git a/src/libstd/sys/wasi/os.rs b/src/libstd/sys/wasi/os.rs index 822ea02a11b89..feee840782550 100644 --- a/src/libstd/sys/wasi/os.rs +++ b/src/libstd/sys/wasi/os.rs @@ -9,7 +9,7 @@ use crate::path::{self, PathBuf}; use crate::ptr; use crate::str; use crate::sys::memchr; -use crate::sys::{cvt, unsupported, Void}; +use crate::sys::{unsupported, Void}; use crate::vec; #[cfg(not(target_feature = "atomics"))] @@ -28,16 +28,11 @@ pub fn errno() -> i32 { } pub fn error_string(errno: i32) -> String { - extern { - fn strerror_r(errnum: libc::c_int, buf: *mut libc::c_char, - buflen: libc::size_t) -> libc::c_int; - } - let mut buf = [0 as libc::c_char; 1024]; let p = buf.as_mut_ptr(); unsafe { - if strerror_r(errno as libc::c_int, p, buf.len()) < 0 { + if libc::strerror_r(errno as libc::c_int, p, buf.len()) < 0 { panic!("strerror_r failure"); } str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned() @@ -89,7 +84,6 @@ impl StdError for JoinPathsError { pub fn current_exe() -> io::Result { unsupported() } - pub struct Env { iter: vec::IntoIter<(OsString, OsString)>, _dont_send_or_sync_me: PhantomData<*mut ()>, @@ -182,3 +176,26 @@ pub fn exit(code: i32) -> ! { pub fn getpid() -> u32 { panic!("unsupported"); } + +#[doc(hidden)] +pub trait IsMinusOne { + fn is_minus_one(&self) -> bool; +} + +macro_rules! impl_is_minus_one { + ($($t:ident)*) => ($(impl IsMinusOne for $t { + fn is_minus_one(&self) -> bool { + *self == -1 + } + })*) +} + +impl_is_minus_one! { i8 i16 i32 i64 isize } + +fn cvt(t: T) -> io::Result { + if t.is_minus_one() { + Err(io::Error::last_os_error()) + } else { + Ok(t) + } +} diff --git a/src/libstd/sys/wasi/process.rs b/src/libstd/sys/wasi/process.rs index 788b829f4bac9..1c4d028b7618b 100644 --- a/src/libstd/sys/wasi/process.rs +++ b/src/libstd/sys/wasi/process.rs @@ -4,14 +4,16 @@ use crate::io; use crate::sys::fs::File; use crate::sys::pipe::AnonPipe; use crate::sys::{unsupported, Void}; -use crate::sys_common::process::{CommandEnv, DefaultEnvKey}; +use crate::sys_common::process::CommandEnv; + +pub use crate::ffi::OsString as EnvKey; //////////////////////////////////////////////////////////////////////////////// // Command //////////////////////////////////////////////////////////////////////////////// pub struct Command { - env: CommandEnv + env: CommandEnv } // passed back to std::process with the pipes connected to the child, if any @@ -38,7 +40,7 @@ impl Command { pub fn arg(&mut self, _arg: &OsStr) { } - pub fn env_mut(&mut self) -> &mut CommandEnv { + pub fn env_mut(&mut self) -> &mut CommandEnv { &mut self.env } diff --git a/src/libstd/sys/wasi/stdio.rs b/src/libstd/sys/wasi/stdio.rs index 2bf8d803c01bb..1d57b9922e599 100644 --- a/src/libstd/sys/wasi/stdio.rs +++ b/src/libstd/sys/wasi/stdio.rs @@ -1,8 +1,9 @@ use crate::io::{self, IoSlice, IoSliceMut}; -use crate::libc; use crate::mem::ManuallyDrop; use crate::sys::fd::WasiFd; +use ::wasi::wasi_unstable as wasi; + pub struct Stdin; pub struct Stdout; pub struct Stderr; @@ -17,7 +18,7 @@ impl Stdin { } pub fn read_vectored(&self, data: &mut [IoSliceMut<'_>]) -> io::Result { - ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDIN_FILENO as u32) }) + ManuallyDrop::new(unsafe { WasiFd::from_raw(wasi::STDIN_FD) }) .read(data) } } @@ -32,7 +33,7 @@ impl Stdout { } pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result { - ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDOUT_FILENO as u32) }) + ManuallyDrop::new(unsafe { WasiFd::from_raw(wasi::STDOUT_FD) }) .write(data) } @@ -51,7 +52,7 @@ impl Stderr { } pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result { - ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDERR_FILENO as u32) }) + ManuallyDrop::new(unsafe { WasiFd::from_raw(wasi::STDERR_FD) }) .write(data) } @@ -73,7 +74,7 @@ impl io::Write for Stderr { pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(libc::__WASI_EBADF as i32) + err.raw_os_error() == Some(wasi::EBADF.get() as i32) } pub fn panic_output() -> Option { diff --git a/src/libstd/sys/wasi/thread.rs b/src/libstd/sys/wasi/thread.rs index 5e69e4d948fee..28a504f197974 100644 --- a/src/libstd/sys/wasi/thread.rs +++ b/src/libstd/sys/wasi/thread.rs @@ -1,10 +1,10 @@ -use crate::cmp; use crate::ffi::CStr; use crate::io; -use crate::sys::cvt; +use crate::mem; use crate::sys::{unsupported, Void}; use crate::time::Duration; -use libc; + +use ::wasi::wasi_unstable as wasi; pub struct Thread(Void); @@ -19,8 +19,8 @@ impl Thread { } pub fn yield_now() { - let ret = unsafe { libc::__wasi_sched_yield() }; - debug_assert_eq!(ret, 0); + let ret = wasi::sched_yield(); + debug_assert_eq!(ret, Ok(())); } pub fn set_name(_name: &CStr) { @@ -28,19 +28,37 @@ impl Thread { } pub fn sleep(dur: Duration) { - let mut secs = dur.as_secs(); - let mut nsecs = dur.subsec_nanos() as i32; - - unsafe { - while secs > 0 || nsecs > 0 { - let mut ts = libc::timespec { - tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t, - tv_nsec: nsecs, - }; - secs -= ts.tv_sec as u64; - cvt(libc::nanosleep(&ts, &mut ts)).unwrap(); - nsecs = 0; - } + let nanos = dur.as_nanos(); + assert!(nanos <= u64::max_value() as u128); + + const CLOCK_ID: wasi::Userdata = 0x0123_45678; + + let clock = wasi::raw::__wasi_subscription_u_clock_t { + identifier: CLOCK_ID, + clock_id: wasi::CLOCK_MONOTONIC, + timeout: nanos as u64, + precision: 0, + flags: 0, + }; + + let in_ = [wasi::Subscription { + userdata: 0, + type_: wasi::EVENTTYPE_CLOCK, + u: wasi::raw::__wasi_subscription_u { clock: clock }, + }]; + let (res, event) = unsafe { + let mut out: [wasi::Event; 1] = mem::zeroed(); + let res = wasi::poll_oneoff(&in_, &mut out); + (res, out[0]) + }; + match (res, event) { + (Ok(1), wasi::Event { + userdata: CLOCK_ID, + error: 0, + type_: wasi::EVENTTYPE_CLOCK, + .. + }) => {} + _ => panic!("thread::sleep(): unexpected result of poll_oneoff"), } } diff --git a/src/libstd/sys/wasi/time.rs b/src/libstd/sys/wasi/time.rs index 3f14c80928c67..4394a22f9c233 100644 --- a/src/libstd/sys/wasi/time.rs +++ b/src/libstd/sys/wasi/time.rs @@ -1,7 +1,5 @@ use crate::time::Duration; -use crate::mem; -use crate::sys::cvt_wasi; -use libc; +use ::wasi::wasi_unstable as wasi; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct Instant(Duration); @@ -12,23 +10,19 @@ pub struct SystemTime(Duration); pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); fn current_time(clock: u32) -> Duration { - unsafe { - let mut ts = mem::zeroed(); - cvt_wasi(libc::__wasi_clock_time_get( - clock, - 1, // precision... seems ignored though? - &mut ts, - )).unwrap(); - Duration::new( - (ts / 1_000_000_000) as u64, - (ts % 1_000_000_000) as u32, - ) - } + let ts = wasi::clock_time_get( + clock, + 1, // precision... seems ignored though? + ).unwrap(); + Duration::new( + (ts / 1_000_000_000) as u64, + (ts % 1_000_000_000) as u32, + ) } impl Instant { pub fn now() -> Instant { - Instant(current_time(libc::__WASI_CLOCK_MONOTONIC)) + Instant(current_time(wasi::CLOCK_MONOTONIC)) } pub const fn zero() -> Instant { @@ -54,10 +48,10 @@ impl Instant { impl SystemTime { pub fn now() -> SystemTime { - SystemTime(current_time(libc::__WASI_CLOCK_REALTIME)) + SystemTime(current_time(wasi::CLOCK_REALTIME)) } - pub fn from_wasi_timestamp(ts: libc::__wasi_timestamp_t) -> SystemTime { + pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime { SystemTime(Duration::from_nanos(ts)) } diff --git a/src/libstd/sys/wasm/args.rs b/src/libstd/sys/wasm/args.rs index b3c77b8699563..8279e5280e924 100644 --- a/src/libstd/sys/wasm/args.rs +++ b/src/libstd/sys/wasm/args.rs @@ -1,7 +1,6 @@ use crate::ffi::OsString; use crate::marker::PhantomData; use crate::vec; -use crate::sys::ArgsSysCall; pub unsafe fn init(_argc: isize, _argv: *const *const u8) { // On wasm these should always be null, so there's nothing for us to do here @@ -11,9 +10,8 @@ pub unsafe fn cleanup() { } pub fn args() -> Args { - let v = ArgsSysCall::perform(); Args { - iter: v.into_iter(), + iter: Vec::new().into_iter(), _dont_send_or_sync_me: PhantomData, } } diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs index 56cbafcfdb8a2..de0bb38dc319e 100644 --- a/src/libstd/sys/wasm/mod.rs +++ b/src/libstd/sys/wasm/mod.rs @@ -15,11 +15,6 @@ //! guaranteed to be a runtime error! use crate::os::raw::c_char; -use crate::ptr; -use crate::sys::os_str::Buf; -use crate::sys_common::{AsInner, FromInner}; -use crate::ffi::{OsString, OsStr}; -use crate::time::Duration; pub mod alloc; pub mod args; @@ -89,7 +84,7 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize { } pub unsafe fn abort_internal() -> ! { - ExitSysCall::perform(1) + crate::arch::wasm32::unreachable() } // We don't have randomness yet, but I totally used a random number generator to @@ -100,218 +95,3 @@ pub unsafe fn abort_internal() -> ! { pub fn hashmap_random_keys() -> (u64, u64) { (1, 2) } - -// Implement a minimal set of system calls to enable basic IO -pub enum SysCallIndex { - Read = 0, - Write = 1, - Exit = 2, - Args = 3, - GetEnv = 4, - SetEnv = 5, - Time = 6, -} - -#[repr(C)] -pub struct ReadSysCall { - fd: usize, - ptr: *mut u8, - len: usize, - result: usize, -} - -impl ReadSysCall { - pub fn perform(fd: usize, buffer: &mut [u8]) -> usize { - let mut call_record = ReadSysCall { - fd, - len: buffer.len(), - ptr: buffer.as_mut_ptr(), - result: 0 - }; - if unsafe { syscall(SysCallIndex::Read, &mut call_record) } { - call_record.result - } else { - 0 - } - } -} - -#[repr(C)] -pub struct WriteSysCall { - fd: usize, - ptr: *const u8, - len: usize, -} - -impl WriteSysCall { - pub fn perform(fd: usize, buffer: &[u8]) { - let mut call_record = WriteSysCall { - fd, - len: buffer.len(), - ptr: buffer.as_ptr() - }; - unsafe { syscall(SysCallIndex::Write, &mut call_record); } - } -} - -#[repr(C)] -pub struct ExitSysCall { - code: usize, -} - -impl ExitSysCall { - pub fn perform(code: usize) -> ! { - let mut call_record = ExitSysCall { - code - }; - unsafe { - syscall(SysCallIndex::Exit, &mut call_record); - crate::intrinsics::abort(); - } - } -} - -fn receive_buffer Result>(estimate: usize, mut f: F) - -> Result, E> -{ - let mut buffer = vec![0; estimate]; - loop { - let result = f(&mut buffer)?; - if result <= buffer.len() { - buffer.truncate(result); - break; - } - buffer.resize(result, 0); - } - Ok(buffer) -} - -#[repr(C)] -pub struct ArgsSysCall { - ptr: *mut u8, - len: usize, - result: usize -} - -impl ArgsSysCall { - pub fn perform() -> Vec { - receive_buffer(1024, |buffer| -> Result { - let mut call_record = ArgsSysCall { - len: buffer.len(), - ptr: buffer.as_mut_ptr(), - result: 0 - }; - if unsafe { syscall(SysCallIndex::Args, &mut call_record) } { - Ok(call_record.result) - } else { - Ok(0) - } - }) - .unwrap() - .split(|b| *b == 0) - .map(|s| FromInner::from_inner(Buf { inner: s.to_owned() })) - .collect() - } -} - -#[repr(C)] -pub struct GetEnvSysCall { - key_ptr: *const u8, - key_len: usize, - value_ptr: *mut u8, - value_len: usize, - result: usize -} - -impl GetEnvSysCall { - pub fn perform(key: &OsStr) -> Option { - let key_buf = &AsInner::as_inner(key).inner; - receive_buffer(64, |buffer| { - let mut call_record = GetEnvSysCall { - key_len: key_buf.len(), - key_ptr: key_buf.as_ptr(), - value_len: buffer.len(), - value_ptr: buffer.as_mut_ptr(), - result: !0usize - }; - if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) } { - if call_record.result == !0usize { - Err(()) - } else { - Ok(call_record.result) - } - } else { - Err(()) - } - }).ok().map(|s| { - FromInner::from_inner(Buf { inner: s }) - }) - } -} - -#[repr(C)] -pub struct SetEnvSysCall { - key_ptr: *const u8, - key_len: usize, - value_ptr: *const u8, - value_len: usize -} - -impl SetEnvSysCall { - pub fn perform(key: &OsStr, value: Option<&OsStr>) { - let key_buf = &AsInner::as_inner(key).inner; - let value_buf = value.map(|v| &AsInner::as_inner(v).inner); - let mut call_record = SetEnvSysCall { - key_len: key_buf.len(), - key_ptr: key_buf.as_ptr(), - value_len: value_buf.map(|v| v.len()).unwrap_or(!0usize), - value_ptr: value_buf.map(|v| v.as_ptr()).unwrap_or(ptr::null()) - }; - unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); } - } -} - -pub enum TimeClock { - Monotonic = 0, - System = 1, -} - -#[repr(C)] -pub struct TimeSysCall { - clock: usize, - secs_hi: usize, - secs_lo: usize, - nanos: usize -} - -impl TimeSysCall { - pub fn perform(clock: TimeClock) -> Duration { - let mut call_record = TimeSysCall { - clock: clock as usize, - secs_hi: 0, - secs_lo: 0, - nanos: 0 - }; - if unsafe { syscall(SysCallIndex::Time, &mut call_record) } { - Duration::new( - ((call_record.secs_hi as u64) << 32) | (call_record.secs_lo as u64), - call_record.nanos as u32 - ) - } else { - panic!("Time system call is not implemented by WebAssembly host"); - } - } -} - -unsafe fn syscall(index: SysCallIndex, data: &mut T) -> bool { - #[cfg(feature = "wasm_syscall")] - extern { - #[no_mangle] - fn rust_wasm_syscall(index: usize, data: *mut Void) -> usize; - } - - #[cfg(not(feature = "wasm_syscall"))] - unsafe fn rust_wasm_syscall(_index: usize, _data: *mut Void) -> usize { 0 } - - rust_wasm_syscall(index as usize, data as *mut T as *mut Void) != 0 -} diff --git a/src/libstd/sys/wasm/os.rs b/src/libstd/sys/wasm/os.rs index 5d21999a991e1..890049e8bfae5 100644 --- a/src/libstd/sys/wasm/os.rs +++ b/src/libstd/sys/wasm/os.rs @@ -4,7 +4,7 @@ use crate::fmt; use crate::io; use crate::path::{self, PathBuf}; use crate::str; -use crate::sys::{unsupported, Void, ExitSysCall, GetEnvSysCall, SetEnvSysCall}; +use crate::sys::{unsupported, Void}; pub fn errno() -> i32 { 0 @@ -73,16 +73,16 @@ pub fn env() -> Env { panic!("not supported on web assembly") } -pub fn getenv(k: &OsStr) -> io::Result> { - Ok(GetEnvSysCall::perform(k)) +pub fn getenv(_: &OsStr) -> io::Result> { + Ok(None) } -pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - Ok(SetEnvSysCall::perform(k, Some(v))) +pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Other, "cannot set env vars on wasm32-unknown-unknown")) } -pub fn unsetenv(k: &OsStr) -> io::Result<()> { - Ok(SetEnvSysCall::perform(k, None)) +pub fn unsetenv(_: &OsStr) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Other, "cannot unset env vars on wasm32-unknown-unknown")) } pub fn temp_dir() -> PathBuf { @@ -94,7 +94,9 @@ pub fn home_dir() -> Option { } pub fn exit(_code: i32) -> ! { - ExitSysCall::perform(_code as isize as usize) + unsafe { + crate::arch::wasm32::unreachable(); + } } pub fn getpid() -> u32 { diff --git a/src/libstd/sys/wasm/process.rs b/src/libstd/sys/wasm/process.rs index a02e009d95356..edf933d10e074 100644 --- a/src/libstd/sys/wasm/process.rs +++ b/src/libstd/sys/wasm/process.rs @@ -4,14 +4,16 @@ use crate::io; use crate::sys::fs::File; use crate::sys::pipe::AnonPipe; use crate::sys::{unsupported, Void}; -use crate::sys_common::process::{CommandEnv, DefaultEnvKey}; +use crate::sys_common::process::CommandEnv; + +pub use crate::ffi::OsString as EnvKey; //////////////////////////////////////////////////////////////////////////////// // Command //////////////////////////////////////////////////////////////////////////////// pub struct Command { - env: CommandEnv + env: CommandEnv, } // passed back to std::process with the pipes connected to the child, if any @@ -38,7 +40,7 @@ impl Command { pub fn arg(&mut self, _arg: &OsStr) { } - pub fn env_mut(&mut self) -> &mut CommandEnv { + pub fn env_mut(&mut self) -> &mut CommandEnv { &mut self.env } diff --git a/src/libstd/sys/wasm/stdio.rs b/src/libstd/sys/wasm/stdio.rs index b8899a9c84746..5a4e4505e93bd 100644 --- a/src/libstd/sys/wasm/stdio.rs +++ b/src/libstd/sys/wasm/stdio.rs @@ -1,5 +1,4 @@ use crate::io; -use crate::sys::{ReadSysCall, WriteSysCall}; pub struct Stdin; pub struct Stdout; @@ -12,8 +11,8 @@ impl Stdin { } impl io::Read for Stdin { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - Ok(ReadSysCall::perform(0, buf)) + fn read(&mut self, _buf: &mut [u8]) -> io::Result { + Ok(0) } } @@ -25,7 +24,6 @@ impl Stdout { impl io::Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { - WriteSysCall::perform(1, buf); Ok(buf.len()) } @@ -42,7 +40,6 @@ impl Stderr { impl io::Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { - WriteSysCall::perform(2, buf); Ok(buf.len()) } @@ -57,10 +54,6 @@ pub fn is_ebadf(_err: &io::Error) -> bool { true } -pub fn panic_output() -> Option { - if cfg!(feature = "wasm_syscall") { - Stderr::new().ok() - } else { - None - } +pub fn panic_output() -> Option> { + None } diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/wasm/time.rs index 3f71461eea487..dd9ad3760b050 100644 --- a/src/libstd/sys/wasm/time.rs +++ b/src/libstd/sys/wasm/time.rs @@ -1,5 +1,4 @@ use crate::time::Duration; -use crate::sys::{TimeSysCall, TimeClock}; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct Instant(Duration); @@ -11,7 +10,7 @@ pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); impl Instant { pub fn now() -> Instant { - Instant(TimeSysCall::perform(TimeClock::Monotonic)) + panic!("time not implemented on wasm32-unknown-unknown") } pub const fn zero() -> Instant { @@ -37,7 +36,7 @@ impl Instant { impl SystemTime { pub fn now() -> SystemTime { - SystemTime(TimeSysCall::perform(TimeClock::System)) + panic!("time not implemented on wasm32-unknown-unknown") } pub fn sub_time(&self, other: &SystemTime) diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index f706709c9ccf4..b1f9d9766f705 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -714,7 +714,7 @@ if #[cfg(target_vendor = "uwp")] { pub struct FILE_STANDARD_INFO { pub AllocationSize: LARGE_INTEGER, pub EndOfFile: LARGE_INTEGER, - pub NumberOfLink: DWORD, + pub NumberOfLinks: DWORD, pub DeletePending: BOOLEAN, pub Directory: BOOLEAN, } diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 5bae6ba4749bd..204f6af5fc1a0 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -357,7 +357,7 @@ impl File { size as c::DWORD))?; attr.file_size = info.AllocationSize as u64; attr.number_of_links = Some(info.NumberOfLinks); - if attr.is_reparse_point() { + if attr.file_type().is_reparse_point() { let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; if let Ok((_, buf)) = self.reparse_point(&mut b) { attr.reparse_tag = buf.ReparseTag; diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 05e0ca6706453..8658deb854635 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -19,7 +19,7 @@ use crate::sys::pipe::{self, AnonPipe}; use crate::sys::stdio; use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; -use crate::sys_common::process::{CommandEnv, EnvKey}; +use crate::sys_common::process::CommandEnv; use crate::borrow::Borrow; use libc::{c_void, EXIT_SUCCESS, EXIT_FAILURE}; @@ -30,30 +30,28 @@ use libc::{c_void, EXIT_SUCCESS, EXIT_FAILURE}; #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] #[doc(hidden)] -pub struct WindowsEnvKey(OsString); +pub struct EnvKey(OsString); -impl From for WindowsEnvKey { +impl From for EnvKey { fn from(k: OsString) -> Self { let mut buf = k.into_inner().into_inner(); buf.make_ascii_uppercase(); - WindowsEnvKey(FromInner::from_inner(FromInner::from_inner(buf))) + EnvKey(FromInner::from_inner(FromInner::from_inner(buf))) } } -impl From for OsString { - fn from(k: WindowsEnvKey) -> Self { k.0 } +impl From for OsString { + fn from(k: EnvKey) -> Self { k.0 } } -impl Borrow for WindowsEnvKey { +impl Borrow for EnvKey { fn borrow(&self) -> &OsStr { &self.0 } } -impl AsRef for WindowsEnvKey { +impl AsRef for EnvKey { fn as_ref(&self) -> &OsStr { &self.0 } } -impl EnvKey for WindowsEnvKey {} - fn ensure_no_nuls>(str: T) -> io::Result { if str.as_ref().encode_wide().any(|b| b == 0) { @@ -66,7 +64,7 @@ fn ensure_no_nuls>(str: T) -> io::Result { pub struct Command { program: OsString, args: Vec, - env: CommandEnv, + env: CommandEnv, cwd: Option, flags: u32, detach: bool, // not currently exposed in std::process @@ -110,7 +108,7 @@ impl Command { pub fn arg(&mut self, arg: &OsStr) { self.args.push(arg.to_os_string()) } - pub fn env_mut(&mut self) -> &mut CommandEnv { + pub fn env_mut(&mut self) -> &mut CommandEnv { &mut self.env } pub fn cwd(&mut self, dir: &OsStr) { @@ -498,7 +496,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result> { } } -fn make_envp(maybe_env: Option>) +fn make_envp(maybe_env: Option>) -> io::Result<(*mut c_void, Vec)> { // On Windows we pass an "environment block" which is not a char**, but // rather a concatenation of null-terminated k=v\0 sequences, with a final diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index bf37ff7ddbd3a..9c406ec39cc45 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -2,25 +2,39 @@ /// supported platforms. use crate::env; +use crate::fmt; use crate::io; +use crate::borrow::Cow; use crate::io::prelude::*; -use crate::mem; -use crate::path::{self, Path}; -use crate::ptr; +use crate::path::{self, Path, PathBuf}; use crate::sync::atomic::{self, Ordering}; use crate::sys::mutex::Mutex; -use backtrace::{BytesOrWideString, Frame, Symbol}; - -pub const HEX_WIDTH: usize = 2 + 2 * mem::size_of::(); +use backtrace_rs::{BacktraceFmt, BytesOrWideString, PrintFmt}; /// Max number of frames to print. const MAX_NB_FRAMES: usize = 100; -/// Prints the current backtrace. -pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { +pub fn lock() -> impl Drop { + struct Guard; static LOCK: Mutex = Mutex::new(); + impl Drop for Guard { + fn drop(&mut self) { + unsafe { + LOCK.unlock(); + } + } + } + + unsafe { + LOCK.lock(); + return Guard; + } +} + +/// Prints the current backtrace. +pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { // There are issues currently linking libbacktrace into tests, and in // general during libstd's own unit tests we're not testing this path. In // test mode immediately return here to optimize away any references to the @@ -32,33 +46,69 @@ pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { // Use a lock to prevent mixed output in multithreading context. // Some platforms also requires it, like `SymFromAddr` on Windows. unsafe { - LOCK.lock(); - let res = _print(w, format); - LOCK.unlock(); - res + let _lock = lock(); + _print(w, format) + } +} + +unsafe fn _print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { + struct DisplayBacktrace { + format: PrintFmt, } + impl fmt::Display for DisplayBacktrace { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + unsafe { + _print_fmt(fmt, self.format) + } + } + } + write!(w, "{}", DisplayBacktrace { format }) } -fn _print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { - writeln!(w, "stack backtrace:")?; +unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result { + let cwd = env::current_dir().ok(); + let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| { + output_filename(fmt, bows, print_fmt, cwd.as_ref()) + }; + let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path); + bt_fmt.add_context()?; + let mut idx = 0; + let mut res = Ok(()); + backtrace_rs::trace_unsynchronized(|frame| { + if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES { + return false; + } - let mut printer = Printer::new(format, w); - unsafe { - backtrace::trace_unsynchronized(|frame| { - let mut hit = false; - backtrace::resolve_frame_unsynchronized(frame, |symbol| { - hit = true; - printer.output(frame, Some(symbol)); - }); - if !hit { - printer.output(frame, None); + let mut hit = false; + let mut stop = false; + backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { + hit = true; + if print_fmt == PrintFmt::Short { + if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { + if sym.contains("__rust_begin_short_backtrace") { + stop = true; + return; + } + } } - !printer.done + + res = bt_fmt.frame().symbol(frame, symbol); }); - } - if printer.skipped { + if stop { + return false; + } + if !hit { + res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); + } + + idx += 1; + res.is_ok() + }); + res?; + bt_fmt.finish()?; + if print_fmt == PrintFmt::Short { writeln!( - w, + fmt, "note: Some details are omitted, \ run with `RUST_BACKTRACE=full` for a verbose backtrace." )?; @@ -66,8 +116,10 @@ fn _print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { Ok(()) } -/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. -#[inline(never)] +/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that +/// this is only inline(never) when backtraces in libstd are enabled, otherwise +/// it's fine to optimize away. +#[cfg_attr(feature = "backtrace", inline(never))] pub fn __rust_begin_short_backtrace(f: F) -> T where F: FnOnce() -> T, @@ -77,169 +129,88 @@ where f() } -/// Controls how the backtrace should be formatted. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum PrintFormat { - /// Show only relevant data from the backtrace. - Short = 2, - /// Show all the frames with absolute path for files. - Full = 3, +pub enum RustBacktrace { + Print(PrintFmt), + Disabled, + RuntimeDisabled, } // For now logging is turned off by default, and this function checks to see // whether the magical environment variable is present to see if it's turned on. -pub fn log_enabled() -> Option { - static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0); - match ENABLED.load(Ordering::SeqCst) { - 0 => {} - 1 => return None, - 2 => return Some(PrintFormat::Short), - _ => return Some(PrintFormat::Full), +pub fn rust_backtrace_env() -> RustBacktrace { + // If the `backtrace` feature of this crate isn't enabled quickly return + // `None` so this can be constant propagated all over the place to turn + // optimize away callers. + if !cfg!(feature = "backtrace") { + return RustBacktrace::Disabled; } - let val = env::var_os("RUST_BACKTRACE").and_then(|x| { - if &x == "0" { - None - } else if &x == "full" { - Some(PrintFormat::Full) - } else { - Some(PrintFormat::Short) - } - }); - ENABLED.store( - match val { - Some(v) => v as isize, - None => 1, - }, - Ordering::SeqCst, - ); - val -} - -struct Printer<'a, 'b> { - format: PrintFormat, - done: bool, - skipped: bool, - idx: usize, - out: &'a mut (dyn Write + 'b), -} - -impl<'a, 'b> Printer<'a, 'b> { - fn new(format: PrintFormat, out: &'a mut (dyn Write + 'b)) -> Printer<'a, 'b> { - Printer { format, done: false, skipped: false, idx: 0, out } + // Setting environment variables for Fuchsia components isn't a standard + // or easily supported workflow. For now, always display backtraces. + if cfg!(target_os = "fuchsia") { + return RustBacktrace::Print(PrintFmt::Full); } - /// Prints the symbol of the backtrace frame. - /// - /// These output functions should now be used everywhere to ensure consistency. - /// You may want to also use `output_fileline`. - fn output(&mut self, frame: &Frame, symbol: Option<&Symbol>) { - if self.idx > MAX_NB_FRAMES { - self.done = true; - self.skipped = true; - return; - } - if self._output(frame, symbol).is_err() { - self.done = true; - } - self.idx += 1; + static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0); + match ENABLED.load(Ordering::SeqCst) { + 0 => {} + 1 => return RustBacktrace::RuntimeDisabled, + 2 => return RustBacktrace::Print(PrintFmt::Short), + _ => return RustBacktrace::Print(PrintFmt::Full), } - fn _output(&mut self, frame: &Frame, symbol: Option<&Symbol>) -> io::Result<()> { - if self.format == PrintFormat::Short { - if let Some(sym) = symbol.and_then(|s| s.name()).and_then(|s| s.as_str()) { - if sym.contains("__rust_begin_short_backtrace") { - self.skipped = true; - self.done = true; - return Ok(()); - } - } - - // Remove the `17: 0x0 - ` line. - if self.format == PrintFormat::Short && frame.ip() == ptr::null_mut() { - self.skipped = true; - return Ok(()); - } - } - - match self.format { - PrintFormat::Full => { - write!(self.out, " {:2}: {:2$?} - ", self.idx, frame.ip(), HEX_WIDTH)? + let (format, cache) = env::var_os("RUST_BACKTRACE") + .map(|x| { + if &x == "0" { + (RustBacktrace::RuntimeDisabled, 1) + } else if &x == "full" { + (RustBacktrace::Print(PrintFmt::Full), 3) + } else { + (RustBacktrace::Print(PrintFmt::Short), 2) } - PrintFormat::Short => write!(self.out, " {:2}: ", self.idx)?, - } + }) + .unwrap_or((RustBacktrace::RuntimeDisabled, 1)); + ENABLED.store(cache, Ordering::SeqCst); + format +} - match symbol.and_then(|s| s.name()) { - Some(symbol) => { - match self.format { - PrintFormat::Full => write!(self.out, "{}", symbol)?, - // Strip the trailing hash if short mode. - PrintFormat::Short => write!(self.out, "{:#}", symbol)?, - } - } - None => self.out.write_all(b"")?, +/// Prints the filename of the backtrace frame. +/// +/// See also `output`. +pub fn output_filename( + fmt: &mut fmt::Formatter<'_>, + bows: BytesOrWideString<'_>, + print_fmt: PrintFmt, + cwd: Option<&PathBuf>, +) -> fmt::Result { + let file: Cow<'_, Path> = match bows { + #[cfg(unix)] + BytesOrWideString::Bytes(bytes) => { + use crate::os::unix::prelude::*; + Path::new(crate::ffi::OsStr::from_bytes(bytes)).into() } - self.out.write_all(b"\n")?; - if let Some(sym) = symbol { - self.output_fileline(sym)?; + #[cfg(not(unix))] + BytesOrWideString::Bytes(bytes) => { + Path::new(crate::str::from_utf8(bytes).unwrap_or("")).into() } - Ok(()) - } - - /// Prints the filename and line number of the backtrace frame. - /// - /// See also `output`. - fn output_fileline(&mut self, symbol: &Symbol) -> io::Result<()> { #[cfg(windows)] - let path_buf; - let file = match symbol.filename_raw() { - #[cfg(unix)] - Some(BytesOrWideString::Bytes(bytes)) => { - use crate::os::unix::prelude::*; - Path::new(crate::ffi::OsStr::from_bytes(bytes)) - } - #[cfg(not(unix))] - Some(BytesOrWideString::Bytes(bytes)) => { - Path::new(crate::str::from_utf8(bytes).unwrap_or("")) - } - #[cfg(windows)] - Some(BytesOrWideString::Wide(wide)) => { - use crate::os::windows::prelude::*; - path_buf = crate::ffi::OsString::from_wide(wide); - Path::new(&path_buf) - } - #[cfg(not(windows))] - Some(BytesOrWideString::Wide(_wide)) => { - Path::new("") - } - None => return Ok(()), - }; - let line = match symbol.lineno() { - Some(line) => line, - None => return Ok(()), - }; - // prior line: " ##: {:2$} - func" - self.out.write_all(b"")?; - match self.format { - PrintFormat::Full => write!(self.out, " {:1$}", "", HEX_WIDTH)?, - PrintFormat::Short => write!(self.out, " ")?, + BytesOrWideString::Wide(wide) => { + use crate::os::windows::prelude::*; + Cow::Owned(crate::ffi::OsString::from_wide(wide).into()) } - - let mut already_printed = false; - if self.format == PrintFormat::Short && file.is_absolute() { - if let Ok(cwd) = env::current_dir() { - if let Ok(stripped) = file.strip_prefix(&cwd) { - if let Some(s) = stripped.to_str() { - write!(self.out, " at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?; - already_printed = true; - } + #[cfg(not(windows))] + BytesOrWideString::Wide(_wide) => { + Path::new("").into() + } + }; + if print_fmt == PrintFmt::Short && file.is_absolute() { + if let Some(cwd) = cwd { + if let Ok(stripped) = file.strip_prefix(&cwd) { + if let Some(s) = stripped.to_str() { + return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s); } } } - if !already_printed { - write!(self.out, " at {}:{}", file.display(), line)?; - } - - self.out.write_all(b"\n") } + fmt::Display::fmt(&file.display(), fmt) } diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index 9190a3b0d5fc7..cba3eca538625 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -41,7 +41,6 @@ macro_rules! rtunwrap { pub mod alloc; pub mod at_exit_imp; -#[cfg(feature = "backtrace")] pub mod backtrace; pub mod condvar; pub mod io; diff --git a/src/libstd/sys_common/os_str_bytes.rs b/src/libstd/sys_common/os_str_bytes.rs index a4961974d89ab..d734f412bf886 100644 --- a/src/libstd/sys_common/os_str_bytes.rs +++ b/src/libstd/sys_common/os_str_bytes.rs @@ -18,6 +18,12 @@ pub(crate) struct Buf { pub inner: Vec } +// FIXME: +// `Buf::as_slice` current implementation relies +// on `Slice` being layout-compatible with `[u8]`. +// When attribute privacy is implemented, `Slice` should be annotated as `#[repr(transparent)]`. +// Anyway, `Slice` representation and layout are considered implementation detail, are +// not documented and must not be relied upon. pub(crate) struct Slice { pub inner: [u8] } diff --git a/src/libstd/sys_common/process.rs b/src/libstd/sys_common/process.rs index 4d40dec97245a..bdf66fca35970 100644 --- a/src/libstd/sys_common/process.rs +++ b/src/libstd/sys_common/process.rs @@ -1,47 +1,20 @@ #![allow(dead_code)] #![unstable(feature = "process_internals", issue = "0")] -use crate::ffi::{OsStr, OsString}; -use crate::env; use crate::collections::BTreeMap; -use crate::borrow::Borrow; - -pub trait EnvKey: - From + Into + - Borrow + Borrow + AsRef + - Ord + Clone {} - -// Implement a case-sensitive environment variable key -#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] -pub struct DefaultEnvKey(OsString); - -impl From for DefaultEnvKey { - fn from(k: OsString) -> Self { DefaultEnvKey(k) } -} - -impl From for OsString { - fn from(k: DefaultEnvKey) -> Self { k.0 } -} - -impl Borrow for DefaultEnvKey { - fn borrow(&self) -> &OsStr { &self.0 } -} - -impl AsRef for DefaultEnvKey { - fn as_ref(&self) -> &OsStr { &self.0 } -} - -impl EnvKey for DefaultEnvKey {} +use crate::env; +use crate::ffi::{OsStr, OsString}; +use crate::sys::process::EnvKey; // Stores a set of changes to an environment #[derive(Clone, Debug)] -pub struct CommandEnv { +pub struct CommandEnv { clear: bool, saw_path: bool, - vars: BTreeMap> + vars: BTreeMap> } -impl Default for CommandEnv { +impl Default for CommandEnv { fn default() -> Self { CommandEnv { clear: false, @@ -51,10 +24,10 @@ impl Default for CommandEnv { } } -impl CommandEnv { +impl CommandEnv { // Capture the current environment with these changes applied - pub fn capture(&self) -> BTreeMap { - let mut result = BTreeMap::::new(); + pub fn capture(&self) -> BTreeMap { + let mut result = BTreeMap::::new(); if !self.clear { for (k, v) in env::vars_os() { result.insert(k.into(), v); @@ -90,7 +63,7 @@ impl CommandEnv { !self.clear && self.vars.is_empty() } - pub fn capture_if_changed(&self) -> Option> { + pub fn capture_if_changed(&self) -> Option> { if self.is_unchanged() { None } else { @@ -103,6 +76,7 @@ impl CommandEnv { self.maybe_saw_path(&key); self.vars.insert(key.to_owned().into(), Some(value.to_owned())); } + pub fn remove(&mut self, key: &OsStr) { self.maybe_saw_path(&key); if self.clear { @@ -111,13 +85,16 @@ impl CommandEnv { self.vars.insert(key.to_owned().into(), None); } } + pub fn clear(&mut self) { self.clear = true; self.vars.clear(); } + pub fn have_changed_path(&self) -> bool { self.saw_path || self.clear } + fn maybe_saw_path(&mut self, key: &OsStr) { if !self.saw_path && key == "PATH" { self.saw_path = true; diff --git a/src/libstd/tests/env.rs b/src/libstd/tests/env.rs index 06fb5533afdd8..f8014cb2ad9af 100644 --- a/src/libstd/tests/env.rs +++ b/src/libstd/tests/env.rs @@ -5,7 +5,7 @@ use rand::{thread_rng, Rng}; use rand::distributions::Alphanumeric; fn make_rand_name() -> OsString { - let mut rng = thread_rng(); + let rng = thread_rng(); let n = format!("TEST{}", rng.sample_iter(&Alphanumeric).take(10) .collect::()); let n = OsString::from(n); diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index f85b5d632f16b..e92c0d1c58e41 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -236,8 +236,8 @@ impl LocalKey { #[stable(feature = "rust1", since = "1.0.0")] pub fn with(&'static self, f: F) -> R where F: FnOnce(&T) -> R { - self.try_with(f).expect("cannot access a TLS value during or \ - after it is destroyed") + self.try_with(f).expect("cannot access a Thread Local Storage value \ + during or after destruction") } /// Acquires a reference to the value in this TLS key. diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 764041d2f4239..0ffa6ace2e4d2 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -465,12 +465,9 @@ impl Builder { } thread_info::set(imp::guard::current(), their_thread); - #[cfg(feature = "backtrace")] let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { crate::sys_common::backtrace::__rust_begin_short_backtrace(f) })); - #[cfg(not(feature = "backtrace"))] - let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f)); *their_packet.get() = Some(try_result); }; diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 98371b9ba3d7e..e1ae01b602a8d 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -15,10 +15,10 @@ use crate::cmp; use crate::error::Error; use crate::fmt; -use crate::ops::{Add, Sub, AddAssign, SubAssign}; +use crate::ops::{Add, AddAssign, Sub, SubAssign}; use crate::sys::time; -use crate::sys_common::FromInner; use crate::sys_common::mutex::Mutex; +use crate::sys_common::FromInner; #[stable(feature = "time", since = "1.3.0")] pub use core::time::Duration; @@ -59,6 +59,30 @@ pub use core::time::Duration; /// println!("{}", now.elapsed().as_secs()); /// } /// ``` +/// +/// # Underlying System calls +/// Currently, the following system calls are being used to get the current time using `now()`: +/// +/// | Platform | System call | +/// |:---------:|:--------------------------------------------------------------------:| +/// | Cloud ABI | [clock_time_get (Monotonic Clock)] | +/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] | +/// | UNIX | [clock_time_get (Monotonic Clock)] | +/// | Darwin | [mach_absolute_time] | +/// | VXWorks | [clock_gettime (Monotonic Clock)] | +/// | WASI | [__wasi_clock_time_get (Monotonic Clock)] | +/// | Windows | [QueryPerformanceCounter] | +/// +/// [QueryPerformanceCounter]: https://docs.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter +/// [`insecure_time` usercall]: https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#method.insecure_time +/// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode +/// [__wasi_clock_time_get (Monotonic Clock)]: https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-api.md#clock_time_get +/// [clock_gettime (Monotonic Clock)]: https://linux.die.net/man/3/clock_gettime +/// [mach_absolute_time]: https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/services/services.html +/// [clock_time_get (Monotonic Clock)]: https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt +/// +/// **Disclaimer:** These system calls might change over time. +/// #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[stable(feature = "time2", since = "1.8.0")] pub struct Instant(time::Instant); @@ -114,6 +138,28 @@ pub struct Instant(time::Instant); /// } /// } /// ``` +/// +/// # Underlying System calls +/// Currently, the following system calls are being used to get the current time using `now()`: +/// +/// | Platform | System call | +/// |:---------:|:--------------------------------------------------------------------:| +/// | Cloud ABI | [clock_time_get (Realtime Clock)] | +/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] | +/// | UNIX | [clock_gettime (Realtime Clock)] | +/// | DARWIN | [gettimeofday] | +/// | VXWorks | [clock_gettime (Realtime Clock)] | +/// | WASI | [__wasi_clock_time_get (Realtime Clock)] | +/// | Windows | [GetSystemTimeAsFileTime] | +/// +/// [clock_time_get (Realtime Clock)]: https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt +/// [gettimeofday]: http://man7.org/linux/man-pages/man2/gettimeofday.2.html +/// [clock_gettime (Realtime Clock)]: https://linux.die.net/man/3/clock_gettime +/// [__wasi_clock_time_get (Realtime Clock)]: https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-api.md#clock_time_get +/// [GetSystemTimeAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime +/// +/// **Disclaimer:** These system calls might change over time. +/// #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[stable(feature = "time2", since = "1.8.0")] pub struct SystemTime(time::SystemTime); @@ -170,17 +216,17 @@ impl Instant { // * https://bugzilla.mozilla.org/show_bug.cgi?id=1487778 - a similar // Firefox bug // - // It simply seems that this it just happens so that a lot in the wild - // we're seeing panics across various platforms where consecutive calls + // It seems that this just happens a lot in the wild. + // We're seeing panics across various platforms where consecutive calls // to `Instant::now`, such as via the `elapsed` function, are panicking // as they're going backwards. Placed here is a last-ditch effort to try // to fix things up. We keep a global "latest now" instance which is // returned instead of what the OS says if the OS goes backwards. // - // To hopefully mitigate the impact of this though a few platforms are + // To hopefully mitigate the impact of this, a few platforms are // whitelisted as "these at least haven't gone backwards yet". if time::Instant::actually_monotonic() { - return Instant(os_now) + return Instant(os_now); } static LOCK: Mutex = Mutex::new(); @@ -216,12 +262,11 @@ impl Instant { } /// Returns the amount of time elapsed from another instant to this one, - /// or None if that instant is earlier than this one. + /// or None if that instant is later than this one. /// /// # Examples /// /// ```no_run - /// #![feature(checked_duration_since)] /// use std::time::{Duration, Instant}; /// use std::thread::sleep; /// @@ -231,7 +276,7 @@ impl Instant { /// println!("{:?}", new_now.checked_duration_since(now)); /// println!("{:?}", now.checked_duration_since(new_now)); // None /// ``` - #[unstable(feature = "checked_duration_since", issue = "58402")] + #[stable(feature = "checked_duration_since", since = "1.39.0")] pub fn checked_duration_since(&self, earlier: Instant) -> Option { self.0.checked_sub_instant(&earlier.0) } @@ -242,7 +287,6 @@ impl Instant { /// # Examples /// /// ```no_run - /// #![feature(checked_duration_since)] /// use std::time::{Duration, Instant}; /// use std::thread::sleep; /// @@ -252,7 +296,7 @@ impl Instant { /// println!("{:?}", new_now.saturating_duration_since(now)); /// println!("{:?}", now.saturating_duration_since(new_now)); // 0ns /// ``` - #[unstable(feature = "checked_duration_since", issue = "58402")] + #[stable(feature = "checked_duration_since", since = "1.39.0")] pub fn saturating_duration_since(&self, earlier: Instant) -> Duration { self.checked_duration_since(earlier).unwrap_or(Duration::new(0, 0)) } @@ -309,8 +353,7 @@ impl Add for Instant { /// /// [`checked_add`]: ../../std/time/struct.Instant.html#method.checked_add fn add(self, other: Duration) -> Instant { - self.checked_add(other) - .expect("overflow when adding duration to instant") + self.checked_add(other).expect("overflow when adding duration to instant") } } @@ -326,8 +369,7 @@ impl Sub for Instant { type Output = Instant; fn sub(self, other: Duration) -> Instant { - self.checked_sub(other) - .expect("overflow when subtracting duration from instant") + self.checked_sub(other).expect("overflow when subtracting duration from instant") } } @@ -420,8 +462,7 @@ impl SystemTime { /// println!("{:?}", difference); /// ``` #[stable(feature = "time2", since = "1.8.0")] - pub fn duration_since(&self, earlier: SystemTime) - -> Result { + pub fn duration_since(&self, earlier: SystemTime) -> Result { self.0.sub_time(&earlier.0).map_err(SystemTimeError) } @@ -488,8 +529,7 @@ impl Add for SystemTime { /// /// [`checked_add`]: ../../std/time/struct.SystemTime.html#method.checked_add fn add(self, dur: Duration) -> SystemTime { - self.checked_add(dur) - .expect("overflow when adding duration to instant") + self.checked_add(dur).expect("overflow when adding duration to instant") } } @@ -505,8 +545,7 @@ impl Sub for SystemTime { type Output = SystemTime; fn sub(self, dur: Duration) -> SystemTime { - self.checked_sub(dur) - .expect("overflow when subtracting duration from instant") + self.checked_sub(dur).expect("overflow when subtracting duration from instant") } } @@ -582,7 +621,9 @@ impl SystemTimeError { #[stable(feature = "time2", since = "1.8.0")] impl Error for SystemTimeError { - fn description(&self) -> &str { "other time was not earlier than self" } + fn description(&self) -> &str { + "other time was not earlier than self" + } } #[stable(feature = "time2", since = "1.8.0")] @@ -600,17 +641,16 @@ impl FromInner for SystemTime { #[cfg(test)] mod tests { - use super::{Instant, SystemTime, Duration, UNIX_EPOCH}; + use super::{Duration, Instant, SystemTime, UNIX_EPOCH}; macro_rules! assert_almost_eq { - ($a:expr, $b:expr) => ({ + ($a:expr, $b:expr) => {{ let (a, b) = ($a, $b); if a != b { - let (a, b) = if a > b {(a, b)} else {(b, a)}; - assert!(a - Duration::new(0, 1000) <= b, - "{:?} is not almost equal to {:?}", a, b); + let (a, b) = if a > b { (a, b) } else { (b, a) }; + assert!(a - Duration::new(0, 1000) <= b, "{:?} is not almost equal to {:?}", a, b); } - }) + }}; } #[test] @@ -685,7 +725,7 @@ mod tests { fn instant_saturating_duration_since_nopanic() { let a = Instant::now(); let ret = (a - Duration::new(1, 0)).saturating_duration_since(a); - assert_eq!(ret, Duration::new(0,0)); + assert_eq!(ret, Duration::new(0, 0)); } #[test] @@ -711,15 +751,14 @@ mod tests { let second = Duration::new(1, 0); assert_almost_eq!(a.duration_since(a - second).unwrap(), second); - assert_almost_eq!(a.duration_since(a + second).unwrap_err() - .duration(), second); + assert_almost_eq!(a.duration_since(a + second).unwrap_err().duration(), second); assert_almost_eq!(a - second + second, a); assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a); let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0); - let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000) - + Duration::new(0, 500_000_000); + let one_second_from_epoch2 = + UNIX_EPOCH + Duration::new(0, 500_000_000) + Duration::new(0, 500_000_000); assert_eq!(one_second_from_epoch, one_second_from_epoch2); // checked_add_duration will not panic on overflow diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index d4a9acc1569b4..d8de21cc6778f 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -18,7 +18,7 @@ lazy_static = "1.0.0" syntax_pos = { path = "../libsyntax_pos" } errors = { path = "../librustc_errors", package = "rustc_errors" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_index = { path = "../librustc_index" } rustc_lexer = { path = "../librustc_lexer" } -rustc_macros = { path = "../librustc_macros" } rustc_target = { path = "../librustc_target" } smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 052eb55b40811..023952042e6d4 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -5,7 +5,7 @@ pub use UnsafeSource::*; pub use crate::symbol::{Ident, Symbol as Name}; pub use crate::util::parser::ExprPrecedence; -use crate::ext::hygiene::{ExpnId, SyntaxContext}; +use crate::ext::hygiene::ExpnId; use crate::parse::token::{self, DelimToken}; use crate::print::pprust; use crate::ptr::P; @@ -14,7 +14,7 @@ use crate::symbol::{kw, sym, Symbol}; use crate::tokenstream::TokenStream; use crate::ThinVec; -use rustc_data_structures::indexed_vec::Idx; +use rustc_index::vec::Idx; #[cfg(target_arch = "x86_64")] use rustc_data_structures::static_assert_size; use rustc_target::spec::abi::Abi; @@ -241,9 +241,8 @@ impl ParenthesizedArgs { // hack to ensure that we don't try to access the private parts of `NodeId` in this module mod node_id_inner { - use rustc_data_structures::indexed_vec::Idx; - use rustc_data_structures::newtype_index; - newtype_index! { + use rustc_index::vec::Idx; + rustc_index::newtype_index! { pub struct NodeId { ENCODABLE = custom DEBUG_FORMAT = "NodeId({})" @@ -352,7 +351,7 @@ pub struct GenericParam { pub ident: Ident, pub attrs: ThinVec, pub bounds: GenericBounds, - + pub is_placeholder: bool, pub kind: GenericParamKind, } @@ -413,11 +412,11 @@ impl WherePredicate { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct WhereBoundPredicate { pub span: Span, - /// Any generics from a `for` binding + /// Any generics from a `for` binding. pub bound_generic_params: Vec, - /// The type being bounded + /// The type being bounded. pub bounded_ty: P, - /// Trait and lifetime bounds (`Clone+Send+'static`) + /// Trait and lifetime bounds (`Clone + Send + 'static`). pub bounds: GenericBounds, } @@ -472,7 +471,7 @@ pub enum NestedMetaItem { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct MetaItem { pub path: Path, - pub node: MetaItemKind, + pub kind: MetaItemKind, pub span: Span, } @@ -495,15 +494,15 @@ pub enum MetaItemKind { NameValue(Lit), } -/// A Block (`{ .. }`). +/// A block (`{ .. }`). /// /// E.g., `{ .. }` as in `fn foo() { .. }`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Block { - /// Statements in a block + /// The statements in the block. pub stmts: Vec, pub id: NodeId, - /// Distinguishes between `unsafe { ... }` and `{ ... }` + /// Distinguishes between `unsafe { ... }` and `{ ... }`. pub rules: BlockCheckMode, pub span: Span, } @@ -511,7 +510,7 @@ pub struct Block { #[derive(Clone, RustcEncodable, RustcDecodable)] pub struct Pat { pub id: NodeId, - pub node: PatKind, + pub kind: PatKind, pub span: Span, } @@ -525,7 +524,7 @@ impl Pat { /// Attempt reparsing the pattern as a type. /// This is intended for use by diagnostics. pub(super) fn to_ty(&self) -> Option> { - let node = match &self.node { + let kind = match &self.kind { // In a type expression `_` is an inference variable. PatKind::Wild => TyKind::Infer, // An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`. @@ -555,40 +554,43 @@ impl Pat { }; Some(P(Ty { - node, + kind, id: self.id, span: self.span, })) } - pub fn walk(&self, it: &mut F) -> bool - where - F: FnMut(&Pat) -> bool, - { + /// Walk top-down and call `it` in each place where a pattern occurs + /// starting with the root pattern `walk` is called on. If `it` returns + /// false then we will descend no further but siblings will be processed. + pub fn walk(&self, it: &mut impl FnMut(&Pat) -> bool) { if !it(self) { - return false; + return; } - match &self.node { + match &self.kind { PatKind::Ident(_, _, Some(p)) => p.walk(it), - PatKind::Struct(_, fields, _) => fields.iter().all(|field| field.node.pat.walk(it)), - PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) => { - s.iter().all(|p| p.walk(it)) - } - PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it), + PatKind::Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk(it)), + PatKind::TupleStruct(_, s) + | PatKind::Tuple(s) + | PatKind::Slice(s) + | PatKind::Or(s) => s.iter().for_each(|p| p.walk(it)), + PatKind::Box(s) + | PatKind::Ref(s, _) + | PatKind::Paren(s) => s.walk(it), PatKind::Wild | PatKind::Rest | PatKind::Lit(_) | PatKind::Range(..) | PatKind::Ident(..) | PatKind::Path(..) - | PatKind::Mac(_) => true, + | PatKind::Mac(_) => {}, } } /// Is this a `..` pattern? pub fn is_rest(&self) -> bool { - match self.node { + match self.kind { PatKind::Rest => true, _ => false, } @@ -608,6 +610,9 @@ pub struct FieldPat { pub pat: P, pub is_shorthand: bool, pub attrs: ThinVec, + pub id: NodeId, + pub span: Span, + pub is_placeholder: bool, } #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)] @@ -641,11 +646,15 @@ pub enum PatKind { /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`). /// The `bool` is `true` in the presence of a `..`. - Struct(Path, Vec>, /* recovered */ bool), + Struct(Path, Vec, /* recovered */ bool), /// A tuple struct/variant pattern (`Variant(x, y, .., z)`). TupleStruct(Path, Vec>), + /// An or-pattern `A | B | C`. + /// Invariant: `pats.len() >= 2`. + Or(Vec>), + /// A possibly qualified path pattern. /// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants /// or associated constants. Qualified path patterns `::B::C`/`::B::C` can @@ -825,31 +834,31 @@ impl UnOp { #[derive(Clone, RustcEncodable, RustcDecodable)] pub struct Stmt { pub id: NodeId, - pub node: StmtKind, + pub kind: StmtKind, pub span: Span, } impl Stmt { pub fn add_trailing_semicolon(mut self) -> Self { - self.node = match self.node { + self.kind = match self.kind { StmtKind::Expr(expr) => StmtKind::Semi(expr), StmtKind::Mac(mac) => { StmtKind::Mac(mac.map(|(mac, _style, attrs)| (mac, MacStmtStyle::Semicolon, attrs))) } - node => node, + kind => kind, }; self } pub fn is_item(&self) -> bool { - match self.node { + match self.kind { StmtKind::Item(_) => true, _ => false, } } pub fn is_expr(&self) -> bool { - match self.node { + match self.kind { StmtKind::Expr(_) => true, _ => false, } @@ -899,11 +908,11 @@ pub enum MacStmtStyle { /// Local represents a `let` statement, e.g., `let : = ;`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Local { + pub id: NodeId, pub pat: P, pub ty: Option>, /// Initializer expression to set the value, if any. pub init: Option>, - pub id: NodeId, pub span: Span, pub attrs: ThinVec, } @@ -921,10 +930,12 @@ pub struct Local { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Arm { pub attrs: Vec, - pub pats: Vec>, + pub pat: P, pub guard: Option>, pub body: P, pub span: Span, + pub id: NodeId, + pub is_placeholder: bool, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] @@ -934,10 +945,10 @@ pub struct Field { pub span: Span, pub is_shorthand: bool, pub attrs: ThinVec, + pub id: NodeId, + pub is_placeholder: bool, } -pub type SpannedIdent = Spanned; - #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)] pub enum BlockCheckMode { Default, @@ -961,11 +972,11 @@ pub struct AnonConst { pub value: P, } -/// An expression +/// An expression. #[derive(Clone, RustcEncodable, RustcDecodable)] pub struct Expr { pub id: NodeId, - pub node: ExprKind, + pub kind: ExprKind, pub span: Span, pub attrs: ThinVec, } @@ -975,32 +986,32 @@ pub struct Expr { static_assert_size!(Expr, 96); impl Expr { - /// Whether this expression would be valid somewhere that expects a value; for example, an `if` - /// condition. + /// Returns `true` if this expression would be valid somewhere that expects a value; + /// for example, an `if` condition. pub fn returns(&self) -> bool { - if let ExprKind::Block(ref block, _) = self.node { - match block.stmts.last().map(|last_stmt| &last_stmt.node) { - // implicit return + if let ExprKind::Block(ref block, _) = self.kind { + match block.stmts.last().map(|last_stmt| &last_stmt.kind) { + // Implicit return Some(&StmtKind::Expr(_)) => true, Some(&StmtKind::Semi(ref expr)) => { - if let ExprKind::Ret(_) = expr.node { - // last statement is explicit return + if let ExprKind::Ret(_) = expr.kind { + // Last statement is explicit return. true } else { false } } - // This is a block that doesn't end in either an implicit or explicit return + // This is a block that doesn't end in either an implicit or explicit return. _ => false, } } else { - // This is not a block, it is a value + // This is not a block, it is a value. true } } fn to_bound(&self) -> Option { - match &self.node { + match &self.kind { ExprKind::Path(None, path) => Some(GenericBound::Trait( PolyTraitRef::new(Vec::new(), path.clone(), self.span), TraitBoundModifier::None, @@ -1010,7 +1021,7 @@ impl Expr { } pub(super) fn to_ty(&self) -> Option> { - let node = match &self.node { + let kind = match &self.kind { ExprKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()), ExprKind::Mac(mac) => TyKind::Mac(mac.clone()), ExprKind::Paren(expr) => expr.to_ty().map(TyKind::Paren)?, @@ -1039,14 +1050,14 @@ impl Expr { }; Some(P(Ty { - node, + kind, id: self.id, span: self.span, })) } pub fn precedence(&self) -> ExprPrecedence { - match self.node { + match self.kind { ExprKind::Box(_) => ExprPrecedence::Box, ExprKind::Array(_) => ExprPrecedence::Array, ExprKind::Call(..) => ExprPrecedence::Call, @@ -1139,12 +1150,9 @@ pub enum ExprKind { Cast(P, P), /// A type ascription (e.g., `42: usize`). Type(P, P), - /// A `let pats = expr` expression that is only semantically allowed in the condition + /// A `let pat = expr` expression that is only semantically allowed in the condition /// of `if` / `while` expressions. (e.g., `if let 0 = x { .. }`). - /// - /// The `Vec>` is for or-patterns at the top level. - /// FIXME(54883): Change this to just `P`. - Let(Vec>, P), + Let(P, P), /// An `if` block, with an optional `else` block. /// /// `if expr { block } else { expr }` @@ -1284,8 +1292,6 @@ pub enum Movability { Movable, } -pub type Mac = Spanned; - /// Represents a macro invocation. The `Path` indicates which macro /// is being invoked, and the vector of token-trees contains the source /// of the macro invocation. @@ -1293,10 +1299,11 @@ pub type Mac = Spanned; /// N.B., the additional ident for a `macro_rules`-style macro is actually /// stored in the enclosing item. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub struct Mac_ { +pub struct Mac { pub path: Path, pub delim: MacDelimiter, pub tts: TokenStream, + pub span: Span, pub prior_type_ascription: Option<(Span, bool)>, } @@ -1307,7 +1314,7 @@ pub enum MacDelimiter { Brace, } -impl Mac_ { +impl Mac { pub fn stream(&self) -> TokenStream { self.tts.clone() } @@ -1353,7 +1360,7 @@ pub struct Lit { /// The "semantic" representation of the literal lowered from the original tokens. /// Strings are unescaped, hexadecimal forms are eliminated, etc. /// FIXME: Remove this and only create the semantic representation during lowering to HIR. - pub node: LitKind, + pub kind: LitKind, pub span: Span, } @@ -1466,7 +1473,7 @@ pub struct TraitItem { pub ident: Ident, pub attrs: Vec, pub generics: Generics, - pub node: TraitItemKind, + pub kind: TraitItemKind, pub span: Span, /// See `Item::tokens` for what this is. pub tokens: Option, @@ -1489,7 +1496,7 @@ pub struct ImplItem { pub defaultness: Defaultness, pub attrs: Vec, pub generics: Generics, - pub node: ImplItemKind, + pub kind: ImplItemKind, pub span: Span, /// See `Item::tokens` for what this is. pub tokens: Option, @@ -1656,7 +1663,7 @@ pub enum AssocTyConstraintKind { #[derive(Clone, RustcEncodable, RustcDecodable)] pub struct Ty { pub id: NodeId, - pub node: TyKind, + pub kind: TyKind, pub span: Span, } @@ -1781,19 +1788,19 @@ pub struct InlineAsm { pub volatile: bool, pub alignstack: bool, pub dialect: AsmDialect, - pub ctxt: SyntaxContext, } -/// An argument in a function header. +/// A parameter in a function header. /// /// E.g., `bar: usize` as in `fn foo(bar: usize)`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub struct Arg { +pub struct Param { pub attrs: ThinVec, pub ty: P, pub pat: P, pub id: NodeId, pub span: Span, + pub is_placeholder: bool, } /// Alternative representation for `Arg`s describing `self` parameter of methods. @@ -1811,13 +1818,13 @@ pub enum SelfKind { pub type ExplicitSelf = Spanned; -impl Arg { +impl Param { pub fn to_self(&self) -> Option { - if let PatKind::Ident(BindingMode::ByValue(mutbl), ident, _) = self.pat.node { + if let PatKind::Ident(BindingMode::ByValue(mutbl), ident, _) = self.pat.kind { if ident.name == kw::SelfLower { - return match self.ty.node { + return match self.ty.kind { TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))), - TyKind::Rptr(lt, MutTy { ref ty, mutbl }) if ty.node.is_implicit_self() => { + TyKind::Rptr(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => { Some(respan(self.pat.span, SelfKind::Region(lt, mutbl))) } _ => Some(respan( @@ -1831,39 +1838,40 @@ impl Arg { } pub fn is_self(&self) -> bool { - if let PatKind::Ident(_, ident, _) = self.pat.node { + if let PatKind::Ident(_, ident, _) = self.pat.kind { ident.name == kw::SelfLower } else { false } } - pub fn from_self(attrs: ThinVec, eself: ExplicitSelf, eself_ident: Ident) -> Arg { + pub fn from_self(attrs: ThinVec, eself: ExplicitSelf, eself_ident: Ident) -> Param { let span = eself.span.to(eself_ident.span); let infer_ty = P(Ty { id: DUMMY_NODE_ID, - node: TyKind::ImplicitSelf, + kind: TyKind::ImplicitSelf, span, }); - let arg = |mutbl, ty| Arg { + let param = |mutbl, ty| Param { attrs, pat: P(Pat { id: DUMMY_NODE_ID, - node: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None), + kind: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None), span, }), span, ty, id: DUMMY_NODE_ID, + is_placeholder: false }; match eself.node { - SelfKind::Explicit(ty, mutbl) => arg(mutbl, ty), - SelfKind::Value(mutbl) => arg(mutbl, infer_ty), - SelfKind::Region(lt, mutbl) => arg( + SelfKind::Explicit(ty, mutbl) => param(mutbl, ty), + SelfKind::Value(mutbl) => param(mutbl, infer_ty), + SelfKind::Region(lt, mutbl) => param( Mutability::Immutable, P(Ty { id: DUMMY_NODE_ID, - node: TyKind::Rptr( + kind: TyKind::Rptr( lt, MutTy { ty: infer_ty, @@ -1882,17 +1890,22 @@ impl Arg { /// E.g., `fn foo(bar: baz)`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct FnDecl { - pub inputs: Vec, + pub inputs: Vec, pub output: FunctionRetTy, - pub c_variadic: bool, } impl FnDecl { pub fn get_self(&self) -> Option { - self.inputs.get(0).and_then(Arg::to_self) + self.inputs.get(0).and_then(Param::to_self) } pub fn has_self(&self) -> bool { - self.inputs.get(0).map(Arg::is_self).unwrap_or(false) + self.inputs.get(0).map(Param::is_self).unwrap_or(false) + } + pub fn c_variadic(&self) -> bool { + self.inputs.last().map(|arg| match arg.ty.kind { + TyKind::CVarArgs => true, + _ => false, + }).unwrap_or(false) } } @@ -2029,7 +2042,6 @@ pub struct ForeignMod { #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy)] pub struct GlobalAsm { pub asm: Symbol, - pub ctxt: SyntaxContext, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] @@ -2038,7 +2050,7 @@ pub struct EnumDef { } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub struct Variant_ { +pub struct Variant { /// Name of the variant. pub ident: Ident, /// Attributes of the variant. @@ -2049,10 +2061,12 @@ pub struct Variant_ { pub data: VariantData, /// Explicit discriminant, e.g., `Foo = 1`. pub disr_expr: Option, + /// Span + pub span: Span, + /// Is a macro placeholder + pub is_placeholder: bool, } -pub type Variant = Spanned; - /// Part of `use` item to the right of its prefix. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum UseTreeKind { @@ -2125,18 +2139,29 @@ impl rustc_serialize::Decodable for AttrId { } } +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub struct AttrItem { + pub path: Path, + pub tokens: TokenStream, +} + /// Metadata associated with an item. /// Doc-comments are promoted to attributes that have `is_sugared_doc = true`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Attribute { + pub item: AttrItem, pub id: AttrId, pub style: AttrStyle, - pub path: Path, - pub tokens: TokenStream, pub is_sugared_doc: bool, pub span: Span, } +// Compatibility impl to avoid churn, consider removing. +impl std::ops::Deref for Attribute { + type Target = AttrItem; + fn deref(&self) -> &Self::Target { &self.item } +} + /// `TraitRef`s appear in impls. /// /// Resolution maps each `TraitRef`'s `ref_id` to its defining trait; that's all @@ -2213,6 +2238,7 @@ pub struct StructField { pub id: NodeId, pub ty: P, pub attrs: Vec, + pub is_placeholder: bool, } /// Fields and constructor ids of enum variants and structs. @@ -2258,7 +2284,7 @@ pub struct Item { pub ident: Ident, pub attrs: Vec, pub id: NodeId, - pub node: ItemKind, + pub kind: ItemKind, pub vis: Visibility, pub span: Span, @@ -2304,37 +2330,37 @@ impl Default for FnHeader { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum ItemKind { - /// An `extern crate` item, with optional *original* crate name if the crate was renamed. + /// An `extern crate` item, with the optional *original* crate name if the crate was renamed. /// /// E.g., `extern crate foo` or `extern crate foo_bar as foo`. ExternCrate(Option), - /// A use declaration (`use` or `pub use`) item. + /// A use declaration item (`use`). /// /// E.g., `use foo;`, `use foo::bar;` or `use foo::bar as FooBar;`. Use(P), - /// A static item (`static` or `pub static`). + /// A static item (`static`). /// /// E.g., `static FOO: i32 = 42;` or `static FOO: &'static str = "bar";`. Static(P, Mutability, P), - /// A constant item (`const` or `pub const`). + /// A constant item (`const`). /// /// E.g., `const FOO: i32 = 42;`. Const(P, P), - /// A function declaration (`fn` or `pub fn`). + /// A function declaration (`fn`). /// /// E.g., `fn foo(bar: usize) -> usize { .. }`. Fn(P, FnHeader, Generics, P), - /// A module declaration (`mod` or `pub mod`). + /// A module declaration (`mod`). /// /// E.g., `mod foo;` or `mod foo { .. }`. Mod(Mod), - /// An external module (`extern` or `pub extern`). + /// An external module (`extern`). /// /// E.g., `extern {}` or `extern "C" {}`. ForeignMod(ForeignMod), /// Module-level inline assembly (from `global_asm!()`). GlobalAsm(P), - /// A type alias (`type` or `pub type`). + /// A type alias (`type`). /// /// E.g., `type Foo = Bar;`. TyAlias(P, Generics), @@ -2342,19 +2368,19 @@ pub enum ItemKind { /// /// E.g., `type Foo = impl Bar + Boo;`. OpaqueTy(GenericBounds, Generics), - /// An enum definition (`enum` or `pub enum`). + /// An enum definition (`enum`). /// /// E.g., `enum Foo { C, D }`. Enum(EnumDef, Generics), - /// A struct definition (`struct` or `pub struct`). + /// A struct definition (`struct`). /// /// E.g., `struct Foo { x: A }`. Struct(VariantData, Generics), - /// A union definition (`union` or `pub union`). + /// A union definition (`union`). /// /// E.g., `union Foo { x: A, y: B }`. Union(VariantData, Generics), - /// A Trait declaration (`trait` or `pub trait`). + /// A trait declaration (`trait`). /// /// E.g., `trait Foo { .. }`, `trait Foo { .. }` or `auto trait Foo {}`. Trait(IsAuto, Unsafety, Generics, GenericBounds, Vec), @@ -2376,7 +2402,7 @@ pub enum ItemKind { ), /// A macro invocation. /// - /// E.g., `macro_rules! foo { .. }` or `foo!(..)`. + /// E.g., `foo!(..)`. Mac(Mac), /// A macro definition. @@ -2410,7 +2436,7 @@ impl ItemKind { pub struct ForeignItem { pub ident: Ident, pub attrs: Vec, - pub node: ForeignItemKind, + pub kind: ForeignItemKind, pub id: NodeId, pub span: Span, pub vis: Visibility, diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index 5fb513783fbaa..2a8e6b2cc9510 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -36,7 +36,7 @@ impl AttributeTemplate { match meta_item_kind { ast::MetaItemKind::Word => self.word, ast::MetaItemKind::List(..) => self.list.is_some(), - ast::MetaItemKind::NameValue(lit) if lit.node.is_str() => self.name_value_str.is_some(), + ast::MetaItemKind::NameValue(lit) if lit.kind.is_str() => self.name_value_str.is_some(), ast::MetaItemKind::NameValue(..) => false, } } @@ -106,7 +106,7 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op attrs.iter().fold(None, |ia, attr| { if attr.check_name(sym::unwind) { if let Some(meta) = attr.meta() { - if let MetaItemKind::List(items) = meta.node { + if let MetaItemKind::List(items) = meta.kind { if items.len() == 1 { if items[0].check_name(sym::allowed) { return Some(UnwindAttr::Allowed); @@ -154,23 +154,10 @@ pub struct Stability { #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)] pub enum StabilityLevel { // Reason for the current stability level and the relevant rust-lang issue - Unstable { reason: Option, issue: u32 }, + Unstable { reason: Option, issue: u32, is_soft: bool }, Stable { since: Symbol }, } -impl Stability { - pub fn unstable(feature: Symbol, reason: Option, issue: u32) -> Stability { - Stability { - level: StabilityLevel::Unstable { reason, issue }, - feature, - rustc_depr: None, - const_stability: None, - promotable: false, - allow_const_fn_ptr: false, - } - } -} - impl StabilityLevel { pub fn is_unstable(&self) -> bool { if let StabilityLevel::Unstable {..} = *self { @@ -252,7 +239,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, allow_const_fn_ptr = true; } // attributes with data - else if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta { + else if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta { let meta = meta.as_ref().unwrap(); let get = |meta: &MetaItem, item: &mut Option| { if item.is_some() { @@ -356,19 +343,27 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, let mut feature = None; let mut reason = None; let mut issue = None; + let mut is_soft = false; for meta in metas { if let Some(mi) = meta.meta_item() { match mi.name_or_empty() { sym::feature => if !get(mi, &mut feature) { continue 'outer }, sym::reason => if !get(mi, &mut reason) { continue 'outer }, sym::issue => if !get(mi, &mut issue) { continue 'outer }, + sym::soft => { + if !mi.is_word() { + let msg = "`soft` should not have any arguments"; + sess.span_diagnostic.span_err(mi.span, msg); + } + is_soft = true; + } _ => { handle_errors( sess, meta.span(), AttrError::UnknownMetaItem( mi.path.to_string(), - &["feature", "reason", "issue"] + &["feature", "reason", "issue", "soft"] ), ); continue 'outer @@ -400,7 +395,8 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, "incorrect 'issue'"); continue } - } + }, + is_soft, }, feature, rustc_depr: None, @@ -538,17 +534,17 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat if cfg.path.segments.len() != 1 { return error(cfg.path.span, "`cfg` predicate key must be an identifier"); } - match &cfg.node { + match &cfg.kind { MetaItemKind::List(..) => { error(cfg.span, "unexpected parentheses after `cfg` predicate key") } - MetaItemKind::NameValue(lit) if !lit.node.is_str() => { + MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { handle_errors( sess, lit.span, AttrError::UnsupportedLiteral( "literal in `cfg` predicate value must be a string", - lit.node.is_bytestr() + lit.kind.is_bytestr() ), ); true @@ -567,7 +563,7 @@ pub fn eval_condition(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F) -> bool where F: FnMut(&ast::MetaItem) -> bool { - match cfg.node { + match cfg.kind { ast::MetaItemKind::List(ref mis) => { for mi in mis.iter() { if !mi.is_meta_item() { @@ -646,7 +642,7 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess, } let meta = attr.meta().unwrap(); - depr = match &meta.node { + depr = match &meta.kind { MetaItemKind::Word => Some(Deprecation { since: None, note: None }), MetaItemKind::NameValue(..) => { meta.value_str().map(|note| { @@ -672,7 +668,7 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess, AttrError::UnsupportedLiteral( "literal in `deprecated` \ value must be a string", - lit.node.is_bytestr() + lit.kind.is_bytestr() ), ); } else { @@ -815,14 +811,14 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { let mut literal_error = None; if name == sym::align { recognised = true; - match parse_alignment(&value.node) { + match parse_alignment(&value.kind) { Ok(literal) => acc.push(ReprAlign(literal)), Err(message) => literal_error = Some(message) }; } else if name == sym::packed { recognised = true; - match parse_alignment(&value.node) { + match parse_alignment(&value.kind) { Ok(literal) => acc.push(ReprPacked(literal)), Err(message) => literal_error = Some(message) }; @@ -834,11 +830,11 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { } else { if let Some(meta_item) = item.meta_item() { if meta_item.check_name(sym::align) { - if let MetaItemKind::NameValue(ref value) = meta_item.node { + if let MetaItemKind::NameValue(ref value) = meta_item.kind { recognised = true; let mut err = struct_span_err!(diagnostic, item.span(), E0693, "incorrect `repr(align)` attribute format"); - match value.node { + match value.kind { ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { err.span_suggestion( item.span(), @@ -945,7 +941,7 @@ crate fn check_builtin_attribute( name == sym::test || name == sym::bench; match attr.parse_meta(sess) { - Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) { + Ok(meta) => if !should_skip(name) && !template.compatible(&meta.kind) { let error_msg = format!("malformed `{}` attribute input", name); let mut msg = "attribute must be of the form ".to_owned(); let mut suggestions = vec![]; diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index a9d3227b3a8f4..7bef693a5be4c 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -1,4 +1,4 @@ -//! Functions dealing with attributes and meta items +//! Functions dealing with attributes and meta items. mod builtin; @@ -9,14 +9,14 @@ pub use StabilityLevel::*; pub use crate::ast::Attribute; use crate::ast; -use crate::ast::{AttrId, AttrStyle, Name, Ident, Path, PathSegment}; +use crate::ast::{AttrItem, AttrId, AttrStyle, Name, Ident, Path, PathSegment}; use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam}; use crate::mut_visit::visit_clobber; -use crate::source_map::{BytePos, Spanned, dummy_spanned}; +use crate::source_map::{BytePos, Spanned, DUMMY_SP}; use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use crate::parse::parser::Parser; -use crate::parse::{self, ParseSess, PResult}; +use crate::parse::{ParseSess, PResult}; use crate::parse::token::{self, Token}; use crate::ptr::P; use crate::symbol::{sym, Symbol}; @@ -25,7 +25,7 @@ use crate::tokenstream::{TokenStream, TokenTree, DelimSpan}; use crate::GLOBALS; use log::debug; -use syntax_pos::{FileName, Span}; +use syntax_pos::Span; use std::iter; use std::ops::DerefMut; @@ -61,7 +61,7 @@ pub fn is_known_lint_tool(m_item: Ident) -> bool { } impl NestedMetaItem { - /// Returns the MetaItem if self is a NestedMetaItem::MetaItem. + /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`. pub fn meta_item(&self) -> Option<&MetaItem> { match *self { NestedMetaItem::MetaItem(ref item) => Some(item), @@ -69,7 +69,7 @@ impl NestedMetaItem { } } - /// Returns the Lit if self is a NestedMetaItem::Literal. + /// Returns the `Lit` if `self` is a `NestedMetaItem::Literal`s. pub fn literal(&self) -> Option<&Lit> { match *self { NestedMetaItem::Literal(ref lit) => Some(lit), @@ -82,7 +82,7 @@ impl NestedMetaItem { self.meta_item().map_or(false, |meta_item| meta_item.check_name(name)) } - /// For a single-segment meta-item returns its name, otherwise returns `None`. + /// For a single-segment meta item, returns its name; otherwise, returns `None`. pub fn ident(&self) -> Option { self.meta_item().and_then(|meta_item| meta_item.ident()) } @@ -90,13 +90,13 @@ impl NestedMetaItem { self.ident().unwrap_or(Ident::invalid()).name } - /// Gets the string value if self is a MetaItem and the MetaItem is a - /// MetaItemKind::NameValue variant containing a string, otherwise None. + /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a + /// `MetaItemKind::NameValue` variant containing a string, otherwise `None`. pub fn value_str(&self) -> Option { self.meta_item().and_then(|meta_item| meta_item.value_str()) } - /// Returns a name and single literal value tuple of the MetaItem. + /// Returns a name and single literal value tuple of the `MetaItem`. pub fn name_value_literal(&self) -> Option<(Name, &Lit)> { self.meta_item().and_then( |meta_item| meta_item.meta_item_list().and_then( @@ -112,32 +112,32 @@ impl NestedMetaItem { })) } - /// Gets a list of inner meta items from a list MetaItem type. + /// Gets a list of inner meta items from a list `MetaItem` type. pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { self.meta_item().and_then(|meta_item| meta_item.meta_item_list()) } - /// Returns `true` if the variant is MetaItem. + /// Returns `true` if the variant is `MetaItem`. pub fn is_meta_item(&self) -> bool { self.meta_item().is_some() } - /// Returns `true` if the variant is Literal. + /// Returns `true` if the variant is `Literal`. pub fn is_literal(&self) -> bool { self.literal().is_some() } - /// Returns `true` if self is a MetaItem and the meta item is a word. + /// Returns `true` if `self` is a `MetaItem` and the meta item is a word. pub fn is_word(&self) -> bool { self.meta_item().map_or(false, |meta_item| meta_item.is_word()) } - /// Returns `true` if self is a MetaItem and the meta item is a ValueString. + /// Returns `true` if `self` is a `MetaItem` and the meta item is a `ValueString`. pub fn is_value_str(&self) -> bool { self.value_str().is_some() } - /// Returns `true` if self is a MetaItem and the meta item is a list. + /// Returns `true` if `self` is a `MetaItem` and the meta item is a list. pub fn is_meta_item_list(&self) -> bool { self.meta_item_list().is_some() } @@ -156,7 +156,7 @@ impl Attribute { matches } - /// For a single-segment attribute returns its name, otherwise returns `None`. + /// For a single-segment attribute, returns its name; otherwise, returns `None`. pub fn ident(&self) -> Option { if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) @@ -174,7 +174,7 @@ impl Attribute { pub fn meta_item_list(&self) -> Option> { match self.meta() { - Some(MetaItem { node: MetaItemKind::List(list), .. }) => Some(list), + Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list), _ => None } } @@ -187,14 +187,14 @@ impl Attribute { self.meta_item_list().is_some() } - /// Indicates if the attribute is a Value String. + /// Indicates if the attribute is a `ValueString`. pub fn is_value_str(&self) -> bool { self.value_str().is_some() } } impl MetaItem { - /// For a single-segment meta-item returns its name, otherwise returns `None`. + /// For a single-segment meta item, returns its name; otherwise, returns `None`. pub fn ident(&self) -> Option { if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) @@ -206,19 +206,20 @@ impl MetaItem { self.ident().unwrap_or(Ident::invalid()).name } - // #[attribute(name = "value")] - // ^^^^^^^^^^^^^^ + // Example: + // #[attribute(name = "value")] + // ^^^^^^^^^^^^^^ pub fn name_value_literal(&self) -> Option<&Lit> { - match &self.node { + match &self.kind { MetaItemKind::NameValue(v) => Some(v), _ => None, } } pub fn value_str(&self) -> Option { - match self.node { + match self.kind { MetaItemKind::NameValue(ref v) => { - match v.node { + match v.kind { LitKind::Str(ref s, _) => Some(*s), _ => None, } @@ -228,14 +229,14 @@ impl MetaItem { } pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { - match self.node { + match self.kind { MetaItemKind::List(ref l) => Some(&l[..]), _ => None } } pub fn is_word(&self) -> bool { - match self.node { + match self.kind { MetaItemKind::Word => true, _ => false, } @@ -254,23 +255,29 @@ impl MetaItem { } } -impl Attribute { - /// Extracts the MetaItem from inside this Attribute. - pub fn meta(&self) -> Option { +impl AttrItem { + crate fn meta(&self, span: Span) -> Option { let mut tokens = self.tokens.trees().peekable(); Some(MetaItem { path: self.path.clone(), - node: if let Some(node) = MetaItemKind::from_tokens(&mut tokens) { + kind: if let Some(kind) = MetaItemKind::from_tokens(&mut tokens) { if tokens.peek().is_some() { return None; } - node + kind } else { return None; }, - span: self.span, + span, }) } +} + +impl Attribute { + /// Extracts the MetaItem from inside this Attribute. + pub fn meta(&self) -> Option { + self.item.meta(self.span) + } pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T> where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, @@ -313,13 +320,13 @@ impl Attribute { pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { Ok(MetaItem { path: self.path.clone(), - node: self.parse(sess, |parser| parser.parse_meta_item_kind())?, + kind: self.parse(sess, |parser| parser.parse_meta_item_kind())?, span: self.span, }) } - /// Converts self to a normal #[doc="foo"] comment, if it is a - /// comment like `///` or `/** */`. (Returns self unchanged for + /// Converts `self` to a normal `#[doc="foo"]` comment, if it is a + /// comment like `///` or `/** */`. (Returns `self` unchanged for /// non-sugared doc attributes.) pub fn with_desugared_doc(&self, f: F) -> T where F: FnOnce(&Attribute) -> T, @@ -327,13 +334,14 @@ impl Attribute { if self.is_sugared_doc { let comment = self.value_str().unwrap(); let meta = mk_name_value_item_str( - Ident::with_empty_ctxt(sym::doc), - dummy_spanned(Symbol::intern(&strip_doc_comment_decoration(&comment.as_str())))); + Ident::with_dummy_span(sym::doc), + Symbol::intern(&strip_doc_comment_decoration(&comment.as_str())), + DUMMY_SP, + ); f(&Attribute { + item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) }, id: self.id, style: self.style, - path: meta.path, - tokens: meta.node.tokens(meta.span), is_sugared_doc: true, span: self.span, }) @@ -345,23 +353,23 @@ impl Attribute { /* Constructors */ -pub fn mk_name_value_item_str(ident: Ident, value: Spanned) -> MetaItem { - let lit_kind = LitKind::Str(value.node, ast::StrStyle::Cooked); - mk_name_value_item(ident, lit_kind, value.span) +pub fn mk_name_value_item_str(ident: Ident, str: Symbol, str_span: Span) -> MetaItem { + let lit_kind = LitKind::Str(str, ast::StrStyle::Cooked); + mk_name_value_item(ident, lit_kind, str_span) } pub fn mk_name_value_item(ident: Ident, lit_kind: LitKind, lit_span: Span) -> MetaItem { let lit = Lit::from_lit_kind(lit_kind, lit_span); let span = ident.span.to(lit_span); - MetaItem { path: Path::from_ident(ident), span, node: MetaItemKind::NameValue(lit) } + MetaItem { path: Path::from_ident(ident), span, kind: MetaItemKind::NameValue(lit) } } pub fn mk_list_item(ident: Ident, items: Vec) -> MetaItem { - MetaItem { path: Path::from_ident(ident), span: ident.span, node: MetaItemKind::List(items) } + MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::List(items) } } pub fn mk_word_item(ident: Ident) -> MetaItem { - MetaItem { path: Path::from_ident(ident), span: ident.span, node: MetaItemKind::Word } + MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::Word } } pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem { @@ -379,28 +387,24 @@ crate fn mk_attr_id() -> AttrId { AttrId(id) } -/// Returns an inner attribute with the given value and span. -pub fn mk_attr_inner(item: MetaItem) -> Attribute { +pub fn mk_attr(style: AttrStyle, path: Path, tokens: TokenStream, span: Span) -> Attribute { Attribute { + item: AttrItem { path, tokens }, id: mk_attr_id(), - style: ast::AttrStyle::Inner, - path: item.path, - tokens: item.node.tokens(item.span), + style, is_sugared_doc: false, - span: item.span, + span, } } +/// Returns an inner attribute with the given value and span. +pub fn mk_attr_inner(item: MetaItem) -> Attribute { + mk_attr(AttrStyle::Inner, item.path, item.kind.tokens(item.span), item.span) +} + /// Returns an outer attribute with the given value and span. pub fn mk_attr_outer(item: MetaItem) -> Attribute { - Attribute { - id: mk_attr_id(), - style: ast::AttrStyle::Outer, - path: item.path, - tokens: item.node.tokens(item.span), - is_sugared_doc: false, - span: item.span, - } + mk_attr(AttrStyle::Outer, item.path, item.kind.tokens(item.span), item.span) } pub fn mk_sugared_doc_attr(text: Symbol, span: Span) -> Attribute { @@ -408,10 +412,12 @@ pub fn mk_sugared_doc_attr(text: Symbol, span: Span) -> Attribute { let lit_kind = LitKind::Str(text, ast::StrStyle::Cooked); let lit = Lit::from_lit_kind(lit_kind, span); Attribute { + item: AttrItem { + path: Path::from_ident(Ident::with_dummy_span(sym::doc).with_span_pos(span)), + tokens: MetaItemKind::NameValue(lit).tokens(span), + }, id: mk_attr_id(), style, - path: Path::from_ident(Ident::with_empty_ctxt(sym::doc).with_span_pos(span)), - tokens: MetaItemKind::NameValue(lit).tokens(span), is_sugared_doc: true, span, } @@ -433,6 +439,30 @@ pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> { attrs.iter().find(|attr| attr.check_name(name)) } +pub fn allow_internal_unstable<'a>( + attrs: &[Attribute], + span_diagnostic: &'a errors::Handler, +) -> Option + 'a> { + find_by_name(attrs, sym::allow_internal_unstable).and_then(|attr| { + attr.meta_item_list().or_else(|| { + span_diagnostic.span_err( + attr.span, + "allow_internal_unstable expects list of feature names" + ); + None + }).map(|features| features.into_iter().filter_map(move |it| { + let name = it.ident().map(|ident| ident.name); + if name.is_none() { + span_diagnostic.span_err( + it.span(), + "`allow_internal_unstable` expects feature names", + ) + } + name + })) + }) +} + pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator { attrs.iter().filter(move |attr| attr.check_name(name)) @@ -459,7 +489,7 @@ impl MetaItem { idents.push(TokenTree::Token(Token::from_ast_ident(segment.ident)).into()); last_pos = segment.ident.span.hi(); } - self.node.tokens(self.span).append_to_tree_and_joint_vec(&mut idents); + self.kind.tokens(self.span).append_to_tree_and_joint_vec(&mut idents); TokenStream::new(idents) } @@ -500,21 +530,21 @@ impl MetaItem { } Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt { token::Nonterminal::NtIdent(ident, _) => Path::from_ident(ident), - token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()), + token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span), token::Nonterminal::NtPath(ref path) => path.clone(), _ => return None, }, _ => return None, }; let list_closing_paren_pos = tokens.peek().map(|tt| tt.span().hi()); - let node = MetaItemKind::from_tokens(tokens)?; - let hi = match node { + let kind = MetaItemKind::from_tokens(tokens)?; + let hi = match kind { MetaItemKind::NameValue(ref lit) => lit.span.hi(), MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()), _ => path.span.hi(), }; let span = path.span.with_hi(hi); - Some(MetaItem { path, node, span }) + Some(MetaItem { path, kind, span }) } } @@ -678,11 +708,11 @@ impl HasAttrs for StmtKind { impl HasAttrs for Stmt { fn attrs(&self) -> &[ast::Attribute] { - self.node.attrs() + self.kind.attrs() } fn visit_attrs)>(&mut self, f: F) { - self.node.visit_attrs(f); + self.kind.visit_attrs(f); } } @@ -712,35 +742,5 @@ macro_rules! derive_has_attrs { derive_has_attrs! { Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm, - ast::Field, ast::FieldPat, ast::Variant_, ast::Arg -} - -pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate { - for raw_attr in attrs { - let mut parser = parse::new_parser_from_source_str( - parse_sess, - FileName::cli_crate_attr_source_code(&raw_attr), - raw_attr.clone(), - ); - - let start_span = parser.token.span; - let (path, tokens) = panictry!(parser.parse_meta_item_unrestricted()); - let end_span = parser.token.span; - if parser.token != token::Eof { - parse_sess.span_diagnostic - .span_err(start_span.to(end_span), "invalid crate attribute"); - continue; - } - - krate.attrs.push(Attribute { - id: mk_attr_id(), - style: AttrStyle::Inner, - path, - tokens, - is_sugared_doc: false, - span: start_span.to(end_span), - }); - } - - krate + ast::Field, ast::FieldPat, ast::Variant, ast::Param } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 1ab367f73c1b3..2923cc86ba029 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -122,8 +122,8 @@ impl<'a> StripUnconfigured<'a> { while !parser.check(&token::CloseDelim(token::Paren)) { let lo = parser.token.span.lo(); - let (path, tokens) = parser.parse_meta_item_unrestricted()?; - expanded_attrs.push((path, tokens, parser.prev_span.with_lo(lo))); + let item = parser.parse_attr_item()?; + expanded_attrs.push((item, parser.prev_span.with_lo(lo))); parser.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?; } @@ -150,11 +150,10 @@ impl<'a> StripUnconfigured<'a> { // `cfg_attr` inside of another `cfg_attr`. E.g. // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. expanded_attrs.into_iter() - .flat_map(|(path, tokens, span)| self.process_cfg_attr(ast::Attribute { + .flat_map(|(item, span)| self.process_cfg_attr(ast::Attribute { + item, id: attr::mk_attr_id(), style: attr.style, - path, - tokens, is_sugared_doc: false, span, })) @@ -260,7 +259,7 @@ impl<'a> StripUnconfigured<'a> { ast::ItemKind::Enum(ast::EnumDef { variants }, _generics) => { variants.flat_map_in_place(|variant| self.configure(variant)); for variant in variants { - self.configure_variant_data(&mut variant.node.data); + self.configure_variant_data(&mut variant.data); } } _ => {} @@ -298,7 +297,7 @@ impl<'a> StripUnconfigured<'a> { } pub fn configure_pat(&mut self, pat: &mut P) { - if let ast::PatKind::Struct(_path, fields, _etc) = &mut pat.node { + if let ast::PatKind::Struct(_path, fields, _etc) = &mut pat.kind { fields.flat_map_in_place(|field| self.configure(field)); } } @@ -321,13 +320,13 @@ impl<'a> MutVisitor for StripUnconfigured<'a> { fn visit_expr(&mut self, expr: &mut P) { self.configure_expr(expr); - self.configure_expr_kind(&mut expr.node); + self.configure_expr_kind(&mut expr.kind); noop_visit_expr(expr, self); } fn filter_map_expr(&mut self, expr: P) -> Option> { let mut expr = configure!(self, expr); - self.configure_expr_kind(&mut expr.node); + self.configure_expr_kind(&mut expr.kind); noop_visit_expr(&mut expr, self); Some(expr) } diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index b754d0833761e..c95c5bd5d02d4 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -1,13 +1,14 @@ #[macro_export] -macro_rules! register_diagnostic { - ($code:tt, $description:tt) => (__register_diagnostic! { $code, $description }); - ($code:tt) => (__register_diagnostic! { $code }) +macro_rules! diagnostic_used { + ($code:ident) => ( + let _ = crate::error_codes::$code; + ) } #[macro_export] macro_rules! span_fatal { ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ - __diagnostic_used!($code); + $crate::diagnostic_used!($code); $session.span_fatal_with_code( $span, &format!($($message)*), @@ -19,7 +20,7 @@ macro_rules! span_fatal { #[macro_export] macro_rules! span_err { ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ - __diagnostic_used!($code); + $crate::diagnostic_used!($code); $session.span_err_with_code( $span, &format!($($message)*), @@ -31,7 +32,7 @@ macro_rules! span_err { #[macro_export] macro_rules! span_warn { ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ - __diagnostic_used!($code); + $crate::diagnostic_used!($code); $session.span_warn_with_code( $span, &format!($($message)*), @@ -43,7 +44,7 @@ macro_rules! span_warn { #[macro_export] macro_rules! struct_err { ($session:expr, $code:ident, $($message:tt)*) => ({ - __diagnostic_used!($code); + $crate::diagnostic_used!($code); $session.struct_err_with_code( &format!($($message)*), $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()), @@ -54,7 +55,7 @@ macro_rules! struct_err { #[macro_export] macro_rules! span_err_or_warn { ($is_warning:expr, $session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ - __diagnostic_used!($code); + $crate::diagnostic_used!($code); if $is_warning { $session.span_warn_with_code( $span, @@ -74,7 +75,7 @@ macro_rules! span_err_or_warn { #[macro_export] macro_rules! struct_span_fatal { ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ - __diagnostic_used!($code); + $crate::diagnostic_used!($code); $session.struct_span_fatal_with_code( $span, &format!($($message)*), @@ -86,7 +87,7 @@ macro_rules! struct_span_fatal { #[macro_export] macro_rules! struct_span_err { ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ - __diagnostic_used!($code); + $crate::diagnostic_used!($code); $session.struct_span_err_with_code( $span, &format!($($message)*), @@ -98,7 +99,7 @@ macro_rules! struct_span_err { #[macro_export] macro_rules! stringify_error_code { ($code:ident) => ({ - __diagnostic_used!($code); + $crate::diagnostic_used!($code); $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()) }) } @@ -117,7 +118,7 @@ macro_rules! type_error_struct { #[macro_export] macro_rules! struct_span_warn { ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ - __diagnostic_used!($code); + $crate::diagnostic_used!($code); $session.struct_span_warn_with_code( $span, &format!($($message)*), @@ -129,7 +130,7 @@ macro_rules! struct_span_warn { #[macro_export] macro_rules! struct_span_err_or_warn { ($is_warning:expr, $session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ - __diagnostic_used!($code); + $crate::diagnostic_used!($code); if $is_warning { $session.struct_span_warn_with_code( $span, @@ -169,20 +170,22 @@ macro_rules! help { #[macro_export] macro_rules! register_diagnostics { - ($($code:tt),*) => ( - $($crate::register_diagnostic! { $code })* + ($($ecode:ident: $message:expr,)*) => ( + $crate::register_diagnostics!{$($ecode:$message,)* ;} ); - ($($code:tt),*,) => ( - $($crate::register_diagnostic! { $code })* - ) -} -#[macro_export] -macro_rules! register_long_diagnostics { - ($($code:tt: $description:tt),*) => ( - $($crate::register_diagnostic! { $code, $description })* - ); - ($($code:tt: $description:tt),*,) => ( - $($crate::register_diagnostic! { $code, $description })* + ($($ecode:ident: $message:expr,)* ; $($code:ident,)*) => ( + pub static DIAGNOSTICS: &[(&str, &str)] = &[ + $( (stringify!($ecode), $message), )* + ]; + + $( + #[deny(unused)] + pub(crate) const $ecode: &str = $message; + )* + $( + #[deny(unused)] + pub(crate) const $code: () = (); + )* ) } diff --git a/src/libsyntax/diagnostics/metadata.rs b/src/libsyntax/diagnostics/metadata.rs deleted file mode 100644 index 53f37bb10bdc0..0000000000000 --- a/src/libsyntax/diagnostics/metadata.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! This module contains utilities for outputting metadata for diagnostic errors. -//! -//! Each set of errors is mapped to a metadata file by a name, which is -//! currently always a crate name. - -use std::collections::BTreeMap; -use std::env; -use std::fs::{remove_file, create_dir_all, File}; -use std::io::Write; -use std::path::PathBuf; -use std::error::Error; -use rustc_serialize::json::as_json; - -use syntax_pos::{Span, FileName}; - -use crate::ext::base::ExtCtxt; -use crate::diagnostics::plugin::{ErrorMap, ErrorInfo}; - -/// JSON encodable/decodable version of `ErrorInfo`. -#[derive(PartialEq, RustcDecodable, RustcEncodable)] -pub struct ErrorMetadata { - pub description: Option, - pub use_site: Option -} - -/// Mapping from error codes to metadata that can be (de)serialized. -pub type ErrorMetadataMap = BTreeMap; - -/// JSON encodable error location type with filename and line number. -#[derive(PartialEq, RustcDecodable, RustcEncodable)] -pub struct ErrorLocation { - pub filename: FileName, - pub line: usize -} - -impl ErrorLocation { - /// Creates an error location from a span. - pub fn from_span(ecx: &ExtCtxt<'_>, sp: Span) -> ErrorLocation { - let loc = ecx.source_map().lookup_char_pos(sp.lo()); - ErrorLocation { - filename: loc.file.name.clone(), - line: loc.line - } - } -} - -/// Gets the directory where metadata for a given `prefix` should be stored. -/// -/// See `output_metadata`. -pub fn get_metadata_dir(prefix: &str) -> PathBuf { - env::var_os("RUSTC_ERROR_METADATA_DST") - .map(PathBuf::from) - .expect("env var `RUSTC_ERROR_METADATA_DST` isn't set") - .join(prefix) -} - -/// Map `name` to a path in the given directory: /.json -fn get_metadata_path(directory: PathBuf, name: &str) -> PathBuf { - directory.join(format!("{}.json", name)) -} - -/// Write metadata for the errors in `err_map` to disk, to a file corresponding to `prefix/name`. -/// -/// For our current purposes the prefix is the target architecture and the name is a crate name. -/// If an error occurs steps will be taken to ensure that no file is created. -pub fn output_metadata(ecx: &ExtCtxt<'_>, prefix: &str, name: &str, err_map: &ErrorMap) - -> Result<(), Box> -{ - // Create the directory to place the file in. - let metadata_dir = get_metadata_dir(prefix); - create_dir_all(&metadata_dir)?; - - // Open the metadata file. - let metadata_path = get_metadata_path(metadata_dir, name); - let mut metadata_file = File::create(&metadata_path)?; - - // Construct a serializable map. - let json_map = err_map.iter().map(|(k, &ErrorInfo { description, use_site })| { - let key = k.as_str().to_string(); - let value = ErrorMetadata { - description: description.map(|n| n.as_str().to_string()), - use_site: use_site.map(|sp| ErrorLocation::from_span(ecx, sp)) - }; - (key, value) - }).collect::(); - - // Write the data to the file, deleting it if the write fails. - let result = write!(&mut metadata_file, "{}", as_json(&json_map)); - if result.is_err() { - remove_file(&metadata_path)?; - } - Ok(result?) -} diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs deleted file mode 100644 index 80591ad304df0..0000000000000 --- a/src/libsyntax/diagnostics/plugin.rs +++ /dev/null @@ -1,211 +0,0 @@ -use std::collections::BTreeMap; -use std::env; - -use crate::ast::{self, Ident, Name}; -use crate::source_map; -use crate::ext::base::{ExtCtxt, MacEager, MacResult}; -use crate::parse::token::{self, Token}; -use crate::ptr::P; -use crate::symbol::kw; -use crate::tokenstream::{TokenTree}; - -use smallvec::smallvec; -use syntax_pos::Span; - -use crate::diagnostics::metadata::output_metadata; - -pub use errors::*; - -// Maximum width of any line in an extended error description (inclusive). -const MAX_DESCRIPTION_WIDTH: usize = 80; - -/// Error information type. -pub struct ErrorInfo { - pub description: Option, - pub use_site: Option -} - -/// Mapping from error codes to metadata. -pub type ErrorMap = BTreeMap; - -pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt<'_>, - span: Span, - token_tree: &[TokenTree]) - -> Box { - let code = match token_tree { - [ - TokenTree::Token(Token { kind: token::Ident(code, _), .. }) - ] => code, - _ => unreachable!() - }; - - ecx.parse_sess.registered_diagnostics.with_lock(|diagnostics| { - match diagnostics.get_mut(&code) { - // Previously used errors. - Some(&mut ErrorInfo { description: _, use_site: Some(previous_span) }) => { - ecx.struct_span_warn(span, &format!( - "diagnostic code {} already used", code - )).span_note(previous_span, "previous invocation") - .emit(); - } - // Newly used errors. - Some(ref mut info) => { - info.use_site = Some(span); - } - // Unregistered errors. - None => { - ecx.span_err(span, &format!( - "used diagnostic code {} not registered", code - )); - } - } - }); - MacEager::expr(ecx.expr_tuple(span, Vec::new())) -} - -pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt<'_>, - span: Span, - token_tree: &[TokenTree]) - -> Box { - let (code, description) = match token_tree { - [ - TokenTree::Token(Token { kind: token::Ident(code, _), .. }) - ] => { - (*code, None) - }, - [ - TokenTree::Token(Token { kind: token::Ident(code, _), .. }), - TokenTree::Token(Token { kind: token::Comma, .. }), - TokenTree::Token(Token { kind: token::Literal(token::Lit { symbol, .. }), ..}) - ] => { - (*code, Some(*symbol)) - }, - _ => unreachable!() - }; - - // Check that the description starts and ends with a newline and doesn't - // overflow the maximum line width. - description.map(|raw_msg| { - let msg = raw_msg.as_str(); - if !msg.starts_with("\n") || !msg.ends_with("\n") { - ecx.span_err(span, &format!( - "description for error code {} doesn't start and end with a newline", - code - )); - } - - // URLs can be unavoidably longer than the line limit, so we allow them. - // Allowed format is: `[name]: https://www.rust-lang.org/` - let is_url = |l: &str| l.starts_with("[") && l.contains("]:") && l.contains("http"); - - if msg.lines().any(|line| line.len() > MAX_DESCRIPTION_WIDTH && !is_url(line)) { - ecx.span_err(span, &format!( - "description for error code {} contains a line longer than {} characters.\n\ - if you're inserting a long URL use the footnote style to bypass this check.", - code, MAX_DESCRIPTION_WIDTH - )); - } - }); - // Add the error to the map. - ecx.parse_sess.registered_diagnostics.with_lock(|diagnostics| { - let info = ErrorInfo { - description, - use_site: None - }; - if diagnostics.insert(code, info).is_some() { - ecx.span_err(span, &format!( - "diagnostic code {} already registered", code - )); - } - }); - - MacEager::items(smallvec![]) -} - -pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt<'_>, - span: Span, - token_tree: &[TokenTree]) - -> Box { - assert_eq!(token_tree.len(), 3); - let (crate_name, ident) = match (&token_tree[0], &token_tree[2]) { - ( - // Crate name. - &TokenTree::Token(Token { kind: token::Ident(crate_name, _), .. }), - // DIAGNOSTICS ident. - &TokenTree::Token(Token { kind: token::Ident(name, _), span }) - ) => (crate_name, Ident::new(name, span)), - _ => unreachable!() - }; - - // Output error metadata to `tmp/extended-errors//.json` - if let Ok(target_triple) = env::var("CFG_COMPILER_HOST_TRIPLE") { - ecx.parse_sess.registered_diagnostics.with_lock(|diagnostics| { - if let Err(e) = output_metadata(ecx, - &target_triple, - &crate_name.as_str(), - diagnostics) { - ecx.span_bug(span, &format!( - "error writing metadata for triple `{}` and crate `{}`, error: {}, \ - cause: {:?}", - target_triple, crate_name, e.description(), e.source() - )); - } - }); - } else { - ecx.span_err(span, &format!( - "failed to write metadata for crate `{}` because $CFG_COMPILER_HOST_TRIPLE is not set", - crate_name)); - } - - // Construct the output expression. - let (count, expr) = - ecx.parse_sess.registered_diagnostics.with_lock(|diagnostics| { - let descriptions: Vec> = - diagnostics.iter().filter_map(|(&code, info)| { - info.description.map(|description| { - ecx.expr_tuple(span, vec![ - ecx.expr_str(span, code), - ecx.expr_str(span, description) - ]) - }) - }).collect(); - (descriptions.len(), ecx.expr_vec(span, descriptions)) - }); - - let static_ = ecx.lifetime(span, Ident::with_empty_ctxt(kw::StaticLifetime)); - let ty_str = ecx.ty_rptr( - span, - ecx.ty_ident(span, ecx.ident_of("str")), - Some(static_), - ast::Mutability::Immutable, - ); - - let ty = ecx.ty( - span, - ast::TyKind::Array( - ecx.ty( - span, - ast::TyKind::Tup(vec![ty_str.clone(), ty_str]) - ), - ast::AnonConst { - id: ast::DUMMY_NODE_ID, - value: ecx.expr_usize(span, count), - }, - ), - ); - - MacEager::items(smallvec![ - P(ast::Item { - ident, - attrs: Vec::new(), - id: ast::DUMMY_NODE_ID, - node: ast::ItemKind::Const( - ty, - expr, - ), - vis: source_map::respan(span.shrink_to_lo(), ast::VisibilityKind::Public), - span, - tokens: None, - }) - ]) -} diff --git a/src/libsyntax/early_buffered_lints.rs b/src/libsyntax/early_buffered_lints.rs index 36c1da2929975..5cc953b906628 100644 --- a/src/libsyntax/early_buffered_lints.rs +++ b/src/libsyntax/early_buffered_lints.rs @@ -11,6 +11,7 @@ use syntax_pos::MultiSpan; pub enum BufferedEarlyLintId { IllFormedAttributeInput, MetaVariableMisuse, + IncompleteInclude, } /// Stores buffered lint info which can later be passed to `librustc`. diff --git a/src/libsyntax/entry.rs b/src/libsyntax/entry.rs index 0b6cf30bd27d2..34b5b1e5b5c84 100644 --- a/src/libsyntax/entry.rs +++ b/src/libsyntax/entry.rs @@ -13,7 +13,7 @@ pub enum EntryPointType { // Beware, this is duplicated in librustc/middle/entry.rs, make sure to keep // them in sync. pub fn entry_point_type(item: &Item, depth: usize) -> EntryPointType { - match item.node { + match item.kind { ItemKind::Fn(..) => { if attr::contains_name(&item.attrs, sym::start) { EntryPointType::Start diff --git a/src/libsyntax/error_codes.rs b/src/libsyntax/error_codes.rs index 1ba29011f75a4..fc3f095856a80 100644 --- a/src/libsyntax/error_codes.rs +++ b/src/libsyntax/error_codes.rs @@ -1,7 +1,8 @@ // Error messages for EXXXX errors. -// Each message should start and end with a new line, and be wrapped to 80 characters. -// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable. -register_long_diagnostics! { +// Each message should start and end with a new line, and be wrapped to 80 +// characters. In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use +// `:set tw=0` to disable. +register_diagnostics! { E0178: r##" In types, the `+` type operator has low precedence, so it is often necessary @@ -143,6 +144,44 @@ fn deprecated_function() {} ``` "##, +E0550: r##" +More than one `deprecated` attribute has been put on an item. + +Erroneous code example: + +```compile_fail,E0550 +#[deprecated(note = "because why not?")] +#[deprecated(note = "right?")] // error! +fn the_banished() {} +``` + +The `deprecated` attribute can only be present **once** on an item. + +``` +#[deprecated(note = "because why not, right?")] +fn the_banished() {} // ok! +``` +"##, + +E0551: r##" +An invalid meta-item was used inside an attribute. + +Erroneous code example: + +```compile_fail,E0551 +#[deprecated(note)] // error! +fn i_am_deprecated() {} +``` + +Meta items are the key-value pairs inside of an attribute. To fix this issue, +you need to give a value to the `note` key. Example: + +``` +#[deprecated(note = "because")] // ok! +fn i_am_deprecated() {} +``` +"##, + E0552: r##" A unrecognized representation attribute was used. @@ -188,6 +227,25 @@ If you need the feature, make sure to use a nightly release of the compiler (but be warned that the feature may be removed or altered in the future). "##, +E0556: r##" +The `feature` attribute was badly formed. + +Erroneous code example: + +```compile_fail,E0556 +#![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] // error! +#![feature] // error! +#![feature = "foo"] // error! +``` + +The `feature` attribute only accept a "feature flag" and can only be used on +nightly. Example: + +```ignore (only works in nightly) +#![feature(flag)] +``` +"##, + E0557: r##" A feature attribute named a feature that has been removed. @@ -420,9 +478,8 @@ Delete the offending feature attribute, or add it to the list of allowed features in the `-Z allow_features` flag. "##, -} +; -register_diagnostics! { E0539, // incorrect meta item E0540, // multiple rustc_deprecated attributes E0542, // missing 'since' @@ -432,17 +489,18 @@ register_diagnostics! { E0546, // missing 'feature' E0547, // missing 'issue' // E0548, // replaced with a generic attribute input check - E0549, // rustc_deprecated attribute must be paired with either stable or unstable attribute - E0550, // multiple deprecated attributes - E0551, // incorrect meta item + // rustc_deprecated attribute must be paired with either stable or unstable + // attribute + E0549, E0553, // multiple rustc_const_unstable attributes // E0555, // replaced with a generic attribute input check - E0556, // malformed feature, expected just one word E0584, // file for module `..` found at both .. and .. E0629, // missing 'feature' (rustc_const_unstable) - E0630, // rustc_const_unstable attribute must be paired with stable/unstable attribute + // rustc_const_unstable attribute must be paired with stable/unstable + // attribute + E0630, E0693, // incorrect `repr(align)` attribute format - E0694, // an unknown tool name found in scoped attributes +// E0694, // an unknown tool name found in scoped attributes E0703, // invalid ABI E0717, // rustc_promotable without stability attribute } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index d69822c7c7f1a..583fb3f770183 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -1,21 +1,22 @@ -use crate::ast::{self, Attribute, Name, PatKind}; -use crate::attr::{HasAttrs, Stability, Deprecation}; -use crate::source_map::{SourceMap, Spanned, respan}; +use crate::ast::{self, NodeId, Attribute, Name, PatKind}; +use crate::attr::{self, HasAttrs, Stability, Deprecation}; +use crate::source_map::SourceMap; use crate::edition::Edition; use crate::ext::expand::{self, AstFragment, Invocation}; -use crate::ext::hygiene::{ExpnId, SyntaxContext, Transparency}; +use crate::ext::hygiene::ExpnId; use crate::mut_visit::{self, MutVisitor}; -use crate::parse::{self, parser, DirectoryOwnership}; +use crate::parse::{self, parser, ParseSess, DirectoryOwnership}; use crate::parse::token; use crate::ptr::P; use crate::symbol::{kw, sym, Ident, Symbol}; use crate::{ThinVec, MACRO_ARGUMENTS}; -use crate::tokenstream::{self, TokenStream, TokenTree}; +use crate::tokenstream::{self, TokenStream}; +use crate::visit::Visitor; use errors::{DiagnosticBuilder, DiagnosticId}; use smallvec::{smallvec, SmallVec}; use syntax_pos::{FileName, Span, MultiSpan, DUMMY_SP}; -use syntax_pos::hygiene::{ExpnInfo, ExpnKind}; +use syntax_pos::hygiene::{AstPass, ExpnData, ExpnKind}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{self, Lrc}; @@ -34,6 +35,13 @@ pub enum Annotatable { ForeignItem(P), Stmt(P), Expr(P), + Arm(ast::Arm), + Field(ast::Field), + FieldPat(ast::FieldPat), + GenericParam(ast::GenericParam), + Param(ast::Param), + StructField(ast::StructField), + Variant(ast::Variant), } impl HasAttrs for Annotatable { @@ -45,6 +53,13 @@ impl HasAttrs for Annotatable { Annotatable::ForeignItem(ref foreign_item) => &foreign_item.attrs, Annotatable::Stmt(ref stmt) => stmt.attrs(), Annotatable::Expr(ref expr) => &expr.attrs, + Annotatable::Arm(ref arm) => &arm.attrs, + Annotatable::Field(ref field) => &field.attrs, + Annotatable::FieldPat(ref fp) => &fp.attrs, + Annotatable::GenericParam(ref gp) => &gp.attrs, + Annotatable::Param(ref p) => &p.attrs, + Annotatable::StructField(ref sf) => &sf.attrs, + Annotatable::Variant(ref v) => &v.attrs(), } } @@ -56,6 +71,13 @@ impl HasAttrs for Annotatable { Annotatable::ForeignItem(foreign_item) => foreign_item.visit_attrs(f), Annotatable::Stmt(stmt) => stmt.visit_attrs(f), Annotatable::Expr(expr) => expr.visit_attrs(f), + Annotatable::Arm(arm) => arm.visit_attrs(f), + Annotatable::Field(field) => field.visit_attrs(f), + Annotatable::FieldPat(fp) => fp.visit_attrs(f), + Annotatable::GenericParam(gp) => gp.visit_attrs(f), + Annotatable::Param(p) => p.visit_attrs(f), + Annotatable::StructField(sf) => sf.visit_attrs(f), + Annotatable::Variant(v) => v.visit_attrs(f), } } } @@ -69,6 +91,31 @@ impl Annotatable { Annotatable::ForeignItem(ref foreign_item) => foreign_item.span, Annotatable::Stmt(ref stmt) => stmt.span, Annotatable::Expr(ref expr) => expr.span, + Annotatable::Arm(ref arm) => arm.span, + Annotatable::Field(ref field) => field.span, + Annotatable::FieldPat(ref fp) => fp.pat.span, + Annotatable::GenericParam(ref gp) => gp.ident.span, + Annotatable::Param(ref p) => p.span, + Annotatable::StructField(ref sf) => sf.span, + Annotatable::Variant(ref v) => v.span, + } + } + + pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) { + match self { + Annotatable::Item(item) => visitor.visit_item(item), + Annotatable::TraitItem(trait_item) => visitor.visit_trait_item(trait_item), + Annotatable::ImplItem(impl_item) => visitor.visit_impl_item(impl_item), + Annotatable::ForeignItem(foreign_item) => visitor.visit_foreign_item(foreign_item), + Annotatable::Stmt(stmt) => visitor.visit_stmt(stmt), + Annotatable::Expr(expr) => visitor.visit_expr(expr), + Annotatable::Arm(arm) => visitor.visit_arm(arm), + Annotatable::Field(field) => visitor.visit_field(field), + Annotatable::FieldPat(fp) => visitor.visit_field_pattern(fp), + Annotatable::GenericParam(gp) => visitor.visit_generic_param(gp), + Annotatable::Param(p) => visitor.visit_param(p), + Annotatable::StructField(sf) =>visitor.visit_struct_field(sf), + Annotatable::Variant(v) => visitor.visit_variant(v), } } @@ -124,9 +171,58 @@ impl Annotatable { } } + pub fn expect_arm(self) -> ast::Arm { + match self { + Annotatable::Arm(arm) => arm, + _ => panic!("expected match arm") + } + } + + pub fn expect_field(self) -> ast::Field { + match self { + Annotatable::Field(field) => field, + _ => panic!("expected field") + } + } + + pub fn expect_field_pattern(self) -> ast::FieldPat { + match self { + Annotatable::FieldPat(fp) => fp, + _ => panic!("expected field pattern") + } + } + + pub fn expect_generic_param(self) -> ast::GenericParam { + match self { + Annotatable::GenericParam(gp) => gp, + _ => panic!("expected generic parameter") + } + } + + pub fn expect_param(self) -> ast::Param { + match self { + Annotatable::Param(param) => param, + _ => panic!("expected parameter") + } + } + + pub fn expect_struct_field(self) -> ast::StructField { + match self { + Annotatable::StructField(sf) => sf, + _ => panic!("expected struct field") + } + } + + pub fn expect_variant(self) -> ast::Variant { + match self { + Annotatable::Variant(v) => v, + _ => panic!("expected variant") + } + } + pub fn derive_allowed(&self) -> bool { match *self { - Annotatable::Item(ref item) => match item.node { + Annotatable::Item(ref item) => match item.kind { ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) => true, @@ -223,18 +319,18 @@ pub trait TTMacroExpander { } pub type MacroExpanderFn = - for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, &[tokenstream::TokenTree]) + for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) -> Box; impl TTMacroExpander for F - where F: for<'cx> Fn(&'cx mut ExtCtxt<'_>, Span, &[tokenstream::TokenTree]) + where F: for<'cx> Fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) -> Box { fn expand<'cx>( &self, ecx: &'cx mut ExtCtxt<'_>, span: Span, - input: TokenStream, + mut input: TokenStream, ) -> Box { struct AvoidInterpolatedIdents; @@ -256,10 +352,8 @@ impl TTMacroExpander for F mut_visit::noop_visit_mac(mac, self) } } - - let input: Vec<_> = - input.trees().map(|mut tt| { AvoidInterpolatedIdents.visit_tt(&mut tt); tt }).collect(); - (*self)(ecx, span, &input) + AvoidInterpolatedIdents.visit_tts(&mut input); + (*self)(ecx, span, input) } } @@ -269,7 +363,7 @@ macro_rules! make_stmts_default { $me.make_expr().map(|e| smallvec![ast::Stmt { id: ast::DUMMY_NODE_ID, span: e.span, - node: ast::StmtKind::Expr(e), + kind: ast::StmtKind::Expr(e), }]) } } @@ -315,6 +409,34 @@ pub trait MacResult { fn make_ty(self: Box) -> Option> { None } + + fn make_arms(self: Box) -> Option> { + None + } + + fn make_fields(self: Box) -> Option> { + None + } + + fn make_field_patterns(self: Box) -> Option> { + None + } + + fn make_generic_params(self: Box) -> Option> { + None + } + + fn make_params(self: Box) -> Option> { + None + } + + fn make_struct_fields(self: Box) -> Option> { + None + } + + fn make_variants(self: Box) -> Option> { + None + } } macro_rules! make_MacEager { @@ -385,11 +507,11 @@ impl MacResult for MacEager { return Some(p); } if let Some(e) = self.expr { - if let ast::ExprKind::Lit(_) = e.node { + if let ast::ExprKind::Lit(_) = e.kind { return Some(P(ast::Pat { id: ast::DUMMY_NODE_ID, span: e.span, - node: PatKind::Lit(e), + kind: PatKind::Lit(e), })); } } @@ -405,7 +527,6 @@ impl MacResult for MacEager { /// after hitting errors. #[derive(Copy, Clone)] pub struct DummyResult { - expr_only: bool, is_error: bool, span: Span, } @@ -416,28 +537,19 @@ impl DummyResult { /// Use this as a return value after hitting any errors and /// calling `span_err`. pub fn any(span: Span) -> Box { - Box::new(DummyResult { expr_only: false, is_error: true, span }) + Box::new(DummyResult { is_error: true, span }) } /// Same as `any`, but must be a valid fragment, not error. pub fn any_valid(span: Span) -> Box { - Box::new(DummyResult { expr_only: false, is_error: false, span }) - } - - /// Creates a default MacResult that can only be an expression. - /// - /// Use this for macros that must expand to an expression, so even - /// if an error is encountered internally, the user will receive - /// an error that they also used it in the wrong place. - pub fn expr(span: Span) -> Box { - Box::new(DummyResult { expr_only: true, is_error: true, span }) + Box::new(DummyResult { is_error: false, span }) } /// A plain dummy expression. pub fn raw_expr(sp: Span, is_error: bool) -> P { P(ast::Expr { id: ast::DUMMY_NODE_ID, - node: if is_error { ast::ExprKind::Err } else { ast::ExprKind::Tup(Vec::new()) }, + kind: if is_error { ast::ExprKind::Err } else { ast::ExprKind::Tup(Vec::new()) }, span: sp, attrs: ThinVec::new(), }) @@ -447,7 +559,7 @@ impl DummyResult { pub fn raw_pat(sp: Span) -> ast::Pat { ast::Pat { id: ast::DUMMY_NODE_ID, - node: PatKind::Wild, + kind: PatKind::Wild, span: sp, } } @@ -456,7 +568,7 @@ impl DummyResult { pub fn raw_ty(sp: Span, is_error: bool) -> P { P(ast::Ty { id: ast::DUMMY_NODE_ID, - node: if is_error { ast::TyKind::Err } else { ast::TyKind::Tup(Vec::new()) }, + kind: if is_error { ast::TyKind::Err } else { ast::TyKind::Tup(Vec::new()) }, span: sp }) } @@ -472,42 +584,25 @@ impl MacResult for DummyResult { } fn make_items(self: Box) -> Option; 1]>> { - // this code needs a comment... why not always just return the Some() ? - if self.expr_only { - None - } else { - Some(SmallVec::new()) - } + Some(SmallVec::new()) } fn make_impl_items(self: Box) -> Option> { - if self.expr_only { - None - } else { - Some(SmallVec::new()) - } + Some(SmallVec::new()) } fn make_trait_items(self: Box) -> Option> { - if self.expr_only { - None - } else { - Some(SmallVec::new()) - } + Some(SmallVec::new()) } fn make_foreign_items(self: Box) -> Option> { - if self.expr_only { - None - } else { - Some(SmallVec::new()) - } + Some(SmallVec::new()) } fn make_stmts(self: Box) -> Option> { Some(smallvec![ast::Stmt { id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Expr(DummyResult::raw_expr(self.span, self.is_error)), + kind: ast::StmtKind::Expr(DummyResult::raw_expr(self.span, self.is_error)), span: self.span, }]) } @@ -515,6 +610,34 @@ impl MacResult for DummyResult { fn make_ty(self: Box) -> Option> { Some(DummyResult::raw_ty(self.span, self.is_error)) } + + fn make_arms(self: Box) -> Option> { + Some(SmallVec::new()) + } + + fn make_fields(self: Box) -> Option> { + Some(SmallVec::new()) + } + + fn make_field_patterns(self: Box) -> Option> { + Some(SmallVec::new()) + } + + fn make_generic_params(self: Box) -> Option> { + Some(SmallVec::new()) + } + + fn make_params(self: Box) -> Option> { + Some(SmallVec::new()) + } + + fn make_struct_fields(self: Box) -> Option> { + Some(SmallVec::new()) + } + + fn make_variants(self: Box) -> Option> { + Some(SmallVec::new()) + } } /// A syntax extension kind. @@ -576,8 +699,6 @@ pub struct SyntaxExtension { pub kind: SyntaxExtensionKind, /// Span of the macro definition. pub span: Span, - /// Hygienic properties of spans produced by this macro by default. - pub default_transparency: Transparency, /// Whitelist of unstable features that are treated as stable inside this macro. pub allow_internal_unstable: Option>, /// Suppresses the `unsafe_code` lint for code produced by this macro. @@ -592,29 +713,13 @@ pub struct SyntaxExtension { pub helper_attrs: Vec, /// Edition of the crate in which this macro is defined. pub edition: Edition, - /// Built-in macros have a couple of special properties (meaning of `$crate`, - /// availability in `#[no_implicit_prelude]` modules), so we have to keep this flag. + /// Built-in macros have a couple of special properties like availability + /// in `#[no_implicit_prelude]` modules, so we have to keep this flag. pub is_builtin: bool, /// We have to identify macros providing a `Copy` impl early for compatibility reasons. pub is_derive_copy: bool, } -impl SyntaxExtensionKind { - /// When a syntax extension is constructed, - /// its transparency can often be inferred from its kind. - fn default_transparency(&self) -> Transparency { - match self { - SyntaxExtensionKind::Bang(..) | - SyntaxExtensionKind::Attr(..) | - SyntaxExtensionKind::Derive(..) | - SyntaxExtensionKind::NonMacroAttr { .. } => Transparency::Opaque, - SyntaxExtensionKind::LegacyBang(..) | - SyntaxExtensionKind::LegacyAttr(..) | - SyntaxExtensionKind::LegacyDerive(..) => Transparency::SemiTransparent, - } - } -} - impl SyntaxExtension { /// Returns which kind of macro calls this syntax extension. pub fn macro_kind(&self) -> MacroKind { @@ -633,7 +738,6 @@ impl SyntaxExtension { pub fn default(kind: SyntaxExtensionKind, edition: Edition) -> SyntaxExtension { SyntaxExtension { span: DUMMY_SP, - default_transparency: kind.default_transparency(), allow_internal_unstable: None, allow_internal_unsafe: false, local_inner_macros: false, @@ -647,8 +751,47 @@ impl SyntaxExtension { } } + /// Constructs a syntax extension with the given properties + /// and other properties converted from attributes. + pub fn new( + sess: &ParseSess, + kind: SyntaxExtensionKind, + span: Span, + helper_attrs: Vec, + edition: Edition, + name: Name, + attrs: &[ast::Attribute], + ) -> SyntaxExtension { + let allow_internal_unstable = attr::allow_internal_unstable( + &attrs, &sess.span_diagnostic, + ).map(|features| features.collect::>().into()); + + let mut local_inner_macros = false; + if let Some(macro_export) = attr::find_by_name(attrs, sym::macro_export) { + if let Some(l) = macro_export.meta_item_list() { + local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros); + } + } + + let is_builtin = attr::contains_name(attrs, sym::rustc_builtin_macro); + + SyntaxExtension { + kind, + span, + allow_internal_unstable, + allow_internal_unsafe: attr::contains_name(attrs, sym::allow_internal_unsafe), + local_inner_macros, + stability: attr::find_stability(&sess, attrs, span), + deprecation: attr::find_deprecation(&sess, attrs, span), + helper_attrs, + edition, + is_builtin, + is_derive_copy: is_builtin && name == sym::Copy, + } + } + pub fn dummy_bang(edition: Edition) -> SyntaxExtension { - fn expander<'cx>(_: &'cx mut ExtCtxt<'_>, span: Span, _: &[TokenTree]) + fn expander<'cx>(_: &'cx mut ExtCtxt<'_>, span: Span, _: TokenStream) -> Box { DummyResult::any(span) } @@ -667,12 +810,12 @@ impl SyntaxExtension { SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr { mark_used }, edition) } - pub fn expn_info(&self, call_site: Span, descr: Symbol) -> ExpnInfo { - ExpnInfo { - call_site, + pub fn expn_data(&self, parent: ExpnId, call_site: Span, descr: Symbol) -> ExpnData { + ExpnData { kind: ExpnKind::Macro(self.macro_kind(), descr), + parent, + call_site, def_site: self.span, - default_transparency: self.default_transparency, allow_internal_unstable: self.allow_internal_unstable.clone(), allow_internal_unsafe: self.allow_internal_unsafe, local_inner_macros: self.local_inner_macros, @@ -683,6 +826,12 @@ impl SyntaxExtension { pub type NamedSyntaxExtension = (Name, SyntaxExtension); +/// Result of resolving a macro invocation. +pub enum InvocationRes { + Single(Lrc), + DeriveContainer(Vec>), +} + /// Error type that denotes indeterminacy. pub struct Indeterminate; @@ -697,19 +846,26 @@ bitflags::bitflags! { } pub trait Resolver { - fn next_node_id(&mut self) -> ast::NodeId; - - fn get_module_scope(&mut self, id: ast::NodeId) -> ExpnId; + fn next_node_id(&mut self) -> NodeId; fn resolve_dollar_crates(&mut self); fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment, - derives: &[ExpnId]); + extra_placeholders: &[NodeId]); fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension); + fn expansion_for_ast_pass( + &mut self, + call_site: Span, + pass: AstPass, + features: &[Symbol], + parent_module_id: Option, + ) -> ExpnId; + fn resolve_imports(&mut self); - fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: ExpnId, force: bool) - -> Result>, Indeterminate>; + fn resolve_macro_invocation( + &mut self, invoc: &Invocation, eager_expansion_root: ExpnId, force: bool + ) -> Result; fn check_unused_macros(&self); @@ -734,7 +890,7 @@ pub struct ExpansionData { /// One of these is made during expansion and incrementally updated as we go; /// when a macro expansion occurs, the resulting nodes have the `backtrace() -/// -> expn_info` of their expansion context stored into their span. +/// -> expn_data` of their expansion context stored into their span. pub struct ExtCtxt<'a> { pub parse_sess: &'a parse::ParseSess, pub ecfg: expand::ExpansionConfig<'a>, @@ -775,41 +931,48 @@ impl<'a> ExtCtxt<'a> { pub fn monotonic_expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> { expand::MacroExpander::new(self, true) } - - pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree]) -> parser::Parser<'a> { - parse::stream_to_parser(self.parse_sess, tts.iter().cloned().collect(), MACRO_ARGUMENTS) + pub fn new_parser_from_tts(&self, stream: TokenStream) -> parser::Parser<'a> { + parse::stream_to_parser(self.parse_sess, stream, MACRO_ARGUMENTS) } pub fn source_map(&self) -> &'a SourceMap { self.parse_sess.source_map() } pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess } pub fn cfg(&self) -> &ast::CrateConfig { &self.parse_sess.config } pub fn call_site(&self) -> Span { - match self.current_expansion.id.expn_info() { - Some(expn_info) => expn_info.call_site, - None => DUMMY_SP, - } + self.current_expansion.id.expn_data().call_site + } + + /// Equivalent of `Span::def_site` from the proc macro API, + /// except that the location is taken from the span passed as an argument. + pub fn with_def_site_ctxt(&self, span: Span) -> Span { + span.with_def_site_ctxt(self.current_expansion.id) + } + + /// Equivalent of `Span::call_site` from the proc macro API, + /// except that the location is taken from the span passed as an argument. + pub fn with_call_site_ctxt(&self, span: Span) -> Span { + span.with_call_site_ctxt(self.current_expansion.id) } - pub fn backtrace(&self) -> SyntaxContext { - SyntaxContext::empty().apply_mark(self.current_expansion.id) + + /// Equivalent of `Span::mixed_site` from the proc macro API, + /// except that the location is taken from the span passed as an argument. + pub fn with_mixed_site_ctxt(&self, span: Span) -> Span { + span.with_mixed_site_ctxt(self.current_expansion.id) } /// Returns span for the macro which originally caused the current expansion to happen. /// /// Stops backtracing at include! boundary. pub fn expansion_cause(&self) -> Option { - let mut ctxt = self.backtrace(); + let mut expn_id = self.current_expansion.id; let mut last_macro = None; loop { - if ctxt.outer_expn_info().map_or(None, |info| { - if info.kind.descr() == sym::include { - // Stop going up the backtrace once include! is encountered - return None; - } - ctxt = info.call_site.ctxt(); - last_macro = Some(info.call_site); - Some(()) - }).is_none() { - break + let expn_data = expn_id.expn_data(); + // Stop going up the backtrace once include! is encountered + if expn_data.is_root() || expn_data.kind.descr() == sym::include { + break; } + expn_id = expn_data.call_site.ctxt().outer_expn(); + last_macro = Some(expn_data.call_site); } last_macro } @@ -860,16 +1023,9 @@ impl<'a> ExtCtxt<'a> { pub fn span_err_with_code>(&self, sp: S, msg: &str, code: DiagnosticId) { self.parse_sess.span_diagnostic.span_err_with_code(sp, msg, code); } - pub fn mut_span_err>(&self, sp: S, msg: &str) - -> DiagnosticBuilder<'a> { - self.parse_sess.span_diagnostic.mut_span_err(sp, msg) - } pub fn span_warn>(&self, sp: S, msg: &str) { self.parse_sess.span_diagnostic.span_warn(sp, msg); } - pub fn span_unimpl>(&self, sp: S, msg: &str) -> ! { - self.parse_sess.span_diagnostic.span_unimpl(sp, msg); - } pub fn span_bug>(&self, sp: S, msg: &str) -> ! { self.parse_sess.span_diagnostic.span_bug(sp, msg); } @@ -893,13 +1049,13 @@ impl<'a> ExtCtxt<'a> { pub fn set_trace_macros(&mut self, x: bool) { self.ecfg.trace_mac = x } - pub fn ident_of(&self, st: &str) -> ast::Ident { - ast::Ident::from_str(st) + pub fn ident_of(&self, st: &str, sp: Span) -> ast::Ident { + ast::Ident::from_str_and_span(st, sp) } pub fn std_path(&self, components: &[Symbol]) -> Vec { - let def_site = DUMMY_SP.apply_mark(self.current_expansion.id); + let def_site = self.with_def_site_ctxt(DUMMY_SP); iter::once(Ident::new(kw::DollarCrate, def_site)) - .chain(components.iter().map(|&s| Ident::with_empty_ctxt(s))) + .chain(components.iter().map(|&s| Ident::with_dummy_span(s))) .collect() } pub fn name_of(&self, st: &str) -> ast::Name { @@ -910,7 +1066,7 @@ impl<'a> ExtCtxt<'a> { self.resolver.check_unused_macros(); } - /// Resolve a path mentioned inside Rust code. + /// Resolves a path mentioned inside Rust code. /// /// This unifies the logic used for resolving `include_X!`, and `#[doc(include)]` file paths. /// @@ -941,17 +1097,16 @@ impl<'a> ExtCtxt<'a> { /// compilation on error, merely emits a non-fatal error and returns `None`. pub fn expr_to_spanned_string<'a>( cx: &'a mut ExtCtxt<'_>, - mut expr: P, + expr: P, err_msg: &str, -) -> Result, Option>> { - // Update `expr.span`'s ctxt now in case expr is an `include!` macro invocation. - expr.span = expr.span.apply_mark(cx.current_expansion.id); - - // we want to be able to handle e.g., `concat!("foo", "bar")` - cx.expander().visit_expr(&mut expr); - Err(match expr.node { - ast::ExprKind::Lit(ref l) => match l.node { - ast::LitKind::Str(s, style) => return Ok(respan(expr.span, (s, style))), +) -> Result<(Symbol, ast::StrStyle, Span), Option>> { + // Perform eager expansion on the expression. + // We want to be able to handle e.g., `concat!("foo", "bar")`. + let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); + + Err(match expr.kind { + ast::ExprKind::Lit(ref l) => match l.kind { + ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)), ast::LitKind::Err(_) => None, _ => Some(cx.struct_span_err(l.span, err_msg)) }, @@ -965,7 +1120,7 @@ pub fn expr_to_string(cx: &mut ExtCtxt<'_>, expr: P, err_msg: &str) expr_to_spanned_string(cx, expr, err_msg) .map_err(|err| err.map(|mut err| err.emit())) .ok() - .map(|s| s.node) + .map(|(symbol, style, _)| (symbol, style)) } /// Non-fatally assert that `tts` is empty. Note that this function @@ -975,7 +1130,7 @@ pub fn expr_to_string(cx: &mut ExtCtxt<'_>, expr: P, err_msg: &str) /// done as rarely as possible). pub fn check_zero_tts(cx: &ExtCtxt<'_>, sp: Span, - tts: &[tokenstream::TokenTree], + tts: TokenStream, name: &str) { if !tts.is_empty() { cx.span_err(sp, &format!("{} takes no arguments", name)); @@ -986,7 +1141,7 @@ pub fn check_zero_tts(cx: &ExtCtxt<'_>, /// expect exactly one string literal, or emit an error and return `None`. pub fn get_single_str_from_tts(cx: &mut ExtCtxt<'_>, sp: Span, - tts: &[tokenstream::TokenTree], + tts: TokenStream, name: &str) -> Option { let mut p = cx.new_parser_from_tts(tts); @@ -1009,12 +1164,16 @@ pub fn get_single_str_from_tts(cx: &mut ExtCtxt<'_>, /// parsing error, emit a non-fatal error and return `None`. pub fn get_exprs_from_tts(cx: &mut ExtCtxt<'_>, sp: Span, - tts: &[tokenstream::TokenTree]) -> Option>> { + tts: TokenStream) -> Option>> { let mut p = cx.new_parser_from_tts(tts); let mut es = Vec::new(); while p.token != token::Eof { - let mut expr = panictry!(p.parse_expr()); - cx.expander().visit_expr(&mut expr); + let expr = panictry!(p.parse_expr()); + + // Perform eager expansion on the expression. + // We want to be able to handle e.g., `concat!("foo", "bar")`. + let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); + es.push(expr); if p.eat(&token::Comma) { continue; diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index db562840e8d3b..8c5289671c98e 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -1,33 +1,28 @@ -use crate::ast::{self, Ident, Generics, Expr, BlockCheckMode, UnOp, PatKind}; +use crate::ast::{self, Ident, Expr, BlockCheckMode, UnOp, PatKind}; use crate::attr; -use crate::source_map::{dummy_spanned, respan, Spanned}; +use crate::source_map::{respan, Spanned}; use crate::ext::base::ExtCtxt; use crate::ptr::P; use crate::symbol::{kw, sym, Symbol}; use crate::ThinVec; -use rustc_target::spec::abi::Abi; use syntax_pos::{Pos, Span}; -// Left so that Cargo tests don't break, this can be removed once those no longer use it -pub trait AstBuilder {} - impl<'a> ExtCtxt<'a> { pub fn path(&self, span: Span, strs: Vec ) -> ast::Path { - self.path_all(span, false, strs, vec![], vec![]) + self.path_all(span, false, strs, vec![]) } pub fn path_ident(&self, span: Span, id: ast::Ident) -> ast::Path { self.path(span, vec![id]) } pub fn path_global(&self, span: Span, strs: Vec ) -> ast::Path { - self.path_all(span, true, strs, vec![], vec![]) + self.path_all(span, true, strs, vec![]) } pub fn path_all(&self, span: Span, global: bool, mut idents: Vec , - args: Vec, - constraints: Vec ) + args: Vec) -> ast::Path { assert!(!idents.is_empty()); let add_root = global && !idents[0].is_path_segment_keyword(); @@ -39,8 +34,8 @@ impl<'a> ExtCtxt<'a> { segments.extend(idents.into_iter().map(|ident| { ast::PathSegment::from_ident(ident.with_span_pos(span)) })); - let args = if !args.is_empty() || !constraints.is_empty() { - ast::AngleBracketedArgs { args, constraints, span }.into() + let args = if !args.is_empty() { + ast::AngleBracketedArgs { args, constraints: Vec::new(), span }.into() } else { None }; @@ -52,42 +47,6 @@ impl<'a> ExtCtxt<'a> { ast::Path { span, segments } } - /// Constructs a qualified path. - /// - /// Constructs a path like `::ident`. - pub fn qpath(&self, - self_type: P, - trait_path: ast::Path, - ident: ast::Ident) - -> (ast::QSelf, ast::Path) { - self.qpath_all(self_type, trait_path, ident, vec![], vec![]) - } - - /// Constructs a qualified path. - /// - /// Constructs a path like `::ident<'a, T, A = Bar>`. - pub fn qpath_all(&self, - self_type: P, - trait_path: ast::Path, - ident: ast::Ident, - args: Vec, - constraints: Vec) - -> (ast::QSelf, ast::Path) { - let mut path = trait_path; - let args = if !args.is_empty() || !constraints.is_empty() { - ast::AngleBracketedArgs { args, constraints, span: ident.span }.into() - } else { - None - }; - path.segments.push(ast::PathSegment { ident, id: ast::DUMMY_NODE_ID, args }); - - (ast::QSelf { - ty: self_type, - path_span: path.span, - position: path.segments.len() - 1 - }, path) - } - pub fn ty_mt(&self, ty: P, mutbl: ast::Mutability) -> ast::MutTy { ast::MutTy { ty, @@ -95,11 +54,11 @@ impl<'a> ExtCtxt<'a> { } } - pub fn ty(&self, span: Span, ty: ast::TyKind) -> P { + pub fn ty(&self, span: Span, kind: ast::TyKind) -> P { P(ast::Ty { id: ast::DUMMY_NODE_ID, span, - node: ty + kind, }) } @@ -114,12 +73,12 @@ impl<'a> ExtCtxt<'a> { self.ty_path(self.path_ident(span, ident)) } - pub fn anon_const(&self, span: Span, expr: ast::ExprKind) -> ast::AnonConst { + pub fn anon_const(&self, span: Span, kind: ast::ExprKind) -> ast::AnonConst { ast::AnonConst { id: ast::DUMMY_NODE_ID, value: P(ast::Expr { id: ast::DUMMY_NODE_ID, - node: expr, + kind, span, attrs: ThinVec::new(), }) @@ -149,10 +108,6 @@ impl<'a> ExtCtxt<'a> { ast::TyKind::Ptr(self.ty_mt(ty, mutbl))) } - pub fn ty_infer(&self, span: Span) -> P { - self.ty(span, ast::TyKind::Infer) - } - pub fn typaram(&self, span: Span, ident: ast::Ident, @@ -166,7 +121,8 @@ impl<'a> ExtCtxt<'a> { bounds, kind: ast::GenericParamKind::Type { default, - } + }, + is_placeholder: false } } @@ -207,6 +163,7 @@ impl<'a> ExtCtxt<'a> { attrs: attrs.into(), bounds, kind: ast::GenericParamKind::Lifetime, + is_placeholder: false } } @@ -214,15 +171,7 @@ impl<'a> ExtCtxt<'a> { ast::Stmt { id: ast::DUMMY_NODE_ID, span: expr.span, - node: ast::StmtKind::Expr(expr), - } - } - - pub fn stmt_semi(&self, expr: P) -> ast::Stmt { - ast::Stmt { - id: ast::DUMMY_NODE_ID, - span: expr.span, - node: ast::StmtKind::Semi(expr), + kind: ast::StmtKind::Expr(expr), } } @@ -244,35 +193,7 @@ impl<'a> ExtCtxt<'a> { }); ast::Stmt { id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Local(local), - span: sp, - } - } - - pub fn stmt_let_typed(&self, - sp: Span, - mutbl: bool, - ident: ast::Ident, - typ: P, - ex: P) - -> ast::Stmt { - let pat = if mutbl { - let binding_mode = ast::BindingMode::ByValue(ast::Mutability::Mutable); - self.pat_ident_binding_mode(sp, ident, binding_mode) - } else { - self.pat_ident(sp, ident) - }; - let local = P(ast::Local { - pat, - ty: Some(typ), - init: Some(ex), - id: ast::DUMMY_NODE_ID, - span: sp, - attrs: ThinVec::new(), - }); - ast::Stmt { - id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Local(local), + kind: ast::StmtKind::Local(local), span: sp, } } @@ -289,7 +210,7 @@ impl<'a> ExtCtxt<'a> { }); ast::Stmt { id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Local(local), + kind: ast::StmtKind::Local(local), span, } } @@ -297,7 +218,7 @@ impl<'a> ExtCtxt<'a> { pub fn stmt_item(&self, sp: Span, item: P) -> ast::Stmt { ast::Stmt { id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Item(item), + kind: ast::StmtKind::Item(item), span: sp, } } @@ -306,7 +227,7 @@ impl<'a> ExtCtxt<'a> { self.block(expr.span, vec![ast::Stmt { id: ast::DUMMY_NODE_ID, span: expr.span, - node: ast::StmtKind::Expr(expr), + kind: ast::StmtKind::Expr(expr), }]) } pub fn block(&self, span: Span, stmts: Vec) -> P { @@ -318,10 +239,10 @@ impl<'a> ExtCtxt<'a> { }) } - pub fn expr(&self, span: Span, node: ast::ExprKind) -> P { + pub fn expr(&self, span: Span, kind: ast::ExprKind) -> P { P(ast::Expr { id: ast::DUMMY_NODE_ID, - node, + kind, span, attrs: ThinVec::new(), }) @@ -331,16 +252,11 @@ impl<'a> ExtCtxt<'a> { self.expr(path.span, ast::ExprKind::Path(None, path)) } - /// Constructs a `QPath` expression. - pub fn expr_qpath(&self, span: Span, qself: ast::QSelf, path: ast::Path) -> P { - self.expr(span, ast::ExprKind::Path(Some(qself), path)) - } - pub fn expr_ident(&self, span: Span, id: ast::Ident) -> P { self.expr_path(self.path_ident(span, id)) } pub fn expr_self(&self, span: Span) -> P { - self.expr_ident(span, Ident::with_empty_ctxt(kw::SelfLower)) + self.expr_ident(span, Ident::with_dummy_span(kw::SelfLower)) } pub fn expr_binary(&self, sp: Span, op: ast::BinOpKind, @@ -349,27 +265,12 @@ impl<'a> ExtCtxt<'a> { } pub fn expr_deref(&self, sp: Span, e: P) -> P { - self.expr_unary(sp, UnOp::Deref, e) - } - pub fn expr_unary(&self, sp: Span, op: ast::UnOp, e: P) -> P { - self.expr(sp, ast::ExprKind::Unary(op, e)) + self.expr(sp, ast::ExprKind::Unary(UnOp::Deref, e)) } - pub fn expr_field_access( - &self, sp: Span, expr: P, ident: ast::Ident, - ) -> P { - self.expr(sp, ast::ExprKind::Field(expr, ident.with_span_pos(sp))) - } - pub fn expr_tup_field_access(&self, sp: Span, expr: P, idx: usize) -> P { - let ident = Ident::from_str(&idx.to_string()).with_span_pos(sp); - self.expr(sp, ast::ExprKind::Field(expr, ident)) - } pub fn expr_addr_of(&self, sp: Span, e: P) -> P { self.expr(sp, ast::ExprKind::AddrOf(ast::Mutability::Immutable, e)) } - pub fn expr_mut_addr_of(&self, sp: Span, e: P) -> P { - self.expr(sp, ast::ExprKind::AddrOf(ast::Mutability::Mutable, e)) - } pub fn expr_call( &self, span: Span, expr: P, args: Vec>, @@ -403,6 +304,8 @@ impl<'a> ExtCtxt<'a> { span, is_shorthand: false, attrs: ThinVec::new(), + id: ast::DUMMY_NODE_ID, + is_placeholder: false, } } pub fn expr_struct( @@ -423,28 +326,10 @@ impl<'a> ExtCtxt<'a> { self.expr_lit(span, ast::LitKind::Int(i as u128, ast::LitIntType::Unsigned(ast::UintTy::Usize))) } - pub fn expr_isize(&self, sp: Span, i: isize) -> P { - if i < 0 { - let i = (-i) as u128; - let lit_ty = ast::LitIntType::Signed(ast::IntTy::Isize); - let lit = self.expr_lit(sp, ast::LitKind::Int(i, lit_ty)); - self.expr_unary(sp, ast::UnOp::Neg, lit) - } else { - self.expr_lit(sp, ast::LitKind::Int(i as u128, - ast::LitIntType::Signed(ast::IntTy::Isize))) - } - } pub fn expr_u32(&self, sp: Span, u: u32) -> P { self.expr_lit(sp, ast::LitKind::Int(u as u128, ast::LitIntType::Unsigned(ast::UintTy::U32))) } - pub fn expr_u16(&self, sp: Span, u: u16) -> P { - self.expr_lit(sp, ast::LitKind::Int(u as u128, - ast::LitIntType::Unsigned(ast::UintTy::U16))) - } - pub fn expr_u8(&self, sp: Span, u: u8) -> P { - self.expr_lit(sp, ast::LitKind::Int(u as u128, ast::LitIntType::Unsigned(ast::UintTy::U8))) - } pub fn expr_bool(&self, sp: Span, value: bool) -> P { self.expr_lit(sp, ast::LitKind::Bool(value)) } @@ -452,10 +337,6 @@ impl<'a> ExtCtxt<'a> { pub fn expr_vec(&self, sp: Span, exprs: Vec>) -> P { self.expr(sp, ast::ExprKind::Array(exprs)) } - pub fn expr_vec_ng(&self, sp: Span) -> P { - self.expr_call_global(sp, self.std_path(&[sym::vec, sym::Vec, sym::new]), - Vec::new()) - } pub fn expr_vec_slice(&self, sp: Span, exprs: Vec>) -> P { self.expr_addr_of(sp, self.expr_vec(sp, exprs)) } @@ -472,16 +353,6 @@ impl<'a> ExtCtxt<'a> { self.expr_call_global(sp, some, vec![expr]) } - pub fn expr_none(&self, sp: Span) -> P { - let none = self.std_path(&[sym::option, sym::Option, sym::None]); - let none = self.path_global(sp, none); - self.expr_path(none) - } - - pub fn expr_break(&self, sp: Span) -> P { - self.expr(sp, ast::ExprKind::Break(None, None)) - } - pub fn expr_tuple(&self, sp: Span, exprs: Vec>) -> P { self.expr(sp, ast::ExprKind::Tup(exprs)) } @@ -495,7 +366,7 @@ impl<'a> ExtCtxt<'a> { let expr_loc_ptr = self.expr_addr_of(span, expr_loc_tuple); self.expr_call_global( span, - self.std_path(&[sym::rt, sym::begin_panic]), + [sym::std, sym::rt, sym::begin_panic].iter().map(|s| Ident::new(*s, span)).collect(), vec![ self.expr_str(span, msg), expr_loc_ptr]) @@ -510,18 +381,13 @@ impl<'a> ExtCtxt<'a> { self.expr_call_global(sp, ok, vec![expr]) } - pub fn expr_err(&self, sp: Span, expr: P) -> P { - let err = self.std_path(&[sym::result, sym::Result, sym::Err]); - self.expr_call_global(sp, err, vec![expr]) - } - pub fn expr_try(&self, sp: Span, head: P) -> P { let ok = self.std_path(&[sym::result, sym::Result, sym::Ok]); let ok_path = self.path_global(sp, ok); let err = self.std_path(&[sym::result, sym::Result, sym::Err]); let err_path = self.path_global(sp, err); - let binding_variable = self.ident_of("__try_var"); + let binding_variable = self.ident_of("__try_var", sp); let binding_pat = self.pat_ident(sp, binding_variable); let binding_expr = self.expr_ident(sp, binding_variable); @@ -536,17 +402,17 @@ impl<'a> ExtCtxt<'a> { let err_expr = self.expr(sp, ast::ExprKind::Ret(Some(err_inner_expr))); // `Ok(__try_var) => __try_var` - let ok_arm = self.arm(sp, vec![ok_pat], binding_expr); + let ok_arm = self.arm(sp, ok_pat, binding_expr); // `Err(__try_var) => return Err(__try_var)` - let err_arm = self.arm(sp, vec![err_pat], err_expr); + let err_arm = self.arm(sp, err_pat, err_expr); // `match head { Ok() => ..., Err() => ... }` self.expr_match(sp, head, vec![ok_arm, err_arm]) } - pub fn pat(&self, span: Span, pat: PatKind) -> P { - P(ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, span }) + pub fn pat(&self, span: Span, kind: PatKind) -> P { + P(ast::Pat { id: ast::DUMMY_NODE_ID, kind, span }) } pub fn pat_wild(&self, span: Span) -> P { self.pat(span, PatKind::Wild) @@ -574,7 +440,7 @@ impl<'a> ExtCtxt<'a> { self.pat(span, PatKind::TupleStruct(path, subpats)) } pub fn pat_struct(&self, span: Span, path: ast::Path, - field_pats: Vec>) -> P { + field_pats: Vec) -> P { self.pat(span, PatKind::Struct(path, field_pats, false)) } pub fn pat_tuple(&self, span: Span, pats: Vec>) -> P { @@ -605,18 +471,20 @@ impl<'a> ExtCtxt<'a> { self.pat_tuple_struct(span, path, vec![pat]) } - pub fn arm(&self, span: Span, pats: Vec>, expr: P) -> ast::Arm { + pub fn arm(&self, span: Span, pat: P, expr: P) -> ast::Arm { ast::Arm { attrs: vec![], - pats, + pat, guard: None, body: expr, span, + id: ast::DUMMY_NODE_ID, + is_placeholder: false, } } pub fn arm_unreachable(&self, span: Span) -> ast::Arm { - self.arm(span, vec![self.pat_wild(span)], self.expr_unreachable(span)) + self.arm(span, self.pat_wild(span), self.expr_unreachable(span)) } pub fn expr_match(&self, span: Span, arg: P, arms: Vec) -> P { @@ -629,10 +497,6 @@ impl<'a> ExtCtxt<'a> { self.expr(span, ast::ExprKind::If(cond, self.block_expr(then), els)) } - pub fn expr_loop(&self, span: Span, block: P) -> P { - self.expr(span, ast::ExprKind::Loop(block, None)) - } - pub fn lambda_fn_decl(&self, span: Span, fn_decl: P, @@ -653,7 +517,7 @@ impl<'a> ExtCtxt<'a> { body: P) -> P { let fn_decl = self.fn_decl( - ids.iter().map(|id| self.arg(span, *id, self.ty_infer(span))).collect(), + ids.iter().map(|id| self.param(span, *id, self.ty(span, ast::TyKind::Infer))).collect(), ast::FunctionRetTy::Default(span)); // FIXME -- We are using `span` as the span of the `|...|` @@ -676,93 +540,46 @@ impl<'a> ExtCtxt<'a> { self.lambda(span, vec![ident], body) } - pub fn lambda_stmts(&self, - span: Span, - ids: Vec, - stmts: Vec) - -> P { - self.lambda(span, ids, self.expr_block(self.block(span, stmts))) - } - pub fn lambda_stmts_0(&self, span: Span, stmts: Vec) -> P { - self.lambda0(span, self.expr_block(self.block(span, stmts))) - } pub fn lambda_stmts_1(&self, span: Span, stmts: Vec, ident: ast::Ident) -> P { self.lambda1(span, self.expr_block(self.block(span, stmts)), ident) } - pub fn arg(&self, span: Span, ident: ast::Ident, ty: P) -> ast::Arg { + pub fn param(&self, span: Span, ident: ast::Ident, ty: P) -> ast::Param { let arg_pat = self.pat_ident(span, ident); - ast::Arg { + ast::Param { attrs: ThinVec::default(), id: ast::DUMMY_NODE_ID, pat: arg_pat, span, ty, + is_placeholder: false, } } // FIXME: unused `self` - pub fn fn_decl(&self, inputs: Vec, output: ast::FunctionRetTy) -> P { + pub fn fn_decl(&self, inputs: Vec, output: ast::FunctionRetTy) -> P { P(ast::FnDecl { inputs, output, - c_variadic: false }) } pub fn item(&self, span: Span, name: Ident, - attrs: Vec, node: ast::ItemKind) -> P { + attrs: Vec, kind: ast::ItemKind) -> P { // FIXME: Would be nice if our generated code didn't violate // Rust coding conventions P(ast::Item { ident: name, attrs, id: ast::DUMMY_NODE_ID, - node, + kind, vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), span, tokens: None, }) } - pub fn item_fn_poly(&self, - span: Span, - name: Ident, - inputs: Vec , - output: P, - generics: Generics, - body: P) -> P { - self.item(span, - name, - Vec::new(), - ast::ItemKind::Fn(self.fn_decl(inputs, ast::FunctionRetTy::Ty(output)), - ast::FnHeader { - unsafety: ast::Unsafety::Normal, - asyncness: dummy_spanned(ast::IsAsync::NotAsync), - constness: dummy_spanned(ast::Constness::NotConst), - abi: Abi::Rust, - }, - generics, - body)) - } - - pub fn item_fn(&self, - span: Span, - name: Ident, - inputs: Vec , - output: P, - body: P - ) -> P { - self.item_fn_poly( - span, - name, - inputs, - output, - Generics::default(), - body) - } - pub fn variant(&self, span: Span, ident: Ident, tys: Vec> ) -> ast::Variant { let fields: Vec<_> = tys.into_iter().map(|ty| { ast::StructField { @@ -772,6 +589,7 @@ impl<'a> ExtCtxt<'a> { vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, + is_placeholder: false, } }).collect(); @@ -781,60 +599,15 @@ impl<'a> ExtCtxt<'a> { ast::VariantData::Tuple(fields, ast::DUMMY_NODE_ID) }; - respan(span, - ast::Variant_ { - ident, - id: ast::DUMMY_NODE_ID, - attrs: Vec::new(), - data: vdata, - disr_expr: None, - }) - } - - pub fn item_enum_poly(&self, span: Span, name: Ident, - enum_definition: ast::EnumDef, - generics: Generics) -> P { - self.item(span, name, Vec::new(), ast::ItemKind::Enum(enum_definition, generics)) - } - - pub fn item_enum(&self, span: Span, name: Ident, - enum_definition: ast::EnumDef) -> P { - self.item_enum_poly(span, name, enum_definition, - Generics::default()) - } - - pub fn item_struct(&self, span: Span, name: Ident, - struct_def: ast::VariantData) -> P { - self.item_struct_poly( - span, - name, - struct_def, - Generics::default() - ) - } - - pub fn item_struct_poly(&self, span: Span, name: Ident, - struct_def: ast::VariantData, generics: Generics) -> P { - self.item(span, name, Vec::new(), ast::ItemKind::Struct(struct_def, generics)) - } - - pub fn item_mod(&self, span: Span, inner_span: Span, name: Ident, - attrs: Vec, - items: Vec>) -> P { - self.item( + ast::Variant { + attrs: Vec::new(), + data: vdata, + disr_expr: None, + id: ast::DUMMY_NODE_ID, + ident, span, - name, - attrs, - ast::ItemKind::Mod(ast::Mod { - inner: inner_span, - items, - inline: true - }) - ) - } - - pub fn item_extern_crate(&self, span: Span, name: Ident) -> P { - self.item(span, name, Vec::new(), ast::ItemKind::ExternCrate(None)) + is_placeholder: false, + } } pub fn item_static(&self, @@ -856,15 +629,6 @@ impl<'a> ExtCtxt<'a> { self.item(span, name, Vec::new(), ast::ItemKind::Const(ty, expr)) } - pub fn item_ty_poly(&self, span: Span, name: Ident, ty: P, - generics: Generics) -> P { - self.item(span, name, Vec::new(), ast::ItemKind::TyAlias(ty, generics)) - } - - pub fn item_ty(&self, span: Span, name: Ident, ty: P) -> P { - self.item_ty_poly(span, name, ty, Generics::default()) - } - pub fn attribute(&self, mi: ast::MetaItem) -> ast::Attribute { attr::mk_attr_outer(mi) } @@ -872,70 +636,4 @@ impl<'a> ExtCtxt<'a> { pub fn meta_word(&self, sp: Span, w: ast::Name) -> ast::MetaItem { attr::mk_word_item(Ident::new(w, sp)) } - - pub fn meta_list_item_word(&self, sp: Span, w: ast::Name) -> ast::NestedMetaItem { - attr::mk_nested_word_item(Ident::new(w, sp)) - } - - pub fn meta_list(&self, sp: Span, name: ast::Name, mis: Vec) - -> ast::MetaItem { - attr::mk_list_item(Ident::new(name, sp), mis) - } - - pub fn meta_name_value(&self, span: Span, name: ast::Name, lit_kind: ast::LitKind) - -> ast::MetaItem { - attr::mk_name_value_item(Ident::new(name, span), lit_kind, span) - } - - pub fn item_use(&self, sp: Span, - vis: ast::Visibility, vp: P) -> P { - P(ast::Item { - id: ast::DUMMY_NODE_ID, - ident: Ident::invalid(), - attrs: vec![], - node: ast::ItemKind::Use(vp), - vis, - span: sp, - tokens: None, - }) - } - - pub fn item_use_simple(&self, sp: Span, vis: ast::Visibility, path: ast::Path) -> P { - self.item_use_simple_(sp, vis, None, path) - } - - pub fn item_use_simple_(&self, sp: Span, vis: ast::Visibility, - rename: Option, path: ast::Path) -> P { - self.item_use(sp, vis, P(ast::UseTree { - span: sp, - prefix: path, - kind: ast::UseTreeKind::Simple(rename, ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID), - })) - } - - pub fn item_use_list(&self, sp: Span, vis: ast::Visibility, - path: Vec, imports: &[ast::Ident]) -> P { - let imports = imports.iter().map(|id| { - (ast::UseTree { - span: sp, - prefix: self.path(sp, vec![*id]), - kind: ast::UseTreeKind::Simple(None, ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID), - }, ast::DUMMY_NODE_ID) - }).collect(); - - self.item_use(sp, vis, P(ast::UseTree { - span: sp, - prefix: self.path(sp, path), - kind: ast::UseTreeKind::Nested(imports), - })) - } - - pub fn item_use_glob(&self, sp: Span, - vis: ast::Visibility, path: Vec) -> P { - self.item_use(sp, vis, P(ast::UseTree { - span: sp, - prefix: self.path(sp, path), - kind: ast::UseTreeKind::Glob, - })) - } } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 964c81dd46641..bbd8da2acef05 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1,11 +1,12 @@ -use crate::ast::{self, Block, Ident, LitKind, NodeId, PatKind, Path}; +use crate::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path}; use crate::ast::{MacStmtStyle, StmtKind, ItemKind}; use crate::attr::{self, HasAttrs}; -use crate::source_map::{dummy_spanned, respan}; +use crate::source_map::respan; use crate::config::StripUnconfigured; use crate::ext::base::*; -use crate::ext::proc_macro::collect_derives; -use crate::ext::hygiene::{ExpnId, SyntaxContext, ExpnInfo, ExpnKind}; +use crate::ext::proc_macro::{collect_derives, MarkAttrs}; +use crate::ext::hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind}; +use crate::ext::mbe::macro_rules::annotate_err_with_kind; use crate::ext::placeholders::{placeholder, PlaceholderExpander}; use crate::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err}; use crate::mut_visit::*; @@ -24,9 +25,8 @@ use syntax_pos::{Span, DUMMY_SP, FileName}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; -use std::fs; use std::io::ErrorKind; -use std::{iter, mem}; +use std::{iter, mem, slice}; use std::ops::DerefMut; use std::rc::Rc; use std::path::PathBuf; @@ -115,20 +115,8 @@ macro_rules! ast_fragments { } } - impl<'a, 'b> MutVisitor for MacroExpander<'a, 'b> { - fn filter_map_expr(&mut self, expr: P) -> Option> { - self.expand_fragment(AstFragment::OptExpr(Some(expr))).make_opt_expr() - } - $($(fn $mut_visit_ast(&mut self, ast: &mut $AstTy) { - visit_clobber(ast, |ast| self.expand_fragment(AstFragment::$Kind(ast)).$make_ast()); - })?)* - $($(fn $flat_map_ast_elt(&mut self, ast_elt: <$AstTy as IntoIterator>::Item) -> $AstTy { - self.expand_fragment(AstFragment::$Kind(smallvec![ast_elt])).$make_ast() - })?)* - } - - impl<'a> MacResult for crate::ext::tt::macro_rules::ParserAnyMacro<'a> { - $(fn $make_ast(self: Box>) + impl<'a> MacResult for crate::ext::mbe::macro_rules::ParserAnyMacro<'a> { + $(fn $make_ast(self: Box>) -> Option<$AstTy> { Some(self.make(AstFragmentKind::$Kind).$make_ast()) })* @@ -153,7 +141,40 @@ ast_fragments! { "impl item"; many fn flat_map_impl_item; fn visit_impl_item; fn make_impl_items; } ForeignItems(SmallVec<[ast::ForeignItem; 1]>) { - "foreign item"; many fn flat_map_foreign_item; fn visit_foreign_item; fn make_foreign_items; + "foreign item"; + many fn flat_map_foreign_item; + fn visit_foreign_item; + fn make_foreign_items; + } + Arms(SmallVec<[ast::Arm; 1]>) { + "match arm"; many fn flat_map_arm; fn visit_arm; fn make_arms; + } + Fields(SmallVec<[ast::Field; 1]>) { + "field expression"; many fn flat_map_field; fn visit_field; fn make_fields; + } + FieldPats(SmallVec<[ast::FieldPat; 1]>) { + "field pattern"; + many fn flat_map_field_pattern; + fn visit_field_pattern; + fn make_field_patterns; + } + GenericParams(SmallVec<[ast::GenericParam; 1]>) { + "generic parameter"; + many fn flat_map_generic_param; + fn visit_generic_param; + fn make_generic_params; + } + Params(SmallVec<[ast::Param; 1]>) { + "function parameter"; many fn flat_map_param; fn visit_param; fn make_params; + } + StructFields(SmallVec<[ast::StructField; 1]>) { + "field"; + many fn flat_map_struct_field; + fn visit_struct_field; + fn make_struct_fields; + } + Variants(SmallVec<[ast::Variant; 1]>) { + "variant"; many fn flat_map_variant; fn visit_variant; fn make_variants; } } @@ -166,6 +187,21 @@ impl AstFragmentKind { -> AstFragment { let mut items = items.into_iter(); match self { + AstFragmentKind::Arms => + AstFragment::Arms(items.map(Annotatable::expect_arm).collect()), + AstFragmentKind::Fields => + AstFragment::Fields(items.map(Annotatable::expect_field).collect()), + AstFragmentKind::FieldPats => + AstFragment::FieldPats(items.map(Annotatable::expect_field_pattern).collect()), + AstFragmentKind::GenericParams => + AstFragment::GenericParams(items.map(Annotatable::expect_generic_param).collect()), + AstFragmentKind::Params => + AstFragment::Params(items.map(Annotatable::expect_param).collect()), + AstFragmentKind::StructFields => AstFragment::StructFields( + items.map(Annotatable::expect_struct_field).collect() + ), + AstFragmentKind::Variants => + AstFragment::Variants(items.map(Annotatable::expect_variant).collect()), AstFragmentKind::Items => AstFragment::Items(items.map(Annotatable::expect_item).collect()), AstFragmentKind::ImplItems => @@ -189,7 +225,7 @@ impl AstFragmentKind { pub struct Invocation { pub kind: InvocationKind, - fragment_kind: AstFragmentKind, + pub fragment_kind: AstFragmentKind, pub expansion_data: ExpansionData, } @@ -257,15 +293,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let krate_item = AstFragment::Items(smallvec![P(ast::Item { attrs: krate.attrs, span: krate.span, - node: ast::ItemKind::Mod(krate.module), + kind: ast::ItemKind::Mod(krate.module), ident: Ident::invalid(), id: ast::DUMMY_NODE_ID, vis: respan(krate.span.shrink_to_lo(), ast::VisibilityKind::Public), tokens: None, })]); - match self.expand_fragment(krate_item).make_items().pop().map(P::into_inner) { - Some(ast::Item { attrs, node: ast::ItemKind::Mod(module), .. }) => { + match self.fully_expand_fragment(krate_item).make_items().pop().map(P::into_inner) { + Some(ast::Item { attrs, kind: ast::ItemKind::Mod(module), .. }) => { krate.attrs = attrs; krate.module = module; }, @@ -284,8 +320,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { krate } - // Fully expand all macro invocations in this AST fragment. - fn expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment { + // Recursively expand all macro invocations in this AST fragment. + pub fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment { let orig_expansion_data = self.cx.current_expansion.clone(); self.cx.current_expansion.depth = 0; @@ -303,7 +339,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // Unresolved macros produce dummy outputs as a recovery measure. invocations.reverse(); let mut expanded_fragments = Vec::new(); - let mut derives: FxHashMap> = FxHashMap::default(); + let mut all_derive_placeholders: FxHashMap> = FxHashMap::default(); let mut undetermined_invocations = Vec::new(); let (mut progress, mut force) = (false, !self.monotonic); loop { @@ -317,10 +353,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { continue }; - let scope = + let eager_expansion_root = if self.monotonic { invoc.expansion_data.id } else { orig_expansion_data.id }; - let ext = match self.cx.resolver.resolve_macro_invocation(&invoc, scope, force) { - Ok(ext) => ext, + let res = match self.cx.resolver.resolve_macro_invocation( + &invoc, eager_expansion_root, force + ) { + Ok(res) => res, Err(Indeterminate) => { undetermined_invocations.push(invoc); continue @@ -330,56 +368,74 @@ impl<'a, 'b> MacroExpander<'a, 'b> { progress = true; let ExpansionData { depth, id: expn_id, .. } = invoc.expansion_data; self.cx.current_expansion = invoc.expansion_data.clone(); - self.cx.current_expansion.id = scope; // FIXME(jseyfried): Refactor out the following logic - let (expanded_fragment, new_invocations) = if let Some(ext) = ext { - let fragment = self.expand_invoc(invoc, &ext.kind); - self.collect_invocations(fragment, &[]) - } else if let InvocationKind::DeriveContainer { derives: traits, item } = invoc.kind { - if !item.derive_allowed() { - let attr = attr::find_by_name(item.attrs(), sym::derive) - .expect("`derive` attribute should exist"); - let span = attr.span; - let mut err = self.cx.mut_span_err(span, - "`derive` may only be applied to \ - structs, enums and unions"); - if let ast::AttrStyle::Inner = attr.style { - let trait_list = traits.iter() - .map(|t| t.to_string()).collect::>(); - let suggestion = format!("#[derive({})]", trait_list.join(", ")); - err.span_suggestion( - span, "try an outer attribute", suggestion, - // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT - Applicability::MaybeIncorrect - ); - } - err.emit(); + let (expanded_fragment, new_invocations) = match res { + InvocationRes::Single(ext) => { + let fragment = self.expand_invoc(invoc, &ext.kind); + self.collect_invocations(fragment, &[]) } + InvocationRes::DeriveContainer(exts) => { + let (derives, item) = match invoc.kind { + InvocationKind::DeriveContainer { derives, item } => (derives, item), + _ => unreachable!(), + }; + if !item.derive_allowed() { + let attr = attr::find_by_name(item.attrs(), sym::derive) + .expect("`derive` attribute should exist"); + let span = attr.span; + let mut err = self.cx.struct_span_err(span, + "`derive` may only be applied to structs, enums and unions"); + if let ast::AttrStyle::Inner = attr.style { + let trait_list = derives.iter() + .map(|t| t.to_string()).collect::>(); + let suggestion = format!("#[derive({})]", trait_list.join(", ")); + err.span_suggestion( + span, "try an outer attribute", suggestion, + // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT + Applicability::MaybeIncorrect + ); + } + err.emit(); + } - let mut item = self.fully_configure(item); - item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive)); - let derives = derives.entry(invoc.expansion_data.id).or_default(); - - derives.reserve(traits.len()); - invocations.reserve(traits.len()); - for path in traits { - let expn_id = ExpnId::fresh(self.cx.current_expansion.id, None); - derives.push(expn_id); - invocations.push(Invocation { - kind: InvocationKind::Derive { path, item: item.clone() }, - fragment_kind: invoc.fragment_kind, - expansion_data: ExpansionData { - id: expn_id, - ..invoc.expansion_data.clone() - }, - }); + let mut item = self.fully_configure(item); + item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive)); + let mut helper_attrs = Vec::new(); + let mut has_copy = false; + for ext in exts { + helper_attrs.extend(&ext.helper_attrs); + has_copy |= ext.is_derive_copy; + } + // Mark derive helpers inside this item as known and used. + // FIXME: This is a hack, derive helpers should be integrated with regular name + // resolution instead. For example, helpers introduced by a derive container + // can be in scope for all code produced by that container's expansion. + item.visit_with(&mut MarkAttrs(&helper_attrs)); + if has_copy { + self.cx.resolver.add_derives(invoc.expansion_data.id, SpecialDerives::COPY); + } + + let derive_placeholders = + all_derive_placeholders.entry(invoc.expansion_data.id).or_default(); + derive_placeholders.reserve(derives.len()); + invocations.reserve(derives.len()); + for path in derives { + let expn_id = ExpnId::fresh(None); + derive_placeholders.push(NodeId::placeholder_from_expn_id(expn_id)); + invocations.push(Invocation { + kind: InvocationKind::Derive { path, item: item.clone() }, + fragment_kind: invoc.fragment_kind, + expansion_data: ExpansionData { + id: expn_id, + ..invoc.expansion_data.clone() + }, + }); + } + let fragment = invoc.fragment_kind + .expect_from_annotatables(::std::iter::once(item)); + self.collect_invocations(fragment, derive_placeholders) } - let fragment = invoc.fragment_kind - .expect_from_annotatables(::std::iter::once(item)); - self.collect_invocations(fragment, derives) - } else { - unreachable!() }; if expanded_fragments.len() < depth { @@ -396,10 +452,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // Finally incorporate all the expanded macros into the input AST fragment. let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic); while let Some(expanded_fragments) = expanded_fragments.pop() { - for (mark, expanded_fragment) in expanded_fragments.into_iter().rev() { - let derives = derives.remove(&mark).unwrap_or_else(Vec::new); - placeholder_expander.add(NodeId::placeholder_from_expn_id(mark), - expanded_fragment, derives); + for (expn_id, expanded_fragment) in expanded_fragments.into_iter().rev() { + let derive_placeholders = + all_derive_placeholders.remove(&expn_id).unwrap_or_else(Vec::new); + placeholder_expander.add(NodeId::placeholder_from_expn_id(expn_id), + expanded_fragment, derive_placeholders); } } fragment_with_placeholders.mut_visit_with(&mut placeholder_expander); @@ -416,7 +473,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { /// them with "placeholders" - dummy macro invocations with specially crafted `NodeId`s. /// Then call into resolver that builds a skeleton ("reduced graph") of the fragment and /// prepares data for resolving paths of macro invocations. - fn collect_invocations(&mut self, mut fragment: AstFragment, derives: &[ExpnId]) + fn collect_invocations(&mut self, mut fragment: AstFragment, extra_placeholders: &[NodeId]) -> (AstFragment, Vec) { // Resolve `$crate`s in the fragment for pretty-printing. self.cx.resolver.resolve_dollar_crates(); @@ -435,9 +492,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { collector.invocations }; + // FIXME: Merge `extra_placeholders` into the `fragment` as regular placeholders. if self.monotonic { self.cx.resolver.visit_ast_fragment_with_placeholders( - self.cx.current_expansion.id, &fragment, derives); + self.cx.current_expansion.id, &fragment, extra_placeholders); } (fragment, invocations) @@ -472,25 +530,37 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Annotatable::Expr(mut expr) => { Annotatable::Expr({ cfg.visit_expr(&mut expr); expr }) } + Annotatable::Arm(arm) => { + Annotatable::Arm(cfg.flat_map_arm(arm).pop().unwrap()) + } + Annotatable::Field(field) => { + Annotatable::Field(cfg.flat_map_field(field).pop().unwrap()) + } + Annotatable::FieldPat(fp) => { + Annotatable::FieldPat(cfg.flat_map_field_pattern(fp).pop().unwrap()) + } + Annotatable::GenericParam(param) => { + Annotatable::GenericParam(cfg.flat_map_generic_param(param).pop().unwrap()) + } + Annotatable::Param(param) => { + Annotatable::Param(cfg.flat_map_param(param).pop().unwrap()) + } + Annotatable::StructField(sf) => { + Annotatable::StructField(cfg.flat_map_struct_field(sf).pop().unwrap()) + } + Annotatable::Variant(v) => { + Annotatable::Variant(cfg.flat_map_variant(v).pop().unwrap()) + } } } fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstFragment { - let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); - if fragment_kind == AstFragmentKind::ForeignItems && !self.cx.ecfg.macros_in_extern() { - if let SyntaxExtensionKind::NonMacroAttr { .. } = ext {} else { - emit_feature_err(&self.cx.parse_sess, sym::macros_in_extern, - span, GateIssue::Language, - "macro invocations in `extern {}` blocks are experimental"); - } - } - if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit { - let info = self.cx.current_expansion.id.expn_info().unwrap(); + let expn_data = self.cx.current_expansion.id.expn_data(); let suggested_limit = self.cx.ecfg.recursion_limit * 2; - let mut err = self.cx.struct_span_err(info.call_site, + let mut err = self.cx.struct_span_err(expn_data.call_site, &format!("recursion limit reached while expanding the macro `{}`", - info.kind.descr())); + expn_data.kind.descr())); err.help(&format!( "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", suggested_limit)); @@ -499,26 +569,26 @@ impl<'a, 'b> MacroExpander<'a, 'b> { FatalError.raise(); } + let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); match invoc.kind { InvocationKind::Bang { mac, .. } => match ext { SyntaxExtensionKind::Bang(expander) => { self.gate_proc_macro_expansion_kind(span, fragment_kind); - let tok_result = expander.expand(self.cx, span, mac.node.stream()); + let tok_result = expander.expand(self.cx, span, mac.stream()); let result = - self.parse_ast_fragment(tok_result, fragment_kind, &mac.node.path, span); + self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span); self.gate_proc_macro_expansion(span, &result); result } SyntaxExtensionKind::LegacyBang(expander) => { let prev = self.cx.current_expansion.prior_type_ascription; - self.cx.current_expansion.prior_type_ascription = - mac.node.prior_type_ascription; - let tok_result = expander.expand(self.cx, span, mac.node.stream()); + self.cx.current_expansion.prior_type_ascription = mac.prior_type_ascription; + let tok_result = expander.expand(self.cx, span, mac.stream()); let result = if let Some(result) = fragment_kind.make_from(tok_result) { result } else { let msg = format!("non-{kind} macro in {kind} position: {path}", - kind = fragment_kind.name(), path = mac.node.path); + kind = fragment_kind.name(), path = mac.path); self.cx.span_err(span, &msg); self.cx.trace_macros_diag(); fragment_kind.dummy(span) @@ -538,10 +608,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Annotatable::ForeignItem(item) => token::NtForeignItem(item.into_inner()), Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()), Annotatable::Expr(expr) => token::NtExpr(expr), + Annotatable::Arm(..) + | Annotatable::Field(..) + | Annotatable::FieldPat(..) + | Annotatable::GenericParam(..) + | Annotatable::Param(..) + | Annotatable::StructField(..) + | Annotatable::Variant(..) + => panic!("unexpected annotatable"), })), DUMMY_SP).into(); - let input = self.extract_proc_macro_attr_input(attr.tokens, span); + let input = self.extract_proc_macro_attr_input(attr.item.tokens, span); let tok_result = expander.expand(self.cx, span, input, item_tok); - let res = self.parse_ast_fragment(tok_result, fragment_kind, &attr.path, span); + let res = + self.parse_ast_fragment(tok_result, fragment_kind, &attr.item.path, span); self.gate_proc_macro_expansion(span, &res); res } @@ -573,8 +652,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { if !item.derive_allowed() { return fragment_kind.dummy(span); } - let meta = ast::MetaItem { node: ast::MetaItemKind::Word, span, path }; - let span = span.with_ctxt(self.cx.backtrace()); + let meta = ast::MetaItem { kind: ast::MetaItemKind::Word, span, path }; let items = expander.expand(self.cx, span, &meta, item); fragment_kind.expect_from_annotatables(items) } @@ -604,7 +682,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) { let (kind, gate) = match *item { Annotatable::Item(ref item) => { - match item.node { + match item.kind { ItemKind::Mod(_) if self.cx.ecfg.proc_macro_hygiene() => return, ItemKind::Mod(_) => ("modules", sym::proc_macro_hygiene), _ => return, @@ -617,6 +695,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Annotatable::Expr(_) if self.cx.ecfg.proc_macro_hygiene() => return, Annotatable::Stmt(_) => ("statements", sym::proc_macro_hygiene), Annotatable::Expr(_) => ("expressions", sym::proc_macro_hygiene), + Annotatable::Arm(..) + | Annotatable::Field(..) + | Annotatable::FieldPat(..) + | Annotatable::GenericParam(..) + | Annotatable::Param(..) + | Annotatable::StructField(..) + | Annotatable::Variant(..) + => panic!("unexpected annotatable"), }; emit_feature_err( self.cx.parse_sess, @@ -644,7 +730,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { impl<'ast, 'a> Visitor<'ast> for DisallowMacros<'a> { fn visit_item(&mut self, i: &'ast ast::Item) { - if let ast::ItemKind::MacroDef(_) = i.node { + if let ast::ItemKind::MacroDef(_) = i.kind { emit_feature_err( self.parse_sess, sym::proc_macro_hygiene, @@ -664,15 +750,23 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn gate_proc_macro_expansion_kind(&self, span: Span, kind: AstFragmentKind) { let kind = match kind { - AstFragmentKind::Expr => "expressions", + AstFragmentKind::Expr | AstFragmentKind::OptExpr => "expressions", AstFragmentKind::Pat => "patterns", - AstFragmentKind::Ty => "types", AstFragmentKind::Stmts => "statements", - AstFragmentKind::Items => return, - AstFragmentKind::TraitItems => return, - AstFragmentKind::ImplItems => return, + AstFragmentKind::Ty | + AstFragmentKind::Items | + AstFragmentKind::TraitItems | + AstFragmentKind::ImplItems | AstFragmentKind::ForeignItems => return, + AstFragmentKind::Arms + | AstFragmentKind::Fields + | AstFragmentKind::FieldPats + | AstFragmentKind::GenericParams + | AstFragmentKind::Params + | AstFragmentKind::StructFields + | AstFragmentKind::Variants + => panic!("unexpected AST fragment kind"), }; if self.cx.ecfg.proc_macro_hygiene() { return @@ -686,13 +780,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ); } - fn parse_ast_fragment(&mut self, - toks: TokenStream, - kind: AstFragmentKind, - path: &Path, - span: Span) - -> AstFragment { - let mut parser = self.cx.new_parser_from_tts(&toks.into_trees().collect::>()); + fn parse_ast_fragment( + &mut self, + toks: TokenStream, + kind: AstFragmentKind, + path: &Path, + span: Span, + ) -> AstFragment { + let mut parser = self.cx.new_parser_from_tts(toks); match parser.parse_ast_fragment(kind, false) { Ok(fragment) => { parser.ensure_complete_parse(path, kind.name(), span); @@ -700,6 +795,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } Err(mut err) => { err.set_span(span); + annotate_err_with_kind(&mut err, kind, span); err.emit(); self.cx.trace_macros_diag(); kind.dummy(span) @@ -761,6 +857,14 @@ impl<'a> Parser<'a> { }, AstFragmentKind::Ty => AstFragment::Ty(self.parse_ty()?), AstFragmentKind::Pat => AstFragment::Pat(self.parse_pat(None)?), + AstFragmentKind::Arms + | AstFragmentKind::Fields + | AstFragmentKind::FieldPats + | AstFragmentKind::GenericParams + | AstFragmentKind::Params + | AstFragmentKind::StructFields + | AstFragmentKind::Variants + => panic!("unexpected AST fragment kind"), }) } @@ -769,7 +873,7 @@ impl<'a> Parser<'a> { let msg = format!("macro expansion ignores token `{}` and any following", self.this_token_to_string()); // Avoid emitting backtrace info twice. - let def_site_span = self.token.span.with_ctxt(SyntaxContext::empty()); + let def_site_span = self.token.span.with_ctxt(SyntaxContext::root()); let mut err = self.diagnostic().struct_span_err(def_site_span, &msg); err.span_label(span, "caused by the macro expansion here"); let msg = format!( @@ -806,17 +910,20 @@ struct InvocationCollector<'a, 'b> { impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment { - // Expansion info for all the collected invocations is set upon their resolution, + // Expansion data for all the collected invocations is set upon their resolution, // with exception of the derive container case which is not resolved and can get - // its expansion info immediately. - let expn_info = match &kind { - InvocationKind::DeriveContainer { item, .. } => Some(ExpnInfo::default( - ExpnKind::Macro(MacroKind::Attr, sym::derive), - item.span(), self.cx.parse_sess.edition, - )), + // its expansion data immediately. + let expn_data = match &kind { + InvocationKind::DeriveContainer { item, .. } => Some(ExpnData { + parent: self.cx.current_expansion.id, + ..ExpnData::default( + ExpnKind::Macro(MacroKind::Attr, sym::derive), + item.span(), self.cx.parse_sess.edition, + ) + }), _ => None, }; - let expn_id = ExpnId::fresh(self.cx.current_expansion.id, expn_info); + let expn_id = ExpnId::fresh(expn_data); self.invocations.push(Invocation { kind, fragment_kind, @@ -905,7 +1012,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn check_attributes(&mut self, attrs: &[ast::Attribute]) { let features = self.cx.ecfg.features.unwrap(); for attr in attrs.iter() { - self.check_attribute_inner(attr, features); + feature_gate::check_attribute(attr, self.cx.parse_sess, features); // macros are expanded before any lint passes so this warning has to be hardcoded if attr.path == sym::derive { @@ -915,22 +1022,13 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } } } - - fn check_attribute(&mut self, at: &ast::Attribute) { - let features = self.cx.ecfg.features.unwrap(); - self.check_attribute_inner(at, features); - } - - fn check_attribute_inner(&mut self, at: &ast::Attribute, features: &Features) { - feature_gate::check_attribute(at, self.cx.parse_sess, features); - } } impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn visit_expr(&mut self, expr: &mut P) { self.cfg.configure_expr(expr); visit_clobber(expr.deref_mut(), |mut expr| { - self.cfg.configure_expr_kind(&mut expr.node); + self.cfg.configure_expr_kind(&mut expr.kind); // ignore derives so they remain unused let (attr, after_derive) = self.classify_nonitem(&mut expr); @@ -947,7 +1045,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .into_inner() } - if let ast::ExprKind::Mac(mac) = expr.node { + if let ast::ExprKind::Mac(mac) = expr.kind { self.check_attributes(&expr.attrs); self.collect_bang(mac, expr.span, AstFragmentKind::Expr) .make_expr() @@ -959,10 +1057,88 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { }); } + fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> { + let mut arm = configure!(self, arm); + + let (attr, traits, after_derive) = self.classify_item(&mut arm); + if attr.is_some() || !traits.is_empty() { + return self.collect_attr(attr, traits, Annotatable::Arm(arm), + AstFragmentKind::Arms, after_derive) + .make_arms(); + } + + noop_flat_map_arm(arm, self) + } + + fn flat_map_field(&mut self, field: ast::Field) -> SmallVec<[ast::Field; 1]> { + let mut field = configure!(self, field); + + let (attr, traits, after_derive) = self.classify_item(&mut field); + if attr.is_some() || !traits.is_empty() { + return self.collect_attr(attr, traits, Annotatable::Field(field), + AstFragmentKind::Fields, after_derive) + .make_fields(); + } + + noop_flat_map_field(field, self) + } + + fn flat_map_field_pattern(&mut self, fp: ast::FieldPat) -> SmallVec<[ast::FieldPat; 1]> { + let mut fp = configure!(self, fp); + + let (attr, traits, after_derive) = self.classify_item(&mut fp); + if attr.is_some() || !traits.is_empty() { + return self.collect_attr(attr, traits, Annotatable::FieldPat(fp), + AstFragmentKind::FieldPats, after_derive) + .make_field_patterns(); + } + + noop_flat_map_field_pattern(fp, self) + } + + fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> { + let mut p = configure!(self, p); + + let (attr, traits, after_derive) = self.classify_item(&mut p); + if attr.is_some() || !traits.is_empty() { + return self.collect_attr(attr, traits, Annotatable::Param(p), + AstFragmentKind::Params, after_derive) + .make_params(); + } + + noop_flat_map_param(p, self) + } + + fn flat_map_struct_field(&mut self, sf: ast::StructField) -> SmallVec<[ast::StructField; 1]> { + let mut sf = configure!(self, sf); + + let (attr, traits, after_derive) = self.classify_item(&mut sf); + if attr.is_some() || !traits.is_empty() { + return self.collect_attr(attr, traits, Annotatable::StructField(sf), + AstFragmentKind::StructFields, after_derive) + .make_struct_fields(); + } + + noop_flat_map_struct_field(sf, self) + } + + fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> { + let mut variant = configure!(self, variant); + + let (attr, traits, after_derive) = self.classify_item(&mut variant); + if attr.is_some() || !traits.is_empty() { + return self.collect_attr(attr, traits, Annotatable::Variant(variant), + AstFragmentKind::Variants, after_derive) + .make_variants(); + } + + noop_flat_map_variant(variant, self) + } + fn filter_map_expr(&mut self, expr: P) -> Option> { let expr = configure!(self, expr); expr.filter_map(|mut expr| { - self.cfg.configure_expr_kind(&mut expr.node); + self.cfg.configure_expr_kind(&mut expr.kind); // Ignore derives so they remain unused. let (attr, after_derive) = self.classify_nonitem(&mut expr); @@ -976,7 +1152,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .map(|expr| expr.into_inner()) } - if let ast::ExprKind::Mac(mac) = expr.node { + if let ast::ExprKind::Mac(mac) = expr.kind { self.check_attributes(&expr.attrs); self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr) .make_opt_expr() @@ -989,13 +1165,13 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn visit_pat(&mut self, pat: &mut P) { self.cfg.configure_pat(pat); - match pat.node { + match pat.kind { PatKind::Mac(_) => {} _ => return noop_visit_pat(pat, self), } visit_clobber(pat, |mut pat| { - match mem::replace(&mut pat.node, PatKind::Wild) { + match mem::replace(&mut pat.kind, PatKind::Wild) { PatKind::Mac(mac) => self.collect_bang(mac, pat.span, AstFragmentKind::Pat).make_pat(), _ => unreachable!(), @@ -1023,7 +1199,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } } - if let StmtKind::Mac(mac) = stmt.node { + if let StmtKind::Mac(mac) = stmt.kind { let (mac, style, attrs) = mac.into_inner(); self.check_attributes(&attrs); let mut placeholder = self.collect_bang(mac, stmt.span, AstFragmentKind::Stmts) @@ -1041,9 +1217,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } // The placeholder expander gives ids to statements, so we avoid folding the id here. - let ast::Stmt { id, node, span } = stmt; - noop_flat_map_stmt_kind(node, self).into_iter().map(|node| { - ast::Stmt { id, node, span } + let ast::Stmt { id, kind, span } = stmt; + noop_flat_map_stmt_kind(kind, self).into_iter().map(|kind| { + ast::Stmt { id, kind, span } }).collect() } @@ -1064,10 +1240,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { AstFragmentKind::Items, after_derive).make_items(); } - match item.node { + match item.kind { ast::ItemKind::Mac(..) => { self.check_attributes(&item.attrs); - item.and_then(|item| match item.node { + item.and_then(|item| match item.kind { ItemKind::Mac(mac) => self.collect( AstFragmentKind::Items, InvocationKind::Bang { mac, span: item.span } ).make_items(), @@ -1135,7 +1311,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { AstFragmentKind::TraitItems, after_derive).make_trait_items() } - match item.node { + match item.kind { ast::TraitItemKind::Macro(mac) => { let ast::TraitItem { attrs, span, .. } = item; self.check_attributes(&attrs); @@ -1154,7 +1330,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { AstFragmentKind::ImplItems, after_derive).make_impl_items(); } - match item.node { + match item.kind { ast::ImplItemKind::Macro(mac) => { let ast::ImplItem { attrs, span, .. } = item; self.check_attributes(&attrs); @@ -1165,13 +1341,13 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } fn visit_ty(&mut self, ty: &mut P) { - match ty.node { + match ty.kind { ast::TyKind::Mac(_) => {} _ => return noop_visit_ty(ty, self), }; visit_clobber(ty, |mut ty| { - match mem::replace(&mut ty.node, ast::TyKind::Err) { + match mem::replace(&mut ty.kind, ast::TyKind::Err) { ast::TyKind::Mac(mac) => self.collect_bang(mac, ty.span, AstFragmentKind::Ty).make_ty(), _ => unreachable!(), @@ -1195,7 +1371,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_foreign_items(); } - if let ast::ForeignItemKind::Macro(mac) = foreign_item.node { + if let ast::ForeignItemKind::Macro(mac) = foreign_item.kind { self.check_attributes(&foreign_item.attrs); return self.collect_bang(mac, foreign_item.span, AstFragmentKind::ForeignItems) .make_foreign_items(); @@ -1214,9 +1390,21 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } } - fn visit_generic_params(&mut self, params: &mut Vec) { - self.cfg.configure_generic_params(params); - noop_visit_generic_params(params, self); + fn flat_map_generic_param( + &mut self, + param: ast::GenericParam + ) -> SmallVec<[ast::GenericParam; 1]> + { + let mut param = configure!(self, param); + + let (attr, traits, after_derive) = self.classify_item(&mut param); + if attr.is_some() || !traits.is_empty() { + return self.collect_attr(attr, traits, Annotatable::GenericParam(param), + AstFragmentKind::GenericParams, after_derive) + .make_generic_params(); + } + + noop_flat_map_generic_param(param, self) } fn visit_attribute(&mut self, at: &mut ast::Attribute) { @@ -1241,37 +1429,37 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { if let Some(file) = it.value_str() { let err_count = self.cx.parse_sess.span_diagnostic.err_count(); - self.check_attribute(&at); + self.check_attributes(slice::from_ref(at)); if self.cx.parse_sess.span_diagnostic.err_count() > err_count { // avoid loading the file if they haven't enabled the feature return noop_visit_attribute(at, self); } let filename = self.cx.resolve_path(&*file.as_str(), it.span()); - match fs::read_to_string(&filename) { - Ok(src) => { - let src_interned = Symbol::intern(&src); - - // Add this input file to the code map to make it available as - // dependency information - self.cx.source_map().new_source_file(filename.into(), src); + match self.cx.source_map().load_file(&filename) { + Ok(source_file) => { + let src = source_file.src.as_ref() + .expect("freshly loaded file should have a source"); + let src_interned = Symbol::intern(src.as_str()); let include_info = vec![ ast::NestedMetaItem::MetaItem( attr::mk_name_value_item_str( - Ident::with_empty_ctxt(sym::file), - dummy_spanned(file), + Ident::with_dummy_span(sym::file), + file, + DUMMY_SP, ), ), ast::NestedMetaItem::MetaItem( attr::mk_name_value_item_str( - Ident::with_empty_ctxt(sym::contents), - dummy_spanned(src_interned), + Ident::with_dummy_span(sym::contents), + src_interned, + DUMMY_SP, ), ), ]; - let include_ident = Ident::with_empty_ctxt(sym::include); + let include_ident = Ident::with_dummy_span(sym::include); let item = attr::mk_list_item(include_ident, include_info); items.push(ast::NestedMetaItem::MetaItem(item)); } @@ -1309,7 +1497,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { // Check if the user erroneously used `doc(include(...))` syntax. let literal = it.meta_item_list().and_then(|list| { if list.len() == 1 { - list[0].literal().map(|literal| &literal.node) + list[0].literal().map(|literal| &literal.kind) } else { None } @@ -1333,13 +1521,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } } - let meta = attr::mk_list_item(Ident::with_empty_ctxt(sym::doc), items); + let meta = attr::mk_list_item(Ident::with_dummy_span(sym::doc), items); *at = attr::Attribute { + item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) }, span: at.span, id: at.id, style: at.style, - path: meta.path, - tokens: meta.node.tokens(meta.span), is_sugared_doc: false, }; } else { @@ -1383,9 +1570,6 @@ impl<'feat> ExpansionConfig<'feat> { } } - fn macros_in_extern(&self) -> bool { - self.features.map_or(false, |features| features.macros_in_extern) - } fn proc_macro_hygiene(&self) -> bool { self.features.map_or(false, |features| features.proc_macro_hygiene) } @@ -1393,17 +1577,3 @@ impl<'feat> ExpansionConfig<'feat> { self.features.map_or(false, |features| features.custom_inner_attributes) } } - -// A Marker adds the given mark to the syntax context. -#[derive(Debug)] -pub struct Marker(pub ExpnId); - -impl MutVisitor for Marker { - fn visit_span(&mut self, span: &mut Span) { - *span = span.apply_mark(self.0) - } - - fn visit_mac(&mut self, mac: &mut ast::Mac) { - noop_visit_mac(mac, self) - } -} diff --git a/src/libsyntax/ext/mbe.rs b/src/libsyntax/ext/mbe.rs new file mode 100644 index 0000000000000..a87da791c9b4f --- /dev/null +++ b/src/libsyntax/ext/mbe.rs @@ -0,0 +1,166 @@ +//! This module implements declarative macros: old `macro_rules` and the newer +//! `macro`. Declarative macros are also known as "macro by example", and that's +//! why we call this module `mbe`. For external documentation, prefer the +//! official terminology: "declarative macros". + +crate mod transcribe; +crate mod macro_check; +crate mod macro_parser; +crate mod macro_rules; +crate mod quoted; + +use crate::ast; +use crate::parse::token::{self, Token, TokenKind}; +use crate::tokenstream::{DelimSpan}; + +use syntax_pos::{BytePos, Span}; + +use rustc_data_structures::sync::Lrc; + +/// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note +/// that the delimiter itself might be `NoDelim`. +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] +struct Delimited { + delim: token::DelimToken, + tts: Vec, +} + +impl Delimited { + /// Returns a `self::TokenTree` with a `Span` corresponding to the opening delimiter. + fn open_tt(&self, span: Span) -> TokenTree { + let open_span = if span.is_dummy() { + span + } else { + span.with_hi(span.lo() + BytePos(self.delim.len() as u32)) + }; + TokenTree::token(token::OpenDelim(self.delim), open_span) + } + + /// Returns a `self::TokenTree` with a `Span` corresponding to the closing delimiter. + fn close_tt(&self, span: Span) -> TokenTree { + let close_span = if span.is_dummy() { + span + } else { + span.with_lo(span.hi() - BytePos(self.delim.len() as u32)) + }; + TokenTree::token(token::CloseDelim(self.delim), close_span) + } +} + +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] +struct SequenceRepetition { + /// The sequence of token trees + tts: Vec, + /// The optional separator + separator: Option, + /// Whether the sequence can be repeated zero (*), or one or more times (+) + kleene: KleeneToken, + /// The number of `Match`s that appear in the sequence (and subsequences) + num_captures: usize, +} + +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)] +struct KleeneToken { + span: Span, + op: KleeneOp, +} + +impl KleeneToken { + fn new(op: KleeneOp, span: Span) -> KleeneToken { + KleeneToken { span, op } + } +} + +/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star) +/// for token sequences. +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +enum KleeneOp { + /// Kleene star (`*`) for zero or more repetitions + ZeroOrMore, + /// Kleene plus (`+`) for one or more repetitions + OneOrMore, + /// Kleene optional (`?`) for zero or one reptitions + ZeroOrOne, +} + +/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)` +/// are "first-class" token trees. Useful for parsing macros. +#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)] +enum TokenTree { + Token(Token), + Delimited(DelimSpan, Lrc), + /// A kleene-style repetition sequence + Sequence(DelimSpan, Lrc), + /// e.g., `$var` + MetaVar(Span, ast::Ident), + /// e.g., `$var:expr`. This is only used in the left hand side of MBE macros. + MetaVarDecl( + Span, + ast::Ident, /* name to bind */ + ast::Ident, /* kind of nonterminal */ + ), +} + +impl TokenTree { + /// Return the number of tokens in the tree. + fn len(&self) -> usize { + match *self { + TokenTree::Delimited(_, ref delimed) => match delimed.delim { + token::NoDelim => delimed.tts.len(), + _ => delimed.tts.len() + 2, + }, + TokenTree::Sequence(_, ref seq) => seq.tts.len(), + _ => 0, + } + } + + /// Returns `true` if the given token tree is delimited. + fn is_delimited(&self) -> bool { + match *self { + TokenTree::Delimited(..) => true, + _ => false, + } + } + + /// Returns `true` if the given token tree is a token of the given kind. + fn is_token(&self, expected_kind: &TokenKind) -> bool { + match self { + TokenTree::Token(Token { kind: actual_kind, .. }) => actual_kind == expected_kind, + _ => false, + } + } + + /// Gets the `index`-th sub-token-tree. This only makes sense for delimited trees and sequences. + fn get_tt(&self, index: usize) -> TokenTree { + match (self, index) { + (&TokenTree::Delimited(_, ref delimed), _) if delimed.delim == token::NoDelim => { + delimed.tts[index].clone() + } + (&TokenTree::Delimited(span, ref delimed), _) => { + if index == 0 { + return delimed.open_tt(span.open); + } + if index == delimed.tts.len() + 1 { + return delimed.close_tt(span.close); + } + delimed.tts[index - 1].clone() + } + (&TokenTree::Sequence(_, ref seq), _) => seq.tts[index].clone(), + _ => panic!("Cannot expand a token tree"), + } + } + + /// Retrieves the `TokenTree`'s span. + fn span(&self) -> Span { + match *self { + TokenTree::Token(Token { span, .. }) + | TokenTree::MetaVar(span, _) + | TokenTree::MetaVarDecl(span, _, _) => span, + TokenTree::Delimited(span, _) | TokenTree::Sequence(span, _) => span.entire(), + } + } + + fn token(kind: TokenKind, span: Span) -> TokenTree { + TokenTree::Token(Token::new(kind, span)) + } +} diff --git a/src/libsyntax/ext/tt/macro_check.rs b/src/libsyntax/ext/mbe/macro_check.rs similarity index 99% rename from src/libsyntax/ext/tt/macro_check.rs rename to src/libsyntax/ext/mbe/macro_check.rs index 5af97199902e6..97074f5cbe46c 100644 --- a/src/libsyntax/ext/tt/macro_check.rs +++ b/src/libsyntax/ext/mbe/macro_check.rs @@ -106,7 +106,7 @@ //! bound. use crate::ast::NodeId; use crate::early_buffered_lints::BufferedEarlyLintId; -use crate::ext::tt::quoted::{KleeneToken, TokenTree}; +use crate::ext::mbe::{KleeneToken, TokenTree}; use crate::parse::token::TokenKind; use crate::parse::token::{DelimToken, Token}; use crate::parse::ParseSess; @@ -196,7 +196,7 @@ struct MacroState<'a> { /// - `node_id` is used to emit lints /// - `span` is used when no spans are available /// - `lhses` and `rhses` should have the same length and represent the macro definition -pub fn check_meta_variables( +pub(super) fn check_meta_variables( sess: &ParseSess, node_id: NodeId, span: Span, diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/mbe/macro_parser.rs similarity index 97% rename from src/libsyntax/ext/tt/macro_parser.rs rename to src/libsyntax/ext/mbe/macro_parser.rs index dbf14daa30e75..d1c50fd85945d 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/mbe/macro_parser.rs @@ -70,12 +70,12 @@ //! eof: [a $( a )* a b ·] //! ``` -pub use NamedMatch::*; -pub use ParseResult::*; +crate use NamedMatch::*; +crate use ParseResult::*; use TokenTreeOrTokenTreeSlice::*; use crate::ast::{Ident, Name}; -use crate::ext::tt::quoted::{self, TokenTree}; +use crate::ext::mbe::{self, TokenTree}; use crate::parse::{Directory, ParseSess}; use crate::parse::parser::{Parser, PathStyle}; use crate::parse::token::{self, DocComment, Nonterminal, Token}; @@ -195,7 +195,7 @@ struct MatcherPos<'root, 'tt> { // `None`. /// The KleeneOp of this sequence if we are in a repetition. - seq_op: Option, + seq_op: Option, /// The separator if we are in a repetition. sep: Option, @@ -267,7 +267,7 @@ impl<'root, 'tt> DerefMut for MatcherPosHandle<'root, 'tt> { } /// Represents the possible results of an attempted parse. -pub enum ParseResult { +crate enum ParseResult { /// Parsed successfully. Success(T), /// Arm failed to match. If the second parameter is `token::Eof`, it indicates an unexpected @@ -279,10 +279,10 @@ pub enum ParseResult { /// A `ParseResult` where the `Success` variant contains a mapping of `Ident`s to `NamedMatch`es. /// This represents the mapping of metavars to the token trees they bind to. -pub type NamedParseResult = ParseResult>; +crate type NamedParseResult = ParseResult>; /// Count how many metavars are named in the given matcher `ms`. -pub fn count_names(ms: &[TokenTree]) -> usize { +pub(super) fn count_names(ms: &[TokenTree]) -> usize { ms.iter().fold(0, |count, elt| { count + match *elt { TokenTree::Sequence(_, ref seq) => seq.num_captures, @@ -352,7 +352,7 @@ fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree], open: Span) -> MatcherP /// only on the nesting depth of `ast::TTSeq`s in the originating /// token tree it was derived from. #[derive(Debug, Clone)] -pub enum NamedMatch { +crate enum NamedMatch { MatchedSeq(Lrc, DelimSpan), MatchedNonterminal(Lrc), } @@ -413,18 +413,6 @@ fn nameize>( Success(ret_val) } -/// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For -/// other tokens, this is "unexpected token...". -pub fn parse_failure_msg(tok: &Token) -> String { - match tok.kind { - token::Eof => "unexpected end of macro invocation".to_string(), - _ => format!( - "no rules expected the token `{}`", - pprust::token_to_string(tok) - ), - } -} - /// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison) fn token_name_eq(t1: &Token, t2: &Token) -> bool { if let (Some((ident1, is_raw1)), Some((ident2, is_raw2))) = (t1.ident(), t2.ident()) { @@ -532,7 +520,7 @@ fn inner_parse_loop<'root, 'tt>( } // We don't need a separator. Move the "dot" back to the beginning of the matcher // and try to match again UNLESS we are only allowed to have _one_ repetition. - else if item.seq_op != Some(quoted::KleeneOp::ZeroOrOne) { + else if item.seq_op != Some(mbe::KleeneOp::ZeroOrOne) { item.match_cur = item.match_lo; item.idx = 0; cur_items.push(item); @@ -555,8 +543,8 @@ fn inner_parse_loop<'root, 'tt>( // implicitly disallowing OneOrMore from having 0 matches here. Thus, that will // result in a "no rules expected token" error by virtue of this matcher not // working. - if seq.kleene.op == quoted::KleeneOp::ZeroOrMore - || seq.kleene.op == quoted::KleeneOp::ZeroOrOne + if seq.kleene.op == mbe::KleeneOp::ZeroOrMore + || seq.kleene.op == mbe::KleeneOp::ZeroOrOne { let mut new_item = item.clone(); new_item.match_cur += seq.num_captures; @@ -648,7 +636,7 @@ fn inner_parse_loop<'root, 'tt>( /// - `directory`: Information about the file locations (needed for the black-box parser) /// - `recurse_into_modules`: Whether or not to recurse into modules (needed for the black-box /// parser) -pub fn parse( +pub(super) fn parse( sess: &ParseSess, tts: TokenStream, ms: &[TokenTree], @@ -936,7 +924,7 @@ fn parse_nt(p: &mut Parser<'_>, sp: Span, name: Symbol) -> Nonterminal { FatalError.raise() } sym::path => token::NtPath(panictry!(p.parse_path(PathStyle::Type))), - sym::meta => token::NtMeta(panictry!(p.parse_meta_item())), + sym::meta => token::NtMeta(panictry!(p.parse_attr_item())), sym::vis => token::NtVis(panictry!(p.parse_visibility(true))), sym::lifetime => if p.check_lifetime() { token::NtLifetime(p.expect_lifetime().ident) diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/mbe/macro_rules.rs similarity index 82% rename from src/libsyntax/ext/tt/macro_rules.rs rename to src/libsyntax/ext/mbe/macro_rules.rs index 7401f25641236..aec4a68314120 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/mbe/macro_rules.rs @@ -1,24 +1,27 @@ +use crate::ast; +use crate::attr::{self, TransparencyError}; use crate::edition::Edition; use crate::ext::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander}; use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind}; use crate::ext::expand::{AstFragment, AstFragmentKind}; -use crate::ext::tt::macro_check; -use crate::ext::tt::macro_parser::{parse, parse_failure_msg}; -use crate::ext::tt::macro_parser::{Error, Failure, Success}; -use crate::ext::tt::macro_parser::{MatchedNonterminal, MatchedSeq}; -use crate::ext::tt::quoted; -use crate::ext::tt::transcribe::transcribe; +use crate::ext::mbe; +use crate::ext::mbe::macro_check; +use crate::ext::mbe::macro_parser::parse; +use crate::ext::mbe::macro_parser::{Error, Failure, Success}; +use crate::ext::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedParseResult}; +use crate::ext::mbe::transcribe::transcribe; use crate::feature_gate::Features; use crate::parse::parser::Parser; use crate::parse::token::TokenKind::*; use crate::parse::token::{self, NtTT, Token}; use crate::parse::{Directory, ParseSess}; +use crate::print::pprust; use crate::symbol::{kw, sym, Symbol}; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree}; -use crate::{ast, attr, attr::TransparencyError}; -use errors::FatalError; +use errors::{DiagnosticBuilder, FatalError}; use log::debug; +use syntax_pos::hygiene::Transparency; use syntax_pos::Span; use rustc_data_structures::fx::FxHashMap; @@ -33,7 +36,7 @@ const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \ `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \ `literal`, `path`, `meta`, `tt`, `item` and `vis`"; -pub struct ParserAnyMacro<'a> { +crate struct ParserAnyMacro<'a> { parser: Parser<'a>, /// Span of the expansion site of the macro this parser is for @@ -43,8 +46,24 @@ pub struct ParserAnyMacro<'a> { arm_span: Span, } +crate fn annotate_err_with_kind( + err: &mut DiagnosticBuilder<'_>, + kind: AstFragmentKind, + span: Span, +) { + match kind { + AstFragmentKind::Ty => { + err.span_label(span, "this macro call doesn't expand to a type"); + } + AstFragmentKind::Pat => { + err.span_label(span, "this macro call doesn't expand to a pattern"); + } + _ => {} + }; +} + impl<'a> ParserAnyMacro<'a> { - pub fn make(mut self: Box>, kind: AstFragmentKind) -> AstFragment { + crate fn make(mut self: Box>, kind: AstFragmentKind) -> AstFragment { let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self; let fragment = panictry!(parser.parse_ast_fragment(kind, true).map_err(|mut e| { if parser.token == token::Eof && e.message().ends_with(", found ``") { @@ -70,6 +89,32 @@ impl<'a> ParserAnyMacro<'a> { } else if !parser.sess.source_map().span_to_filename(parser.token.span).is_real() { e.span_label(site_span, "in this macro invocation"); } + match kind { + AstFragmentKind::Pat if macro_ident.name == sym::vec => { + let mut suggestion = None; + if let Ok(code) = parser.sess.source_map().span_to_snippet(site_span) { + if let Some(bang) = code.find('!') { + suggestion = Some(code[bang + 1..].to_string()); + } + } + if let Some(suggestion) = suggestion { + e.span_suggestion( + site_span, + "use a slice pattern here instead", + suggestion, + Applicability::MachineApplicable, + ); + } else { + e.span_label( + site_span, + "use a slice pattern here instead", + ); + } + e.help("for more information, see https://doc.rust-lang.org/edition-guide/\ + rust-2018/slice-patterns.html"); + } + _ => annotate_err_with_kind(&mut e, kind, site_span), + }; e })); @@ -90,8 +135,9 @@ impl<'a> ParserAnyMacro<'a> { struct MacroRulesMacroExpander { name: ast::Ident, span: Span, - lhses: Vec, - rhses: Vec, + transparency: Transparency, + lhses: Vec, + rhses: Vec, valid: bool, } @@ -105,7 +151,9 @@ impl TTMacroExpander for MacroRulesMacroExpander { if !self.valid { return DummyResult::any(sp); } - generic_extension(cx, sp, self.span, self.name, input, &self.lhses, &self.rhses) + generic_extension( + cx, sp, self.span, self.name, self.transparency, input, &self.lhses, &self.rhses + ) } } @@ -120,9 +168,10 @@ fn generic_extension<'cx>( sp: Span, def_span: Span, name: ast::Ident, + transparency: Transparency, arg: TokenStream, - lhses: &[quoted::TokenTree], - rhses: &[quoted::TokenTree], + lhses: &[mbe::TokenTree], + rhses: &[mbe::TokenTree], ) -> Box { if cx.trace_macros() { trace_macros_note(cx, sp, format!("expanding `{}! {{ {} }}`", name, arg)); @@ -134,7 +183,7 @@ fn generic_extension<'cx>( for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers let lhs_tt = match *lhs { - quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..], + mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..], _ => cx.span_bug(sp, "malformed macro lhs"), }; @@ -142,14 +191,14 @@ fn generic_extension<'cx>( Success(named_matches) => { let rhs = match rhses[i] { // ignore delimiters - quoted::TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(), + mbe::TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(), _ => cx.span_bug(sp, "malformed macro rhs"), }; let arm_span = rhses[i].span(); let rhs_spans = rhs.iter().map(|t| t.span()).collect::>(); // rhs has holes ( `$id` and `$(...)` that need filled) - let mut tts = transcribe(cx, &named_matches, rhs); + let mut tts = transcribe(cx, &named_matches, rhs, transparency); // Replace all the tokens for the corresponding positions in the macro, to maintain // proper positions in error reporting, while maintaining the macro_backtrace. @@ -210,7 +259,7 @@ fn generic_extension<'cx>( for lhs in lhses { // try each arm's matchers let lhs_tt = match *lhs { - quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..], + mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..], _ => continue, }; match TokenTree::parse(cx, lhs_tt, arg.clone()) { @@ -240,19 +289,20 @@ fn generic_extension<'cx>( // // Holy self-referential! -/// Converts a `macro_rules!` invocation into a syntax extension. -pub fn compile( +/// Converts a macro item into a syntax extension. +pub fn compile_declarative_macro( sess: &ParseSess, features: &Features, def: &ast::Item, edition: Edition, ) -> SyntaxExtension { + let diag = &sess.span_diagnostic; let lhs_nm = ast::Ident::new(sym::lhs, def.span); let rhs_nm = ast::Ident::new(sym::rhs, def.span); let tt_spec = ast::Ident::new(sym::tt, def.span); // Parse the macro_rules! invocation - let body = match def.node { + let body = match def.kind { ast::ItemKind::MacroDef(ref body) => body, _ => unreachable!(), }; @@ -263,32 +313,32 @@ pub fn compile( // ...quasiquoting this would be nice. // These spans won't matter, anyways let argument_gram = vec![ - quoted::TokenTree::Sequence( + mbe::TokenTree::Sequence( DelimSpan::dummy(), - Lrc::new(quoted::SequenceRepetition { + Lrc::new(mbe::SequenceRepetition { tts: vec![ - quoted::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec), - quoted::TokenTree::token(token::FatArrow, def.span), - quoted::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec), + mbe::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec), + mbe::TokenTree::token(token::FatArrow, def.span), + mbe::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec), ], separator: Some(Token::new( if body.legacy { token::Semi } else { token::Comma }, def.span, )), - kleene: quoted::KleeneToken::new(quoted::KleeneOp::OneOrMore, def.span), + kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, def.span), num_captures: 2, }), ), // to phase into semicolon-termination instead of semicolon-separation - quoted::TokenTree::Sequence( + mbe::TokenTree::Sequence( DelimSpan::dummy(), - Lrc::new(quoted::SequenceRepetition { - tts: vec![quoted::TokenTree::token( + Lrc::new(mbe::SequenceRepetition { + tts: vec![mbe::TokenTree::token( if body.legacy { token::Semi } else { token::Comma }, def.span, )], separator: None, - kleene: quoted::KleeneToken::new(quoted::KleeneOp::ZeroOrMore, def.span), + kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, def.span), num_captures: 0, }), ), @@ -318,14 +368,10 @@ pub fn compile( .map(|m| { if let MatchedNonterminal(ref nt) = *m { if let NtTT(ref tt) = **nt { - let tt = quoted::parse( + let tt = mbe::quoted::parse( tt.clone().into(), true, sess, - features, - &def.attrs, - edition, - def.id, ) .pop() .unwrap(); @@ -335,7 +381,7 @@ pub fn compile( } sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") }) - .collect::>(), + .collect::>(), _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"), }; @@ -345,14 +391,10 @@ pub fn compile( .map(|m| { if let MatchedNonterminal(ref nt) = *m { if let NtTT(ref tt) = **nt { - return quoted::parse( + return mbe::quoted::parse( tt.clone().into(), false, sess, - features, - &def.attrs, - edition, - def.id, ) .pop() .unwrap(); @@ -360,7 +402,7 @@ pub fn compile( } sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") }) - .collect::>(), + .collect::>(), _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"), }; @@ -377,86 +419,39 @@ pub fn compile( // that is not lint-checked and trigger the "failed to process buffered lint here" bug. valid &= macro_check::check_meta_variables(sess, ast::CRATE_NODE_ID, def.span, &lhses, &rhses); - let expander: Box<_> = - Box::new(MacroRulesMacroExpander { name: def.ident, span: def.span, lhses, rhses, valid }); - - let (default_transparency, transparency_error) = - attr::find_transparency(&def.attrs, body.legacy); + let (transparency, transparency_error) = attr::find_transparency(&def.attrs, body.legacy); match transparency_error { Some(TransparencyError::UnknownTransparency(value, span)) => - sess.span_diagnostic.span_err( - span, &format!("unknown macro transparency: `{}`", value) - ), + diag.span_err(span, &format!("unknown macro transparency: `{}`", value)), Some(TransparencyError::MultipleTransparencyAttrs(old_span, new_span)) => - sess.span_diagnostic.span_err( - vec![old_span, new_span], "multiple macro transparency attributes" - ), + diag.span_err(vec![old_span, new_span], "multiple macro transparency attributes"), None => {} } - let allow_internal_unstable = - attr::find_by_name(&def.attrs, sym::allow_internal_unstable).map(|attr| { - attr.meta_item_list() - .map(|list| { - list.iter() - .filter_map(|it| { - let name = it.ident().map(|ident| ident.name); - if name.is_none() { - sess.span_diagnostic.span_err( - it.span(), - "allow internal unstable expects feature names", - ) - } - name - }) - .collect::>() - .into() - }) - .unwrap_or_else(|| { - sess.span_diagnostic.span_warn( - attr.span, - "allow_internal_unstable expects list of feature names. In the \ - future this will become a hard error. Please use `allow_internal_unstable(\ - foo, bar)` to only allow the `foo` and `bar` features", - ); - vec![sym::allow_internal_unstable_backcompat_hack].into() - }) - }); - - let mut local_inner_macros = false; - if let Some(macro_export) = attr::find_by_name(&def.attrs, sym::macro_export) { - if let Some(l) = macro_export.meta_item_list() { - local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros); - } - } + let expander: Box<_> = Box::new(MacroRulesMacroExpander { + name: def.ident, span: def.span, transparency, lhses, rhses, valid + }); - let is_builtin = attr::contains_name(&def.attrs, sym::rustc_builtin_macro); - - SyntaxExtension { - kind: SyntaxExtensionKind::LegacyBang(expander), - span: def.span, - default_transparency, - allow_internal_unstable, - allow_internal_unsafe: attr::contains_name(&def.attrs, sym::allow_internal_unsafe), - local_inner_macros, - stability: attr::find_stability(&sess, &def.attrs, def.span), - deprecation: attr::find_deprecation(&sess, &def.attrs, def.span), - helper_attrs: Vec::new(), + SyntaxExtension::new( + sess, + SyntaxExtensionKind::LegacyBang(expander), + def.span, + Vec::new(), edition, - is_builtin, - is_derive_copy: is_builtin && def.ident.name == sym::Copy, - } + def.ident.name, + &def.attrs, + ) } fn check_lhs_nt_follows( sess: &ParseSess, features: &Features, attrs: &[ast::Attribute], - lhs: "ed::TokenTree, + lhs: &mbe::TokenTree, ) -> bool { // lhs is going to be like TokenTree::Delimited(...), where the // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens. - if let quoted::TokenTree::Delimited(_, ref tts) = *lhs { + if let mbe::TokenTree::Delimited(_, ref tts) = *lhs { check_matcher(sess, features, attrs, &tts.tts) } else { let msg = "invalid macro matcher; matchers must be contained in balanced delimiters"; @@ -469,8 +464,8 @@ fn check_lhs_nt_follows( /// Checks that the lhs contains no repetition which could match an empty token /// tree, because then the matcher would hang indefinitely. -fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool { - use quoted::TokenTree; +fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool { + use mbe::TokenTree; for tt in tts { match *tt { TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => (), @@ -484,8 +479,8 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool { && seq.tts.iter().all(|seq_tt| match *seq_tt { TokenTree::MetaVarDecl(_, _, id) => id.name == sym::vis, TokenTree::Sequence(_, ref sub_seq) => { - sub_seq.kleene.op == quoted::KleeneOp::ZeroOrMore - || sub_seq.kleene.op == quoted::KleeneOp::ZeroOrOne + sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore + || sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne } _ => false, }) @@ -504,9 +499,9 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool { true } -fn check_rhs(sess: &ParseSess, rhs: "ed::TokenTree) -> bool { +fn check_rhs(sess: &ParseSess, rhs: &mbe::TokenTree) -> bool { match *rhs { - quoted::TokenTree::Delimited(..) => return true, + mbe::TokenTree::Delimited(..) => return true, _ => sess.span_diagnostic.span_err(rhs.span(), "macro rhs must be delimited"), } false @@ -516,7 +511,7 @@ fn check_matcher( sess: &ParseSess, features: &Features, attrs: &[ast::Attribute], - matcher: &[quoted::TokenTree], + matcher: &[mbe::TokenTree], ) -> bool { let first_sets = FirstSets::new(matcher); let empty_suffix = TokenSet::empty(); @@ -548,8 +543,8 @@ struct FirstSets { } impl FirstSets { - fn new(tts: &[quoted::TokenTree]) -> FirstSets { - use quoted::TokenTree; + fn new(tts: &[mbe::TokenTree]) -> FirstSets { + use mbe::TokenTree; let mut sets = FirstSets { first: FxHashMap::default() }; build_recur(&mut sets, tts); @@ -596,8 +591,8 @@ impl FirstSets { // Reverse scan: Sequence comes before `first`. if subfirst.maybe_empty - || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore - || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne + || seq_rep.kleene.op == mbe::KleeneOp::ZeroOrMore + || seq_rep.kleene.op == mbe::KleeneOp::ZeroOrOne { // If sequence is potentially empty, then // union them (preserving first emptiness). @@ -617,8 +612,8 @@ impl FirstSets { // walks forward over `tts` until all potential FIRST tokens are // identified. - fn first(&self, tts: &[quoted::TokenTree]) -> TokenSet { - use quoted::TokenTree; + fn first(&self, tts: &[mbe::TokenTree]) -> TokenSet { + use mbe::TokenTree; let mut first = TokenSet::empty(); for tt in tts.iter() { @@ -654,8 +649,8 @@ impl FirstSets { assert!(first.maybe_empty); first.add_all(subfirst); if subfirst.maybe_empty - || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore - || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne + || seq_rep.kleene.op == mbe::KleeneOp::ZeroOrMore + || seq_rep.kleene.op == mbe::KleeneOp::ZeroOrOne { // Continue scanning for more first // tokens, but also make sure we @@ -676,7 +671,7 @@ impl FirstSets { } } -// A set of `quoted::TokenTree`s, which may include `TokenTree::Match`s +// A set of `mbe::TokenTree`s, which may include `TokenTree::Match`s // (for macro-by-example syntactic variables). It also carries the // `maybe_empty` flag; that is true if and only if the matcher can // match an empty token sequence. @@ -688,7 +683,7 @@ impl FirstSets { // (Notably, we must allow for *-op to occur zero times.) #[derive(Clone, Debug)] struct TokenSet { - tokens: Vec, + tokens: Vec, maybe_empty: bool, } @@ -700,13 +695,13 @@ impl TokenSet { // Returns the set `{ tok }` for the single-token (and thus // non-empty) sequence [tok]. - fn singleton(tok: quoted::TokenTree) -> Self { + fn singleton(tok: mbe::TokenTree) -> Self { TokenSet { tokens: vec![tok], maybe_empty: false } } // Changes self to be the set `{ tok }`. // Since `tok` is always present, marks self as non-empty. - fn replace_with(&mut self, tok: quoted::TokenTree) { + fn replace_with(&mut self, tok: mbe::TokenTree) { self.tokens.clear(); self.tokens.push(tok); self.maybe_empty = false; @@ -721,7 +716,7 @@ impl TokenSet { } // Adds `tok` to the set for `self`, marking sequence as non-empy. - fn add_one(&mut self, tok: quoted::TokenTree) { + fn add_one(&mut self, tok: mbe::TokenTree) { if !self.tokens.contains(&tok) { self.tokens.push(tok); } @@ -729,7 +724,7 @@ impl TokenSet { } // Adds `tok` to the set for `self`. (Leaves `maybe_empty` flag alone.) - fn add_one_maybe(&mut self, tok: quoted::TokenTree) { + fn add_one_maybe(&mut self, tok: mbe::TokenTree) { if !self.tokens.contains(&tok) { self.tokens.push(tok); } @@ -770,10 +765,10 @@ fn check_matcher_core( features: &Features, attrs: &[ast::Attribute], first_sets: &FirstSets, - matcher: &[quoted::TokenTree], + matcher: &[mbe::TokenTree], follow: &TokenSet, ) -> TokenSet { - use quoted::TokenTree; + use mbe::TokenTree; let mut last = TokenSet::empty(); @@ -879,9 +874,9 @@ fn check_matcher_core( // Now `last` holds the complete set of NT tokens that could // end the sequence before SUFFIX. Check that every one works with `suffix`. 'each_last: for token in &last.tokens { - if let TokenTree::MetaVarDecl(_, ref name, ref frag_spec) = *token { + if let TokenTree::MetaVarDecl(_, name, frag_spec) = *token { for next_token in &suffix_first.tokens { - match is_in_follow(next_token, &frag_spec.as_str()) { + match is_in_follow(next_token, frag_spec.name) { IsInFollow::Invalid(msg, help) => { sess.span_diagnostic .struct_span_err(next_token.span(), &msg) @@ -948,9 +943,9 @@ fn check_matcher_core( last } -fn token_can_be_followed_by_any(tok: "ed::TokenTree) -> bool { - if let quoted::TokenTree::MetaVarDecl(_, _, frag_spec) = *tok { - frag_can_be_followed_by_any(&frag_spec.as_str()) +fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool { + if let mbe::TokenTree::MetaVarDecl(_, _, frag_spec) = *tok { + frag_can_be_followed_by_any(frag_spec.name) } else { // (Non NT's can always be followed by anthing in matchers.) true @@ -965,15 +960,15 @@ fn token_can_be_followed_by_any(tok: "ed::TokenTree) -> bool { /// specifier which consumes at most one token tree can be followed by /// a fragment specifier (indeed, these fragments can be followed by /// ANYTHING without fear of future compatibility hazards). -fn frag_can_be_followed_by_any(frag: &str) -> bool { +fn frag_can_be_followed_by_any(frag: Symbol) -> bool { match frag { - "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 + sym::item | // always terminated by `}` or `;` + sym::block | // exactly one token tree + sym::ident | // exactly one token tree + sym::literal | // exactly one token tree + sym::meta | // exactly one token tree + sym::lifetime | // exactly one token tree + sym::tt => // exactly one token tree true, _ => @@ -995,8 +990,8 @@ enum IsInFollow { /// break macros that were relying on that binary operator as a /// separator. // when changing this do not forget to update doc/book/macros.md! -fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> IsInFollow { - use quoted::TokenTree; +fn is_in_follow(tok: &mbe::TokenTree, frag: Symbol) -> IsInFollow { + use mbe::TokenTree; if let TokenTree::Token(Token { kind: token::CloseDelim(_), .. }) = *tok { // closing a token tree can never be matched by any fragment; @@ -1004,17 +999,17 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> IsInFollow { IsInFollow::Yes } else { match frag { - "item" => { + sym::item => { // since items *must* be followed by either a `;` or a `}`, we can // accept anything after them IsInFollow::Yes } - "block" => { + sym::block => { // anything can follow block, the braces provide an easy boundary to // maintain IsInFollow::Yes } - "stmt" | "expr" => { + sym::stmt | sym::expr => { const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"]; match tok { TokenTree::Token(token) => match token.kind { @@ -1024,7 +1019,7 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> IsInFollow { _ => IsInFollow::No(TOKENS), } } - "pat" => { + sym::pat => { const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"]; match tok { TokenTree::Token(token) => match token.kind { @@ -1035,7 +1030,7 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> IsInFollow { _ => IsInFollow::No(TOKENS), } } - "path" | "ty" => { + sym::path | sym::ty => { const TOKENS: &[&str] = &[ "`{`", "`[`", "`=>`", "`,`", "`>`", "`=`", "`:`", "`;`", "`|`", "`as`", "`where`", @@ -1063,20 +1058,20 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> IsInFollow { _ => IsInFollow::No(TOKENS), } } - "ident" | "lifetime" => { + sym::ident | sym::lifetime => { // being a single token, idents and lifetimes are harmless IsInFollow::Yes } - "literal" => { + sym::literal => { // literals may be of a single token, or two tokens (negative numbers) IsInFollow::Yes } - "meta" | "tt" => { + sym::meta | sym::tt => { // being either a single token or a delimited sequence, tt is // harmless IsInFollow::Yes } - "vis" => { + sym::vis => { // Explicitly disallow `priv`, on the off chance it comes back. const TOKENS: &[&str] = &["`,`", "an ident", "a type"]; match tok { @@ -1101,7 +1096,7 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> IsInFollow { _ => IsInFollow::No(TOKENS), } } - "" => IsInFollow::Yes, // kw::Invalid + kw::Invalid => IsInFollow::Yes, _ => IsInFollow::Invalid( format!("invalid fragment specifier `{}`", frag), VALID_FRAGMENT_NAMES_MSG, @@ -1114,10 +1109,10 @@ fn has_legal_fragment_specifier( sess: &ParseSess, features: &Features, attrs: &[ast::Attribute], - tok: "ed::TokenTree, + tok: &mbe::TokenTree, ) -> Result<(), String> { debug!("has_legal_fragment_specifier({:?})", tok); - if let quoted::TokenTree::MetaVarDecl(_, _, ref frag_spec) = *tok { + if let mbe::TokenTree::MetaVarDecl(_, _, ref frag_spec) = *tok { let frag_span = tok.span(); if !is_legal_fragment_specifier(sess, features, attrs, frag_spec.name, frag_span) { return Err(frag_spec.to_string()); @@ -1158,14 +1153,39 @@ fn is_legal_fragment_specifier( } } -fn quoted_tt_to_string(tt: "ed::TokenTree) -> String { +fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { match *tt { - quoted::TokenTree::Token(ref token) => crate::print::pprust::token_to_string(&token), - quoted::TokenTree::MetaVar(_, name) => format!("${}", name), - quoted::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind), + mbe::TokenTree::Token(ref token) => crate::print::pprust::token_to_string(&token), + mbe::TokenTree::MetaVar(_, name) => format!("${}", name), + mbe::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind), _ => panic!( - "unexpected quoted::TokenTree::{{Sequence or Delimited}} \ + "unexpected mbe::TokenTree::{{Sequence or Delimited}} \ in follow set checker" ), } } + +impl TokenTree { + /// Use this token tree as a matcher to parse given tts. + fn parse(cx: &ExtCtxt<'_>, mtch: &[mbe::TokenTree], tts: TokenStream) + -> NamedParseResult { + // `None` is because we're not interpolating + let directory = Directory { + path: Cow::from(cx.current_expansion.module.directory.as_path()), + ownership: cx.current_expansion.directory_ownership, + }; + parse(cx.parse_sess(), tts, mtch, Some(directory), true) + } +} + +/// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For +/// other tokens, this is "unexpected token...". +fn parse_failure_msg(tok: &Token) -> String { + match tok.kind { + token::Eof => "unexpected end of macro invocation".to_string(), + _ => format!( + "no rules expected the token `{}`", + pprust::token_to_string(tok), + ), + } +} diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/mbe/quoted.rs similarity index 63% rename from src/libsyntax/ext/tt/quoted.rs rename to src/libsyntax/ext/mbe/quoted.rs index cad94a0e4c120..8cb85bdef762f 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/mbe/quoted.rs @@ -1,178 +1,15 @@ use crate::ast; -use crate::ast::NodeId; -use crate::ext::tt::macro_parser; -use crate::feature_gate::Features; -use crate::parse::token::{self, Token, TokenKind}; +use crate::ext::mbe::macro_parser; +use crate::ext::mbe::{TokenTree, KleeneOp, KleeneToken, SequenceRepetition, Delimited}; +use crate::parse::token::{self, Token}; use crate::parse::ParseSess; use crate::print::pprust; use crate::symbol::kw; -use crate::tokenstream::{self, DelimSpan}; +use crate::tokenstream; -use syntax_pos::{edition::Edition, BytePos, Span}; +use syntax_pos::Span; use rustc_data_structures::sync::Lrc; -use std::iter::Peekable; - -/// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note -/// that the delimiter itself might be `NoDelim`. -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] -pub struct Delimited { - pub delim: token::DelimToken, - pub tts: Vec, -} - -impl Delimited { - /// Returns a `self::TokenTree` with a `Span` corresponding to the opening delimiter. - pub fn open_tt(&self, span: Span) -> TokenTree { - let open_span = if span.is_dummy() { - span - } else { - span.with_hi(span.lo() + BytePos(self.delim.len() as u32)) - }; - TokenTree::token(token::OpenDelim(self.delim), open_span) - } - - /// Returns a `self::TokenTree` with a `Span` corresponding to the closing delimiter. - pub fn close_tt(&self, span: Span) -> TokenTree { - let close_span = if span.is_dummy() { - span - } else { - span.with_lo(span.hi() - BytePos(self.delim.len() as u32)) - }; - TokenTree::token(token::CloseDelim(self.delim), close_span) - } -} - -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] -pub struct SequenceRepetition { - /// The sequence of token trees - pub tts: Vec, - /// The optional separator - pub separator: Option, - /// Whether the sequence can be repeated zero (*), or one or more times (+) - pub kleene: KleeneToken, - /// The number of `Match`s that appear in the sequence (and subsequences) - pub num_captures: usize, -} - -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)] -pub struct KleeneToken { - pub span: Span, - pub op: KleeneOp, -} - -impl KleeneToken { - pub fn new(op: KleeneOp, span: Span) -> KleeneToken { - KleeneToken { span, op } - } -} - -/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star) -/// for token sequences. -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum KleeneOp { - /// Kleene star (`*`) for zero or more repetitions - ZeroOrMore, - /// Kleene plus (`+`) for one or more repetitions - OneOrMore, - /// Kleene optional (`?`) for zero or one reptitions - ZeroOrOne, -} - -/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)` -/// are "first-class" token trees. Useful for parsing macros. -#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)] -pub enum TokenTree { - Token(Token), - Delimited(DelimSpan, Lrc), - /// A kleene-style repetition sequence - Sequence(DelimSpan, Lrc), - /// e.g., `$var` - MetaVar(Span, ast::Ident), - /// e.g., `$var:expr`. This is only used in the left hand side of MBE macros. - MetaVarDecl( - Span, - ast::Ident, /* name to bind */ - ast::Ident, /* kind of nonterminal */ - ), -} - -impl TokenTree { - /// Return the number of tokens in the tree. - pub fn len(&self) -> usize { - match *self { - TokenTree::Delimited(_, ref delimed) => match delimed.delim { - token::NoDelim => delimed.tts.len(), - _ => delimed.tts.len() + 2, - }, - TokenTree::Sequence(_, ref seq) => seq.tts.len(), - _ => 0, - } - } - - /// Returns `true` if the given token tree contains no other tokens. This is vacuously true for - /// single tokens or metavar/decls, but may be false for delimited trees or sequences. - pub fn is_empty(&self) -> bool { - match *self { - TokenTree::Delimited(_, ref delimed) => match delimed.delim { - token::NoDelim => delimed.tts.is_empty(), - _ => false, - }, - TokenTree::Sequence(_, ref seq) => seq.tts.is_empty(), - _ => true, - } - } - - /// Returns `true` if the given token tree is delimited. - pub fn is_delimited(&self) -> bool { - match *self { - TokenTree::Delimited(..) => true, - _ => false, - } - } - - /// Returns `true` if the given token tree is a token of the given kind. - pub fn is_token(&self, expected_kind: &TokenKind) -> bool { - match self { - TokenTree::Token(Token { kind: actual_kind, .. }) => actual_kind == expected_kind, - _ => false, - } - } - - /// Gets the `index`-th sub-token-tree. This only makes sense for delimited trees and sequences. - pub fn get_tt(&self, index: usize) -> TokenTree { - match (self, index) { - (&TokenTree::Delimited(_, ref delimed), _) if delimed.delim == token::NoDelim => { - delimed.tts[index].clone() - } - (&TokenTree::Delimited(span, ref delimed), _) => { - if index == 0 { - return delimed.open_tt(span.open); - } - if index == delimed.tts.len() + 1 { - return delimed.close_tt(span.close); - } - delimed.tts[index - 1].clone() - } - (&TokenTree::Sequence(_, ref seq), _) => seq.tts[index].clone(), - _ => panic!("Cannot expand a token tree"), - } - } - - /// Retrieves the `TokenTree`'s span. - pub fn span(&self) -> Span { - match *self { - TokenTree::Token(Token { span, .. }) - | TokenTree::MetaVar(span, _) - | TokenTree::MetaVarDecl(span, _, _) => span, - TokenTree::Delimited(span, _) | TokenTree::Sequence(span, _) => span.entire(), - } - } - - crate fn token(kind: TokenKind, span: Span) -> TokenTree { - TokenTree::Token(Token::new(kind, span)) - } -} /// Takes a `tokenstream::TokenStream` and returns a `Vec`. Specifically, this /// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a @@ -195,21 +32,17 @@ impl TokenTree { /// # Returns /// /// A collection of `self::TokenTree`. There may also be some errors emitted to `sess`. -pub fn parse( +pub(super) fn parse( input: tokenstream::TokenStream, expect_matchers: bool, sess: &ParseSess, - features: &Features, - attrs: &[ast::Attribute], - edition: Edition, - macro_node_id: NodeId, ) -> Vec { // Will contain the final collection of `self::TokenTree` let mut result = Vec::new(); // For each token tree in `input`, parse the token into a `self::TokenTree`, consuming // additional trees if need be. - let mut trees = input.trees().peekable(); + let mut trees = input.trees(); while let Some(tree) = trees.next() { // Given the parsed tree, if there is a metavar and we are expecting matchers, actually // parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`). @@ -218,10 +51,6 @@ pub fn parse( &mut trees, expect_matchers, sess, - features, - attrs, - edition, - macro_node_id, ); match tree { TokenTree::MetaVar(start_sp, ident) if expect_matchers => { @@ -269,13 +98,9 @@ pub fn parse( /// unstable features or not. fn parse_tree( tree: tokenstream::TokenTree, - trees: &mut Peekable>, + trees: &mut impl Iterator, expect_matchers: bool, sess: &ParseSess, - features: &Features, - attrs: &[ast::Attribute], - edition: Edition, - macro_node_id: NodeId, ) -> TokenTree { // Depending on what `tree` is, we could be parsing different parts of a macro match tree { @@ -295,10 +120,6 @@ fn parse_tree( tts.into(), expect_matchers, sess, - features, - attrs, - edition, - macro_node_id, ); // Get the Kleene operator and optional separator let (separator, kleene) = parse_sep_and_kleene_op(trees, span.entire(), sess); @@ -352,10 +173,6 @@ fn parse_tree( tts.into(), expect_matchers, sess, - features, - attrs, - edition, - macro_node_id, ), }), ), @@ -404,7 +221,7 @@ fn parse_kleene_op( /// operator and separator, then a tuple with `(separator, KleeneOp)` is returned. Otherwise, an /// error with the appropriate span is emitted to `sess` and a dummy value is returned. fn parse_sep_and_kleene_op( - input: &mut Peekable>, + input: &mut impl Iterator, span: Span, sess: &ParseSess, ) -> (Option, KleeneToken) { diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/mbe/transcribe.rs similarity index 86% rename from src/libsyntax/ext/tt/transcribe.rs rename to src/libsyntax/ext/mbe/transcribe.rs index 214e721fd1506..ba818ebd35c7f 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/mbe/transcribe.rs @@ -1,36 +1,59 @@ -use crate::ast::Ident; +use crate::ast::{Ident, Mac}; use crate::ext::base::ExtCtxt; -use crate::ext::expand::Marker; -use crate::ext::tt::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch}; -use crate::ext::tt::quoted; -use crate::mut_visit::noop_visit_tt; +use crate::ext::mbe; +use crate::ext::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch}; +use crate::mut_visit::{self, MutVisitor}; use crate::parse::token::{self, NtTT, Token}; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; use smallvec::{smallvec, SmallVec}; +use errors::pluralise; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; +use syntax_pos::hygiene::{ExpnId, Transparency}; +use syntax_pos::Span; + use std::mem; +// A Marker adds the given mark to the syntax context. +struct Marker(ExpnId, Transparency); + +impl MutVisitor for Marker { + fn visit_span(&mut self, span: &mut Span) { + *span = span.apply_mark(self.0, self.1) + } + + fn visit_mac(&mut self, mac: &mut Mac) { + mut_visit::noop_visit_mac(mac, self) + } +} + +impl Marker { + fn visit_delim_span(&mut self, dspan: &mut DelimSpan) { + self.visit_span(&mut dspan.open); + self.visit_span(&mut dspan.close); + } +} + /// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`). enum Frame { - Delimited { forest: Lrc, idx: usize, span: DelimSpan }, - Sequence { forest: Lrc, idx: usize, sep: Option }, + Delimited { forest: Lrc, idx: usize, span: DelimSpan }, + Sequence { forest: Lrc, idx: usize, sep: Option }, } impl Frame { /// Construct a new frame around the delimited set of tokens. - fn new(tts: Vec) -> Frame { - let forest = Lrc::new(quoted::Delimited { delim: token::NoDelim, tts }); + fn new(tts: Vec) -> Frame { + let forest = Lrc::new(mbe::Delimited { delim: token::NoDelim, tts }); Frame::Delimited { forest, idx: 0, span: DelimSpan::dummy() } } } impl Iterator for Frame { - type Item = quoted::TokenTree; + type Item = mbe::TokenTree; - fn next(&mut self) -> Option { + fn next(&mut self) -> Option { match *self { Frame::Delimited { ref forest, ref mut idx, .. } => { *idx += 1; @@ -67,7 +90,8 @@ impl Iterator for Frame { pub(super) fn transcribe( cx: &ExtCtxt<'_>, interp: &FxHashMap, - src: Vec, + src: Vec, + transparency: Transparency, ) -> TokenStream { // Nothing for us to transcribe... if src.is_empty() { @@ -96,6 +120,7 @@ pub(super) fn transcribe( // again, and we are done transcribing. let mut result: Vec = Vec::new(); let mut result_stack = Vec::new(); + let mut marker = Marker(cx.current_expansion.id, transparency); loop { // Look at the last frame on the stack. @@ -153,7 +178,7 @@ pub(super) fn transcribe( // We are descending into a sequence. We first make sure that the matchers in the RHS // and the matches in `interp` have the same shape. Otherwise, either the caller or the // macro writer has made a mistake. - seq @ quoted::TokenTree::Sequence(..) => { + seq @ mbe::TokenTree::Sequence(..) => { match lockstep_iter_size(&seq, interp, &repeats) { LockstepIterSize::Unconstrained => { cx.span_fatal( @@ -174,7 +199,7 @@ pub(super) fn transcribe( LockstepIterSize::Constraint(len, _) => { // We do this to avoid an extra clone above. We know that this is a // sequence already. - let (sp, seq) = if let quoted::TokenTree::Sequence(sp, seq) = seq { + let (sp, seq) = if let mbe::TokenTree::Sequence(sp, seq) = seq { (sp, seq) } else { unreachable!() @@ -182,7 +207,7 @@ pub(super) fn transcribe( // Is the repetition empty? if len == 0 { - if seq.kleene.op == quoted::KleeneOp::OneOrMore { + if seq.kleene.op == mbe::KleeneOp::OneOrMore { // FIXME: this really ought to be caught at macro definition // time... It happens when the Kleene operator in the matcher and // the body for the same meta-variable do not match. @@ -207,7 +232,7 @@ pub(super) fn transcribe( } // Replace the meta-var with the matched token tree from the invocation. - quoted::TokenTree::MetaVar(mut sp, ident) => { + mbe::TokenTree::MetaVar(mut sp, mut ident) => { // Find the matched nonterminal from the macro invocation, and use it to replace // the meta-var. if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) { @@ -218,7 +243,7 @@ pub(super) fn transcribe( if let NtTT(ref tt) = **nt { result.push(tt.clone().into()); } else { - sp = sp.apply_mark(cx.current_expansion.id); + marker.visit_span(&mut sp); let token = TokenTree::token(token::Interpolated(nt.clone()), sp); result.push(token.into()); } @@ -232,9 +257,8 @@ pub(super) fn transcribe( } else { // If we aren't able to match the meta-var, we push it back into the result but // with modified syntax context. (I believe this supports nested macros). - let ident = - Ident::new(ident.name, ident.span.apply_mark(cx.current_expansion.id)); - sp = sp.apply_mark(cx.current_expansion.id); + marker.visit_span(&mut sp); + marker.visit_ident(&mut ident); result.push(TokenTree::token(token::Dollar, sp).into()); result.push(TokenTree::Token(Token::from_ast_ident(ident)).into()); } @@ -245,23 +269,22 @@ pub(super) fn transcribe( // We will produce all of the results of the inside of the `Delimited` and then we will // jump back out of the Delimited, pop the result_stack and add the new results back to // the previous results (from outside the Delimited). - quoted::TokenTree::Delimited(mut span, delimited) => { - span = span.apply_mark(cx.current_expansion.id); + mbe::TokenTree::Delimited(mut span, delimited) => { + marker.visit_delim_span(&mut span); stack.push(Frame::Delimited { forest: delimited, idx: 0, span }); result_stack.push(mem::take(&mut result)); } // Nothing much to do here. Just push the token to the result, being careful to // preserve syntax context. - quoted::TokenTree::Token(token) => { - let mut marker = Marker(cx.current_expansion.id); + mbe::TokenTree::Token(token) => { let mut tt = TokenTree::Token(token); - noop_visit_tt(&mut tt, &mut marker); + marker.visit_tt(&mut tt); result.push(tt.into()); } // There should be no meta-var declarations in the invocation of a macro. - quoted::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"), + mbe::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"), } } } @@ -323,8 +346,13 @@ impl LockstepIterSize { LockstepIterSize::Constraint(r_len, _) if l_len == r_len => self, LockstepIterSize::Constraint(r_len, r_id) => { let msg = format!( - "meta-variable `{}` repeats {} times, but `{}` repeats {} times", - l_id, l_len, r_id, r_len + "meta-variable `{}` repeats {} time{}, but `{}` repeats {} time{}", + l_id, + l_len, + pluralise!(l_len), + r_id, + r_len, + pluralise!(r_len), ); LockstepIterSize::Contradiction(msg) } @@ -340,11 +368,11 @@ impl LockstepIterSize { /// `lookup_cur_matched` will return `None`, which is why this still works even in the presnece of /// multiple nested matcher sequences. fn lockstep_iter_size( - tree: "ed::TokenTree, + tree: &mbe::TokenTree, interpolations: &FxHashMap, repeats: &[(usize, usize)], ) -> LockstepIterSize { - use quoted::TokenTree; + use mbe::TokenTree; match *tree { TokenTree::Delimited(_, ref delimed) => { delimed.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| { diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index b2b17b0fb2873..8eecef1020d0a 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -2,7 +2,6 @@ use crate::ast::{self, NodeId}; use crate::source_map::{DUMMY_SP, dummy_spanned}; use crate::ext::base::ExtCtxt; use crate::ext::expand::{AstFragment, AstFragmentKind}; -use crate::ext::hygiene::ExpnId; use crate::tokenstream::TokenStream; use crate::mut_visit::*; use crate::ptr::P; @@ -14,12 +13,13 @@ use rustc_data_structures::fx::FxHashMap; pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment { fn mac_placeholder() -> ast::Mac { - dummy_spanned(ast::Mac_ { + ast::Mac { path: ast::Path { span: DUMMY_SP, segments: Vec::new() }, tts: TokenStream::empty().into(), delim: ast::MacDelimiter::Brace, + span: DUMMY_SP, prior_type_ascription: None, - }) + } } let ident = ast::Ident::invalid(); @@ -30,7 +30,17 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment { let expr_placeholder = || P(ast::Expr { id, span, attrs: ThinVec::new(), - node: ast::ExprKind::Mac(mac_placeholder()), + kind: ast::ExprKind::Mac(mac_placeholder()), + }); + let ty = P(ast::Ty { + id, + kind: ast::TyKind::Mac(mac_placeholder()), + span, + }); + let pat = P(ast::Pat { + id, + kind: ast::PatKind::Mac(mac_placeholder()), + span, }); match kind { @@ -38,35 +48,110 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment { AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())), AstFragmentKind::Items => AstFragment::Items(smallvec![P(ast::Item { id, span, ident, vis, attrs, - node: ast::ItemKind::Mac(mac_placeholder()), + kind: ast::ItemKind::Mac(mac_placeholder()), tokens: None, })]), AstFragmentKind::TraitItems => AstFragment::TraitItems(smallvec![ast::TraitItem { id, span, ident, attrs, generics, - node: ast::TraitItemKind::Macro(mac_placeholder()), + kind: ast::TraitItemKind::Macro(mac_placeholder()), tokens: None, }]), AstFragmentKind::ImplItems => AstFragment::ImplItems(smallvec![ast::ImplItem { id, span, ident, vis, attrs, generics, - node: ast::ImplItemKind::Macro(mac_placeholder()), + kind: ast::ImplItemKind::Macro(mac_placeholder()), defaultness: ast::Defaultness::Final, tokens: None, }]), AstFragmentKind::ForeignItems => AstFragment::ForeignItems(smallvec![ast::ForeignItem { id, span, ident, vis, attrs, - node: ast::ForeignItemKind::Macro(mac_placeholder()), + kind: ast::ForeignItemKind::Macro(mac_placeholder()), }]), AstFragmentKind::Pat => AstFragment::Pat(P(ast::Pat { - id, span, node: ast::PatKind::Mac(mac_placeholder()), + id, span, kind: ast::PatKind::Mac(mac_placeholder()), })), AstFragmentKind::Ty => AstFragment::Ty(P(ast::Ty { - id, span, node: ast::TyKind::Mac(mac_placeholder()), + id, span, kind: ast::TyKind::Mac(mac_placeholder()), })), AstFragmentKind::Stmts => AstFragment::Stmts(smallvec![{ let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ThinVec::new())); - ast::Stmt { id, span, node: ast::StmtKind::Mac(mac) } + ast::Stmt { id, span, kind: ast::StmtKind::Mac(mac) } + }]), + AstFragmentKind::Arms => AstFragment::Arms(smallvec![ + ast::Arm { + attrs: Default::default(), + body: expr_placeholder(), + guard: None, + id, + pat, + span, + is_placeholder: true, + } + ]), + AstFragmentKind::Fields => AstFragment::Fields(smallvec![ + ast::Field { + attrs: Default::default(), + expr: expr_placeholder(), + id, + ident, + is_shorthand: false, + span, + is_placeholder: true, + } + ]), + AstFragmentKind::FieldPats => AstFragment::FieldPats(smallvec![ + ast::FieldPat { + attrs: Default::default(), + id, + ident, + is_shorthand: false, + pat, + span, + is_placeholder: true, + } + ]), + AstFragmentKind::GenericParams => AstFragment::GenericParams(smallvec![{ + ast::GenericParam { + attrs: Default::default(), + bounds: Default::default(), + id, + ident, + is_placeholder: true, + kind: ast::GenericParamKind::Lifetime, + } }]), + AstFragmentKind::Params => AstFragment::Params(smallvec![ + ast::Param { + attrs: Default::default(), + id, + pat, + span, + ty, + is_placeholder: true, + } + ]), + AstFragmentKind::StructFields => AstFragment::StructFields(smallvec![ + ast::StructField { + attrs: Default::default(), + id, + ident: None, + span, + ty, + vis, + is_placeholder: true, + } + ]), + AstFragmentKind::Variants => AstFragment::Variants(smallvec![ + ast::Variant { + attrs: Default::default(), + data: ast::VariantData::Struct(Default::default(), false), + disr_expr: None, + id, + ident, + span, + is_placeholder: true, + } + ]) } } @@ -85,11 +170,11 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> { } } - pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment, derives: Vec) { + pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment, placeholders: Vec) { fragment.mut_visit_with(self); if let AstFragment::Items(mut items) = fragment { - for derive in derives { - match self.remove(NodeId::placeholder_from_expn_id(derive)) { + for placeholder in placeholders { + match self.remove(placeholder) { AstFragment::Items(derived_items) => items.extend(derived_items), _ => unreachable!(), } @@ -105,8 +190,68 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> { } impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { + fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> { + if arm.is_placeholder { + self.remove(arm.id).make_arms() + } else { + noop_flat_map_arm(arm, self) + } + } + + fn flat_map_field(&mut self, field: ast::Field) -> SmallVec<[ast::Field; 1]> { + if field.is_placeholder { + self.remove(field.id).make_fields() + } else { + noop_flat_map_field(field, self) + } + } + + fn flat_map_field_pattern(&mut self, fp: ast::FieldPat) -> SmallVec<[ast::FieldPat; 1]> { + if fp.is_placeholder { + self.remove(fp.id).make_field_patterns() + } else { + noop_flat_map_field_pattern(fp, self) + } + } + + fn flat_map_generic_param( + &mut self, + param: ast::GenericParam + ) -> SmallVec<[ast::GenericParam; 1]> + { + if param.is_placeholder { + self.remove(param.id).make_generic_params() + } else { + noop_flat_map_generic_param(param, self) + } + } + + fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> { + if p.is_placeholder { + self.remove(p.id).make_params() + } else { + noop_flat_map_param(p, self) + } + } + + fn flat_map_struct_field(&mut self, sf: ast::StructField) -> SmallVec<[ast::StructField; 1]> { + if sf.is_placeholder { + self.remove(sf.id).make_struct_fields() + } else { + noop_flat_map_struct_field(sf, self) + } + } + + fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> { + if variant.is_placeholder { + self.remove(variant.id).make_variants() + } else { + noop_flat_map_variant(variant, self) + } + } + fn flat_map_item(&mut self, item: P) -> SmallVec<[P; 1]> { - match item.node { + match item.kind { ast::ItemKind::Mac(_) => return self.remove(item.id).make_items(), ast::ItemKind::MacroDef(_) => return smallvec![item], _ => {} @@ -116,42 +261,42 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { } fn flat_map_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> { - match item.node { + match item.kind { ast::TraitItemKind::Macro(_) => self.remove(item.id).make_trait_items(), _ => noop_flat_map_trait_item(item, self), } } fn flat_map_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> { - match item.node { + match item.kind { ast::ImplItemKind::Macro(_) => self.remove(item.id).make_impl_items(), _ => noop_flat_map_impl_item(item, self), } } fn flat_map_foreign_item(&mut self, item: ast::ForeignItem) -> SmallVec<[ast::ForeignItem; 1]> { - match item.node { + match item.kind { ast::ForeignItemKind::Macro(_) => self.remove(item.id).make_foreign_items(), _ => noop_flat_map_foreign_item(item, self), } } fn visit_expr(&mut self, expr: &mut P) { - match expr.node { + match expr.kind { ast::ExprKind::Mac(_) => *expr = self.remove(expr.id).make_expr(), _ => noop_visit_expr(expr, self), } } fn filter_map_expr(&mut self, expr: P) -> Option> { - match expr.node { + match expr.kind { ast::ExprKind::Mac(_) => self.remove(expr.id).make_opt_expr(), _ => noop_filter_map_expr(expr, self), } } fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { - let (style, mut stmts) = match stmt.node { + let (style, mut stmts) = match stmt.kind { ast::StmtKind::Mac(mac) => (mac.1, self.remove(stmt.id).make_stmts()), _ => return noop_flat_map_stmt(stmt, self), }; @@ -166,14 +311,14 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { } fn visit_pat(&mut self, pat: &mut P) { - match pat.node { + match pat.kind { ast::PatKind::Mac(_) => *pat = self.remove(pat.id).make_pat(), _ => noop_visit_pat(pat, self), } } fn visit_ty(&mut self, ty: &mut P) { - match ty.node { + match ty.kind { ast::TyKind::Mac(_) => *ty = self.remove(ty.id).make_ty(), _ => noop_visit_ty(ty, self), } @@ -192,7 +337,7 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { fn visit_mod(&mut self, module: &mut ast::Mod) { noop_visit_mod(module, self); - module.items.retain(|item| match item.node { + module.items.retain(|item| match item.kind { ast::ItemKind::Mac(_) if !self.cx.ecfg.keep_macs => false, // remove macro definitions _ => true, }); diff --git a/src/libsyntax/ext/proc_macro.rs b/src/libsyntax/ext/proc_macro.rs index c17b6f6b4248a..e17bbf79fd5e0 100644 --- a/src/libsyntax/ext/proc_macro.rs +++ b/src/libsyntax/ext/proc_macro.rs @@ -78,7 +78,6 @@ pub struct ProcMacroDerive { pub client: proc_macro::bridge::client::Client< fn(proc_macro::TokenStream) -> proc_macro::TokenStream, >, - pub attrs: Vec, } impl MultiItemModifier for ProcMacroDerive { @@ -89,6 +88,14 @@ impl MultiItemModifier for ProcMacroDerive { item: Annotatable) -> Vec { let item = match item { + Annotatable::Arm(..) | + Annotatable::Field(..) | + Annotatable::FieldPat(..) | + Annotatable::GenericParam(..) | + Annotatable::Param(..) | + Annotatable::StructField(..) | + Annotatable::Variant(..) + => panic!("unexpected annotatable"), Annotatable::Item(item) => item, Annotatable::ImplItem(_) | Annotatable::TraitItem(_) | @@ -100,7 +107,7 @@ impl MultiItemModifier for ProcMacroDerive { return Vec::new() } }; - match item.node { + match item.kind { ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..) => {}, @@ -111,9 +118,6 @@ impl MultiItemModifier for ProcMacroDerive { } } - // Mark attributes as known, and used. - MarkAttrs(&self.attrs).visit_item(&item); - let token = token::Interpolated(Lrc::new(token::NtItem(item))); let input = tokenstream::TokenTree::token(token, DUMMY_SP).into(); @@ -164,7 +168,7 @@ impl MultiItemModifier for ProcMacroDerive { } } -struct MarkAttrs<'a>(&'a [ast::Name]); +crate struct MarkAttrs<'a>(crate &'a [ast::Name]); impl<'a> Visitor<'a> for MarkAttrs<'a> { fn visit_attribute(&mut self, attr: &Attribute) { diff --git a/src/libsyntax/ext/proc_macro_server.rs b/src/libsyntax/ext/proc_macro_server.rs index 36621ce777510..021ec46d987cf 100644 --- a/src/libsyntax/ext/proc_macro_server.rs +++ b/src/libsyntax/ext/proc_macro_server.rs @@ -4,10 +4,9 @@ use crate::parse::{self, token, ParseSess}; use crate::parse::lexer::comments; use crate::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint}; -use errors::{Diagnostic, DiagnosticBuilder}; +use errors::Diagnostic; use rustc_data_structures::sync::Lrc; use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span}; -use syntax_pos::hygiene::{SyntaxContext, Transparency}; use syntax_pos::symbol::{kw, sym, Symbol}; use proc_macro::{Delimiter, Level, LineColumn, Spacing}; @@ -323,8 +322,7 @@ impl Ident { fn is_valid(string: &str) -> bool { let mut chars = string.chars(); if let Some(start) = chars.next() { - (start == '_' || start.is_xid_start()) - && chars.all(|cont| cont == '_' || cont.is_xid_continue()) + rustc_lexer::is_id_start(start) && chars.all(rustc_lexer::is_id_continue) } else { false } @@ -357,22 +355,17 @@ pub(crate) struct Rustc<'a> { sess: &'a ParseSess, def_site: Span, call_site: Span, + mixed_site: Span, } impl<'a> Rustc<'a> { pub fn new(cx: &'a ExtCtxt<'_>) -> Self { - // No way to determine def location for a proc macro right now, so use call location. - let location = cx.current_expansion.id.expn_info().unwrap().call_site; - let to_span = |transparency| { - location.with_ctxt( - SyntaxContext::empty() - .apply_mark_with_transparency(cx.current_expansion.id, transparency), - ) - }; + let expn_data = cx.current_expansion.id.expn_data(); Rustc { sess: cx.parse_sess, - def_site: to_span(Transparency::Opaque), - call_site: to_span(Transparency::Transparent), + def_site: cx.with_def_site_ctxt(expn_data.def_site), + call_site: cx.with_call_site_ctxt(expn_data.call_site), + mixed_site: cx.with_mixed_site_ctxt(expn_data.call_site), } } @@ -659,7 +652,7 @@ impl server::Diagnostic for Rustc<'_> { diag.sub(level.to_internal(), msg, MultiSpan::from_spans(spans), None); } fn emit(&mut self, diag: Self::Diagnostic) { - DiagnosticBuilder::new_diagnostic(&self.sess.span_diagnostic, diag).emit() + self.sess.span_diagnostic.emit_diagnostic(&diag); } } @@ -673,11 +666,14 @@ impl server::Span for Rustc<'_> { fn call_site(&mut self) -> Self::Span { self.call_site } + fn mixed_site(&mut self) -> Self::Span { + self.mixed_site + } fn source_file(&mut self, span: Self::Span) -> Self::SourceFile { self.sess.source_map().lookup_char_pos(span.lo()).file } fn parent(&mut self, span: Self::Span) -> Option { - span.ctxt().outer_expn_info().map(|i| i.call_site) + span.parent() } fn source(&mut self, span: Self::Span) -> Self::Span { span.source_callsite() diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs deleted file mode 100644 index 08a113b53d032..0000000000000 --- a/src/libsyntax/feature_gate.rs +++ /dev/null @@ -1,2525 +0,0 @@ -//! # Feature gating -//! -//! This module implements the gating necessary for preventing certain compiler -//! features from being used by default. This module will crawl a pre-expanded -//! AST to ensure that there are no features which are used that are not -//! enabled. -//! -//! Features are enabled in programs via the crate-level attributes of -//! `#![feature(...)]` with a comma-separated list of features. -//! -//! For the purpose of future feature-tracking, once code for detection of feature -//! gate usage is added, *do not remove it again* even once the feature -//! becomes stable. - -use AttributeType::*; -use AttributeGate::*; - -use crate::ast::{ - self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind, - PatKind, RangeEnd, -}; -use crate::attr::{self, check_builtin_attribute, AttributeTemplate}; -use crate::source_map::Spanned; -use crate::edition::{ALL_EDITIONS, Edition}; -use crate::visit::{self, FnKind, Visitor}; -use crate::parse::{token, ParseSess}; -use crate::parse::parser::Parser; -use crate::symbol::{Symbol, sym}; -use crate::tokenstream::TokenTree; - -use errors::{Applicability, DiagnosticBuilder, Handler}; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::Lock; -use rustc_target::spec::abi::Abi; -use syntax_pos::{Span, DUMMY_SP, MultiSpan}; -use log::debug; -use lazy_static::lazy_static; - -use std::env; - -macro_rules! set { - ($field: ident) => {{ - fn f(features: &mut Features, _: Span) { - features.$field = true; - } - f as fn(&mut Features, Span) - }} -} - -macro_rules! declare_features { - ($((active, $feature: ident, $ver: expr, $issue: expr, $edition: expr),)+) => { - /// Represents active features that are currently being implemented or - /// currently being considered for addition/removal. - const ACTIVE_FEATURES: - &[(Symbol, &str, Option, Option, fn(&mut Features, Span))] = - &[$((sym::$feature, $ver, $issue, $edition, set!($feature))),+]; - - /// A set of features to be used by later passes. - #[derive(Clone)] - pub struct Features { - /// `#![feature]` attrs for language features, for error reporting - pub declared_lang_features: Vec<(Symbol, Span, Option)>, - /// `#![feature]` attrs for non-language (library) features - pub declared_lib_features: Vec<(Symbol, Span)>, - $(pub $feature: bool),+ - } - - impl Features { - pub fn new() -> Features { - Features { - declared_lang_features: Vec::new(), - declared_lib_features: Vec::new(), - $($feature: false),+ - } - } - - pub fn walk_feature_fields(&self, mut f: F) - where F: FnMut(&str, bool) - { - $(f(stringify!($feature), self.$feature);)+ - } - } - }; - - ($((removed, $feature: ident, $ver: expr, $issue: expr, None, $reason: expr),)+) => { - /// Represents unstable features which have since been removed (it was once Active) - const REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ - $((sym::$feature, $ver, $issue, $reason)),+ - ]; - }; - - ($((stable_removed, $feature: ident, $ver: expr, $issue: expr, None),)+) => { - /// Represents stable features which have since been removed (it was once Accepted) - const STABLE_REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ - $((sym::$feature, $ver, $issue, None)),+ - ]; - }; - - ($((accepted, $feature: ident, $ver: expr, $issue: expr, None),)+) => { - /// Those language feature has since been Accepted (it was once Active) - const ACCEPTED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ - $((sym::$feature, $ver, $issue, None)),+ - ]; - } -} - -// If you change this, please modify `src/doc/unstable-book` as well. -// -// Don't ever remove anything from this list; set them to 'Removed'. -// -// The version numbers here correspond to the version in which the current status -// was set. This is most important for knowing when a particular feature became -// stable (active). -// -// Note that the features are grouped into internal/user-facing and then -// sorted by version inside those groups. This is inforced with tidy. -// -// N.B., `tools/tidy/src/features.rs` parses this information directly out of the -// source, so take care when modifying it. - -declare_features! ( - // ------------------------------------------------------------------------- - // feature-group-start: internal feature gates - // ------------------------------------------------------------------------- - - // no-tracking-issue-start - - // Allows using compiler's own crates. - (active, rustc_private, "1.0.0", Some(27812), None), - - // Allows using the `rust-intrinsic`'s "ABI". - (active, intrinsics, "1.0.0", None, None), - - // Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. - (active, lang_items, "1.0.0", None, None), - - // Allows using the `#[stable]` and `#[unstable]` attributes. - (active, staged_api, "1.0.0", None, None), - - // Allows using `#[allow_internal_unstable]`. This is an - // attribute on `macro_rules!` and can't use the attribute handling - // below (it has to be checked before expansion possibly makes - // macros disappear). - (active, allow_internal_unstable, "1.0.0", None, None), - - // Allows using `#[allow_internal_unsafe]`. This is an - // attribute on `macro_rules!` and can't use the attribute handling - // below (it has to be checked before expansion possibly makes - // macros disappear). - (active, allow_internal_unsafe, "1.0.0", None, None), - - // Allows using the macros: - // + `__diagnostic_used` - // + `__register_diagnostic` - // +`__build_diagnostic_array` - (active, rustc_diagnostic_macros, "1.0.0", None, None), - - // Allows using `#[rustc_const_unstable(feature = "foo", ..)]` which - // lets a function to be `const` when opted into with `#![feature(foo)]`. - (active, rustc_const_unstable, "1.0.0", None, None), - - // no-tracking-issue-end - - // Allows using `#[link_name="llvm.*"]`. - (active, link_llvm_intrinsics, "1.0.0", Some(29602), None), - - // Allows using `rustc_*` attributes (RFC 572). - (active, rustc_attrs, "1.0.0", Some(29642), None), - - // Allows using `#[on_unimplemented(..)]` on traits. - (active, on_unimplemented, "1.0.0", Some(29628), None), - - // Allows using the `box $expr` syntax. - (active, box_syntax, "1.0.0", Some(49733), None), - - // Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls. - (active, main, "1.0.0", Some(29634), None), - - // Allows using `#[start]` on a function indicating that it is the program entrypoint. - (active, start, "1.0.0", Some(29633), None), - - // Allows using the `#[fundamental]` attribute. - (active, fundamental, "1.0.0", Some(29635), None), - - // Allows using the `rust-call` ABI. - (active, unboxed_closures, "1.0.0", Some(29625), None), - - // Allows using the `#[linkage = ".."]` attribute. - (active, linkage, "1.0.0", Some(29603), None), - - // Allows features specific to OIBIT (auto traits). - (active, optin_builtin_traits, "1.0.0", Some(13231), None), - - // Allows using `box` in patterns (RFC 469). - (active, box_patterns, "1.0.0", Some(29641), None), - - // no-tracking-issue-start - - // Allows using `#[prelude_import]` on glob `use` items. - (active, prelude_import, "1.2.0", None, None), - - // no-tracking-issue-end - - // no-tracking-issue-start - - // Allows using `#[omit_gdb_pretty_printer_section]`. - (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), - - // Allows using the `vectorcall` ABI. - (active, abi_vectorcall, "1.7.0", None, None), - - // no-tracking-issue-end - - // Allows using `#[structural_match]` which indicates that a type is structurally matchable. - (active, structural_match, "1.8.0", Some(31434), None), - - // Allows using the `may_dangle` attribute (RFC 1327). - (active, dropck_eyepatch, "1.10.0", Some(34761), None), - - // Allows using the `#![panic_runtime]` attribute. - (active, panic_runtime, "1.10.0", Some(32837), None), - - // Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. - (active, needs_panic_runtime, "1.10.0", Some(32837), None), - - // no-tracking-issue-start - - // Allows identifying the `compiler_builtins` crate. - (active, compiler_builtins, "1.13.0", None, None), - - // Allows using the `unadjusted` ABI; perma-unstable. - (active, abi_unadjusted, "1.16.0", None, None), - - // Allows identifying crates that contain sanitizer runtimes. - (active, sanitizer_runtime, "1.17.0", None, None), - - // Used to identify crates that contain the profiler runtime. - (active, profiler_runtime, "1.18.0", None, None), - - // Allows using the `thiscall` ABI. - (active, abi_thiscall, "1.19.0", None, None), - - // Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`. - (active, allocator_internals, "1.20.0", None, None), - - // no-tracking-issue-end - - // Added for testing E0705; perma-unstable. - (active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)), - - // ------------------------------------------------------------------------- - // feature-group-end: internal feature gates - // ------------------------------------------------------------------------- - - // ------------------------------------------------------------------------- - // feature-group-start: actual feature gates (target features) - // ------------------------------------------------------------------------- - - // FIXME: Document these and merge with the list below. - - // Unstable `#[target_feature]` directives. - (active, arm_target_feature, "1.27.0", Some(44839), None), - (active, aarch64_target_feature, "1.27.0", Some(44839), None), - (active, hexagon_target_feature, "1.27.0", Some(44839), None), - (active, powerpc_target_feature, "1.27.0", Some(44839), None), - (active, mips_target_feature, "1.27.0", Some(44839), None), - (active, avx512_target_feature, "1.27.0", Some(44839), None), - (active, mmx_target_feature, "1.27.0", Some(44839), None), - (active, sse4a_target_feature, "1.27.0", Some(44839), None), - (active, tbm_target_feature, "1.27.0", Some(44839), None), - (active, wasm_target_feature, "1.30.0", Some(44839), None), - (active, adx_target_feature, "1.32.0", Some(44839), None), - (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None), - (active, movbe_target_feature, "1.34.0", Some(44839), None), - (active, rtm_target_feature, "1.35.0", Some(44839), None), - (active, f16c_target_feature, "1.36.0", Some(44839), None), - - // ------------------------------------------------------------------------- - // feature-group-end: actual feature gates (target features) - // ------------------------------------------------------------------------- - - // ------------------------------------------------------------------------- - // feature-group-start: actual feature gates - // ------------------------------------------------------------------------- - - // Allows using the `#[link_args]` attribute. - (active, link_args, "1.0.0", Some(29596), None), - - // Allows defining identifiers beyond ASCII. - (active, non_ascii_idents, "1.0.0", Some(55467), None), - - // Allows using `#[plugin_registrar]` on functions. - (active, plugin_registrar, "1.0.0", Some(29597), None), - - // Allows using `#![plugin(myplugin)]`. - (active, plugin, "1.0.0", Some(29597), None), - - // Allows using `#[thread_local]` on `static` items. - (active, thread_local, "1.0.0", Some(29594), None), - - // Allows the use of SIMD types in functions declared in `extern` blocks. - (active, simd_ffi, "1.0.0", Some(27731), None), - - // Allows using custom attributes (RFC 572). - (active, custom_attribute, "1.0.0", Some(29642), None), - - // Allows using non lexical lifetimes (RFC 2094). - (active, nll, "1.0.0", Some(43234), None), - - // Allows using slice patterns. - (active, slice_patterns, "1.0.0", Some(62254), None), - - // Allows the definition of `const` functions with some advanced features. - (active, const_fn, "1.2.0", Some(57563), None), - - // Allows associated type defaults. - (active, associated_type_defaults, "1.2.0", Some(29661), None), - - // Allows `#![no_core]`. - (active, no_core, "1.3.0", Some(29639), None), - - // Allows default type parameters to influence type inference. - (active, default_type_parameter_fallback, "1.3.0", Some(27336), None), - - // Allows `repr(simd)` and importing the various simd intrinsics. - (active, repr_simd, "1.4.0", Some(27731), None), - - // Allows `extern "platform-intrinsic" { ... }`. - (active, platform_intrinsics, "1.4.0", Some(27731), None), - - // Allows `#[unwind(..)]`. - // - // Permits specifying whether a function should permit unwinding or abort on unwind. - (active, unwind_attributes, "1.4.0", Some(58760), None), - - // Allows `#[no_debug]`. - (active, no_debug, "1.5.0", Some(29721), None), - - // Allows attributes on expressions and non-item statements. - (active, stmt_expr_attributes, "1.6.0", Some(15701), None), - - // Allows the use of type ascription in expressions. - (active, type_ascription, "1.6.0", Some(23416), None), - - // Allows `cfg(target_thread_local)`. - (active, cfg_target_thread_local, "1.7.0", Some(29594), None), - - // Allows specialization of implementations (RFC 1210). - (active, specialization, "1.7.0", Some(31844), None), - - // Allows using `#[naked]` on functions. - (active, naked_functions, "1.9.0", Some(32408), None), - - // Allows `cfg(target_has_atomic = "...")`. - (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), - - // Allows `X..Y` patterns. - (active, exclusive_range_pattern, "1.11.0", Some(37854), None), - - // Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. - (active, never_type, "1.13.0", Some(35121), None), - - // Allows exhaustive pattern matching on types that contain uninhabited types. - (active, exhaustive_patterns, "1.13.0", Some(51085), None), - - // Allows untagged unions `union U { ... }`. - (active, untagged_unions, "1.13.0", Some(32836), None), - - // Allows `#[link(..., cfg(..))]`. - (active, link_cfg, "1.14.0", Some(37406), None), - - // Allows `extern "ptx-*" fn()`. - (active, abi_ptx, "1.15.0", Some(38788), None), - - // Allows the `#[repr(i128)]` attribute for enums. - (active, repr128, "1.16.0", Some(35118), None), - - // Allows `#[link(kind="static-nobundle"...)]`. - (active, static_nobundle, "1.16.0", Some(37403), None), - - // Allows `extern "msp430-interrupt" fn()`. - (active, abi_msp430_interrupt, "1.16.0", Some(38487), None), - - // Allows declarative macros 2.0 (`macro`). - (active, decl_macro, "1.17.0", Some(39412), None), - - // Allows `extern "x86-interrupt" fn()`. - (active, abi_x86_interrupt, "1.17.0", Some(40180), None), - - // Allows overlapping impls of marker traits. - (active, overlapping_marker_traits, "1.18.0", Some(29864), None), - - // Allows a test to fail without failing the whole suite. - (active, allow_fail, "1.19.0", Some(46488), None), - - // Allows unsized tuple coercion. - (active, unsized_tuple_coercion, "1.20.0", Some(42877), None), - - // Allows defining generators. - (active, generators, "1.21.0", Some(43122), None), - - // Allows `#[doc(cfg(...))]`. - (active, doc_cfg, "1.21.0", Some(43781), None), - - // Allows `#[doc(masked)]`. - (active, doc_masked, "1.21.0", Some(44027), None), - - // Allows `#[doc(spotlight)]`. - (active, doc_spotlight, "1.22.0", Some(45040), None), - - // Allows `#[doc(include = "some-file")]`. - (active, external_doc, "1.22.0", Some(44732), None), - - // Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008). - (active, non_exhaustive, "1.22.0", Some(44109), None), - - // Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. - (active, crate_visibility_modifier, "1.23.0", Some(53120), None), - - // Allows defining `extern type`s. - (active, extern_types, "1.23.0", Some(43467), None), - - // Allows trait methods with arbitrary self types. - (active, arbitrary_self_types, "1.23.0", Some(44874), None), - - // Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`). - (active, in_band_lifetimes, "1.23.0", Some(44524), None), - - // Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). - (active, generic_associated_types, "1.23.0", Some(44265), None), - - // Allows defining `trait X = A + B;` alias items. - (active, trait_alias, "1.24.0", Some(41517), None), - - // Allows infering `'static` outlives requirements (RFC 2093). - (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None), - - // Allows macro invocations in `extern {}` blocks. - (active, macros_in_extern, "1.27.0", Some(49476), None), - - // Allows accessing fields of unions inside `const` functions. - (active, const_fn_union, "1.27.0", Some(51909), None), - - // Allows casting raw pointers to `usize` during const eval. - (active, const_raw_ptr_to_usize_cast, "1.27.0", Some(51910), None), - - // Allows dereferencing raw pointers during const eval. - (active, const_raw_ptr_deref, "1.27.0", Some(51911), None), - - // Allows comparing raw pointers during const eval. - (active, const_compare_raw_pointers, "1.27.0", Some(53020), None), - - // Allows `#[doc(alias = "...")]`. - (active, doc_alias, "1.27.0", Some(50146), None), - - // Allows inconsistent bounds in where clauses. - (active, trivial_bounds, "1.28.0", Some(48214), None), - - // Allows `'a: { break 'a; }`. - (active, label_break_value, "1.28.0", Some(48594), None), - - // Allows using `#[doc(keyword = "...")]`. - (active, doc_keyword, "1.28.0", Some(51315), None), - - // Allows async and await syntax. - (active, async_await, "1.28.0", Some(50547), None), - - // Allows reinterpretation of the bits of a value of one type as another type during const eval. - (active, const_transmute, "1.29.0", Some(53605), None), - - // Allows using `try {...}` expressions. - (active, try_blocks, "1.29.0", Some(31436), None), - - // Allows defining an `#[alloc_error_handler]`. - (active, alloc_error_handler, "1.29.0", Some(51540), None), - - // Allows using the `amdgpu-kernel` ABI. - (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None), - - // Allows panicking during const eval (producing compile-time errors). - (active, const_panic, "1.30.0", Some(51999), None), - - // Allows `#[marker]` on certain traits allowing overlapping implementations. - (active, marker_trait_attr, "1.30.0", Some(29864), None), - - // Allows macro invocations on modules expressions and statements and - // procedural macros to expand to non-items. - (active, proc_macro_hygiene, "1.30.0", Some(54727), None), - - // Allows unsized rvalues at arguments and parameters. - (active, unsized_locals, "1.30.0", Some(48055), None), - - // Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. - (active, custom_test_frameworks, "1.30.0", Some(50297), None), - - // Allows non-builtin attributes in inner attribute position. - (active, custom_inner_attributes, "1.30.0", Some(54726), None), - - // Allows mixing bind-by-move in patterns and references to those identifiers in guards. - (active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None), - - // Allows `impl Trait` in bindings (`let`, `const`, `static`). - (active, impl_trait_in_bindings, "1.30.0", Some(63065), None), - - // Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. - (active, lint_reasons, "1.31.0", Some(54503), None), - - // Allows exhaustive integer pattern matching on `usize` and `isize`. - (active, precise_pointer_size_matching, "1.32.0", Some(56354), None), - - // Allows relaxing the coherence rules such that - // `impl ForeignTrait for ForeignType is permitted. - (active, re_rebalance_coherence, "1.32.0", Some(55437), None), - - // Allows using `#[ffi_returns_twice]` on foreign functions. - (active, ffi_returns_twice, "1.34.0", Some(58314), None), - - // Allows const generic types (e.g. `struct Foo(...);`). - (active, const_generics, "1.34.0", Some(44580), None), - - // Allows using `#[optimize(X)]`. - (active, optimize_attribute, "1.34.0", Some(54882), None), - - // Allows using C-variadics. - (active, c_variadic, "1.34.0", Some(44930), None), - - // Allows the user of associated type bounds. - (active, associated_type_bounds, "1.34.0", Some(52662), None), - - // Attributes on formal function params. - (active, param_attrs, "1.36.0", Some(60406), None), - - // Allows calling constructor functions in `const fn`. - (active, const_constructor, "1.37.0", Some(61456), None), - - // Allows `if/while p && let q = r && ...` chains. - (active, let_chains, "1.37.0", Some(53667), None), - - // Allows #[repr(transparent)] on enums (RFC 2645). - (active, transparent_enums, "1.37.0", Some(60405), None), - - // Allows #[repr(transparent)] on unions (RFC 2645). - (active, transparent_unions, "1.37.0", Some(60405), None), - - // Allows explicit discriminants on non-unit enum variants. - (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None), - - // Allows `impl Trait` with multiple unrelated lifetimes. - (active, member_constraints, "1.37.0", Some(61977), None), - - // Allows `async || body` closures. - (active, async_closure, "1.37.0", Some(62290), None), - - // Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests - (active, cfg_doctest, "1.37.0", Some(62210), None), - - // Allows `[x; N]` where `x` is a constant (RFC 2203). - (active, const_in_array_repeat_expressions, "1.37.0", Some(49147), None), - - // Allows `impl Trait` to be used inside type aliases (RFC 2515). - (active, type_alias_impl_trait, "1.38.0", Some(63063), None), - - // ------------------------------------------------------------------------- - // feature-group-end: actual feature gates - // ------------------------------------------------------------------------- -); - -/// Some features are known to be incomplete and using them is likely to have -/// unanticipated results, such as compiler crashes. We warn the user about these -/// to alert them. -pub const INCOMPLETE_FEATURES: &[Symbol] = &[ - sym::impl_trait_in_bindings, - sym::generic_associated_types, - sym::const_generics, - sym::let_chains, -]; - -declare_features! ( - // ------------------------------------------------------------------------- - // feature-group-start: removed features - // ------------------------------------------------------------------------- - - (removed, import_shadowing, "1.0.0", None, None, None), - (removed, managed_boxes, "1.0.0", None, None, None), - // Allows use of unary negate on unsigned integers, e.g., -e for e: u8 - (removed, negate_unsigned, "1.0.0", Some(29645), None, None), - (removed, reflect, "1.0.0", Some(27749), None, None), - // A way to temporarily opt out of opt in copy. This will *never* be accepted. - (removed, opt_out_copy, "1.0.0", None, None, None), - (removed, quad_precision_float, "1.0.0", None, None, None), - (removed, struct_inherit, "1.0.0", None, None, None), - (removed, test_removed_feature, "1.0.0", None, None, None), - (removed, visible_private_types, "1.0.0", None, None, None), - (removed, unsafe_no_drop_flag, "1.0.0", None, None, None), - // Allows using items which are missing stability attributes - (removed, unmarked_api, "1.0.0", None, None, None), - (removed, allocator, "1.0.0", None, None, None), - (removed, simd, "1.0.0", Some(27731), None, - Some("removed in favor of `#[repr(simd)]`")), - (removed, advanced_slice_patterns, "1.0.0", Some(62254), None, - Some("merged into `#![feature(slice_patterns)]`")), - (removed, macro_reexport, "1.0.0", Some(29638), None, - Some("subsumed by `pub use`")), - (removed, pushpop_unsafe, "1.2.0", None, None, None), - (removed, needs_allocator, "1.4.0", Some(27389), None, - Some("subsumed by `#![feature(allocator_internals)]`")), - (removed, proc_macro_mod, "1.27.0", Some(54727), None, - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), - (removed, proc_macro_expr, "1.27.0", Some(54727), None, - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), - (removed, proc_macro_non_items, "1.27.0", Some(54727), None, - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), - (removed, proc_macro_gen, "1.27.0", Some(54727), None, - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), - (removed, panic_implementation, "1.28.0", Some(44489), None, - Some("subsumed by `#[panic_handler]`")), - // Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`. - (removed, custom_derive, "1.32.0", Some(29644), None, - Some("subsumed by `#[proc_macro_derive]`")), - // Paths of the form: `extern::foo::bar` - (removed, extern_in_paths, "1.33.0", Some(55600), None, - Some("subsumed by `::foo::bar` paths")), - (removed, quote, "1.33.0", Some(29601), None, None), - // Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238). - (removed, dropck_parametricity, "1.38.0", Some(28498), None, None), - (removed, await_macro, "1.38.0", Some(50547), None, - Some("subsumed by `.await` syntax")), - // Allows defining `existential type`s. - (removed, existential_type, "1.38.0", Some(63063), None, - Some("removed in favor of `#![feature(type_alias_impl_trait)]`")), - - // ------------------------------------------------------------------------- - // feature-group-end: removed features - // ------------------------------------------------------------------------- -); - -declare_features! ( - (stable_removed, no_stack_check, "1.0.0", None, None), -); - -declare_features! ( - // ------------------------------------------------------------------------- - // feature-group-start: for testing purposes - // ------------------------------------------------------------------------- - - // A temporary feature gate used to enable parser extensions needed - // to bootstrap fix for #5723. - (accepted, issue_5723_bootstrap, "1.0.0", None, None), - // These are used to test this portion of the compiler, - // they don't actually mean anything. - (accepted, test_accepted_feature, "1.0.0", None, None), - - // ------------------------------------------------------------------------- - // feature-group-end: for testing purposes - // ------------------------------------------------------------------------- - - // ------------------------------------------------------------------------- - // feature-group-start: accepted features - // ------------------------------------------------------------------------- - - // Allows using associated `type`s in `trait`s. - (accepted, associated_types, "1.0.0", None, None), - // Allows using assigning a default type to type parameters in algebraic data type definitions. - (accepted, default_type_params, "1.0.0", None, None), - // FIXME: explain `globs`. - (accepted, globs, "1.0.0", None, None), - // Allows `macro_rules!` items. - (accepted, macro_rules, "1.0.0", None, None), - // Allows use of `&foo[a..b]` as a slicing syntax. - (accepted, slicing_syntax, "1.0.0", None, None), - // Allows struct variants `Foo { baz: u8, .. }` in enums (RFC 418). - (accepted, struct_variant, "1.0.0", None, None), - // Allows indexing tuples. - (accepted, tuple_indexing, "1.0.0", None, None), - // Allows the use of `if let` expressions. - (accepted, if_let, "1.0.0", None, None), - // Allows the use of `while let` expressions. - (accepted, while_let, "1.0.0", None, None), - // Allows using `#![no_std]`. - (accepted, no_std, "1.6.0", None, None), - // Allows overloading augmented assignment operations like `a += b`. - (accepted, augmented_assignments, "1.8.0", Some(28235), None), - // Allows empty structs and enum variants with braces. - (accepted, braced_empty_structs, "1.8.0", Some(29720), None), - // Allows `#[deprecated]` attribute. - (accepted, deprecated, "1.9.0", Some(29935), None), - // Allows macros to appear in the type position. - (accepted, type_macros, "1.13.0", Some(27245), None), - // Allows use of the postfix `?` operator in expressions. - (accepted, question_mark, "1.13.0", Some(31436), None), - // Allows `..` in tuple (struct) patterns. - (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627), None), - // Allows some increased flexibility in the name resolution rules, - // especially around globs and shadowing (RFC 1560). - (accepted, item_like_imports, "1.15.0", Some(35120), None), - // Allows using `Self` and associated types in struct expressions and patterns. - (accepted, more_struct_aliases, "1.16.0", Some(37544), None), - // Allows elision of `'static` lifetimes in `static`s and `const`s. - (accepted, static_in_const, "1.17.0", Some(35897), None), - // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. - (accepted, field_init_shorthand, "1.17.0", Some(37340), None), - // Allows the definition recursive static items. - (accepted, static_recursion, "1.17.0", Some(29719), None), - // Allows `pub(restricted)` visibilities (RFC 1422). - (accepted, pub_restricted, "1.18.0", Some(32409), None), - // Allows `#![windows_subsystem]`. - (accepted, windows_subsystem, "1.18.0", Some(37499), None), - // Allows `break {expr}` with a value inside `loop`s. - (accepted, loop_break_value, "1.19.0", Some(37339), None), - // Allows numeric fields in struct expressions and patterns. - (accepted, relaxed_adts, "1.19.0", Some(35626), None), - // Allows coercing non capturing closures to function pointers. - (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None), - // Allows attributes on struct literal fields. - (accepted, struct_field_attributes, "1.20.0", Some(38814), None), - // Allows the definition of associated constants in `trait` or `impl` blocks. - (accepted, associated_consts, "1.20.0", Some(29646), None), - // Allows usage of the `compile_error!` macro. - (accepted, compile_error, "1.20.0", Some(40872), None), - // Allows code like `let x: &'static u32 = &42` to work (RFC 1414). - (accepted, rvalue_static_promotion, "1.21.0", Some(38865), None), - // Allows `Drop` types in constants (RFC 1440). - (accepted, drop_types_in_const, "1.22.0", Some(33156), None), - // Allows the sysV64 ABI to be specified on all platforms - // instead of just the platforms on which it is the C ABI. - (accepted, abi_sysv64, "1.24.0", Some(36167), None), - // Allows `repr(align(16))` struct attribute (RFC 1358). - (accepted, repr_align, "1.25.0", Some(33626), None), - // Allows '|' at beginning of match arms (RFC 1925). - (accepted, match_beginning_vert, "1.25.0", Some(44101), None), - // Allows nested groups in `use` items (RFC 2128). - (accepted, use_nested_groups, "1.25.0", Some(44494), None), - // Allows indexing into constant arrays. - (accepted, const_indexing, "1.26.0", Some(29947), None), - // Allows using `a..=b` and `..=b` as inclusive range syntaxes. - (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), - // Allows `..=` in patterns (RFC 1192). - (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None), - // Allows `fn main()` with return types which implements `Termination` (RFC 1937). - (accepted, termination_trait, "1.26.0", Some(43301), None), - // Allows implementing `Clone` for closures where possible (RFC 2132). - (accepted, clone_closures, "1.26.0", Some(44490), None), - // Allows implementing `Copy` for closures where possible (RFC 2132). - (accepted, copy_closures, "1.26.0", Some(44490), None), - // Allows `impl Trait` in function arguments. - (accepted, universal_impl_trait, "1.26.0", Some(34511), None), - // Allows `impl Trait` in function return types. - (accepted, conservative_impl_trait, "1.26.0", Some(34511), None), - // Allows using the `u128` and `i128` types. - (accepted, i128_type, "1.26.0", Some(35118), None), - // Allows default match binding modes (RFC 2005). - (accepted, match_default_bindings, "1.26.0", Some(42640), None), - // Allows `'_` placeholder lifetimes. - (accepted, underscore_lifetimes, "1.26.0", Some(44524), None), - // Allows attributes on lifetime/type formal parameters in generics (RFC 1327). - (accepted, generic_param_attrs, "1.27.0", Some(48848), None), - // Allows `cfg(target_feature = "...")`. - (accepted, cfg_target_feature, "1.27.0", Some(29717), None), - // Allows `#[target_feature(...)]`. - (accepted, target_feature, "1.27.0", None, None), - // Allows using `dyn Trait` as a syntax for trait objects. - (accepted, dyn_trait, "1.27.0", Some(44662), None), - // Allows `#[must_use]` on functions, and introduces 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), - // Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). - (accepted, termination_trait_test, "1.27.0", Some(48854), None), - // Allows the `#[global_allocator]` attribute. - (accepted, global_allocator, "1.28.0", Some(27389), None), - // Allows `#[repr(transparent)]` attribute on newtype structs. - (accepted, repr_transparent, "1.28.0", Some(43036), None), - // Allows procedural macros in `proc-macro` crates. - (accepted, proc_macro, "1.29.0", Some(38356), None), - // Allows `foo.rs` as an alternative to `foo/mod.rs`. - (accepted, non_modrs_mods, "1.30.0", Some(44660), None), - // Allows use of the `:vis` macro fragment specifier - (accepted, macro_vis_matcher, "1.30.0", Some(41022), None), - // Allows importing and reexporting macros with `use`, - // enables macro modularization in general. - (accepted, use_extern_macros, "1.30.0", Some(35896), None), - // Allows keywords to be escaped for use as identifiers. - (accepted, raw_identifiers, "1.30.0", Some(48589), None), - // Allows attributes scoped to tools. - (accepted, tool_attributes, "1.30.0", Some(44690), None), - // Allows multi-segment paths in attributes and derives. - (accepted, proc_macro_path_invoc, "1.30.0", Some(38356), None), - // Allows all literals in attribute lists and values of key-value pairs. - (accepted, attr_literals, "1.30.0", Some(34981), None), - // Allows inferring outlives requirements (RFC 2093). - (accepted, infer_outlives_requirements, "1.30.0", Some(44493), None), - // Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`. - // This defines the behavior of panics. - (accepted, panic_handler, "1.30.0", Some(44489), None), - // Allows `#[used]` to preserve symbols (see llvm.used). - (accepted, used, "1.30.0", Some(40289), None), - // Allows `crate` in paths. - (accepted, crate_in_paths, "1.30.0", Some(45477), None), - // Allows resolving absolute paths as paths from other crates. - (accepted, extern_absolute_paths, "1.30.0", Some(44660), None), - // Allows access to crate names passed via `--extern` through prelude. - (accepted, extern_prelude, "1.30.0", Some(44660), None), - // Allows parentheses in patterns. - (accepted, pattern_parentheses, "1.31.0", Some(51087), None), - // Allows the definition of `const fn` functions. - (accepted, min_const_fn, "1.31.0", Some(53555), None), - // Allows scoped lints. - (accepted, tool_lints, "1.31.0", Some(44690), None), - // Allows lifetime elision in `impl` headers. For example: - // + `impl Iterator for &mut Iterator` - // + `impl Debug for Foo<'_>` - (accepted, impl_header_lifetime_elision, "1.31.0", Some(15872), None), - // Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. - (accepted, extern_crate_item_prelude, "1.31.0", Some(55599), None), - // Allows use of the `:literal` macro fragment specifier (RFC 1576). - (accepted, macro_literal_matcher, "1.32.0", Some(35625), None), - // Allows use of `?` as the Kleene "at most one" operator in macros. - (accepted, macro_at_most_once_rep, "1.32.0", Some(48075), None), - // Allows `Self` struct constructor (RFC 2302). - (accepted, self_struct_ctor, "1.32.0", Some(51994), None), - // Allows `Self` in type definitions (RFC 2300). - (accepted, self_in_typedefs, "1.32.0", Some(49303), None), - // Allows `use x::y;` to search `x` in the current scope. - (accepted, uniform_paths, "1.32.0", Some(53130), None), - // Allows integer match exhaustiveness checking (RFC 2591). - (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907), None), - // Allows `use path as _;` and `extern crate c as _;`. - (accepted, underscore_imports, "1.33.0", Some(48216), None), - // Allows `#[repr(packed(N))]` attribute on structs. - (accepted, repr_packed, "1.33.0", Some(33158), None), - // Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086). - (accepted, irrefutable_let_patterns, "1.33.0", Some(44495), None), - // Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions. - (accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None), - // Allows let bindings, assignments and destructuring in `const` functions and constants. - // As long as control flow is not implemented in const eval, `&&` and `||` may not be used - // at the same time as let bindings. - (accepted, const_let, "1.33.0", Some(48821), None), - // Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. - (accepted, cfg_attr_multi, "1.33.0", Some(54881), None), - // Allows top level or-patterns (`p | q`) in `if let` and `while let`. - (accepted, if_while_or_patterns, "1.33.0", Some(48215), None), - // Allows `cfg(target_vendor = "...")`. - (accepted, cfg_target_vendor, "1.33.0", Some(29718), None), - // Allows `extern crate self as foo;`. - // This puts local crate root into extern prelude under name `foo`. - (accepted, extern_crate_self, "1.34.0", Some(56409), None), - // Allows arbitrary delimited token streams in non-macro attributes. - (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208), None), - // Allows paths to enum variants on type aliases including `Self`. - (accepted, type_alias_enum_variants, "1.37.0", Some(49683), None), - // Allows using `#[repr(align(X))]` on enums with equivalent semantics - // to wrapping an enum in a wrapper struct with `#[repr(align(X))]`. - (accepted, repr_align_enum, "1.37.0", Some(57996), None), - // Allows `const _: TYPE = VALUE`. - (accepted, underscore_const_names, "1.37.0", Some(54912), None), - - // ------------------------------------------------------------------------- - // feature-group-end: accepted features - // ------------------------------------------------------------------------- -); - -// If you change this, please modify `src/doc/unstable-book` as well. You must -// move that documentation into the relevant place in the other docs, and -// remove the chapter on the flag. - -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum AttributeType { - /// Normal, builtin attribute that is consumed - /// by the compiler before the unused_attribute check - Normal, - - /// Builtin attribute that may not be consumed by the compiler - /// before the unused_attribute check. These attributes - /// will be ignored by the unused_attribute lint - Whitelisted, - - /// Builtin attribute that is only allowed at the crate level - CrateLevel, -} - -pub enum AttributeGate { - /// Is gated by a given feature gate, reason - /// and function to check if enabled - Gated(Stability, Symbol, &'static str, fn(&Features) -> bool), - - /// Ungated attribute, can be used on all release channels - Ungated, -} - -/// A convenience macro for constructing attribute templates. -/// E.g., `template!(Word, List: "description")` means that the attribute -/// supports forms `#[attr]` and `#[attr(description)]`. -macro_rules! template { - (Word) => { template!(@ true, None, None) }; - (List: $descr: expr) => { template!(@ false, Some($descr), None) }; - (NameValueStr: $descr: expr) => { template!(@ false, None, Some($descr)) }; - (Word, List: $descr: expr) => { template!(@ true, Some($descr), None) }; - (Word, NameValueStr: $descr: expr) => { template!(@ true, None, Some($descr)) }; - (List: $descr1: expr, NameValueStr: $descr2: expr) => { - template!(@ false, Some($descr1), Some($descr2)) - }; - (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => { - template!(@ true, Some($descr1), Some($descr2)) - }; - (@ $word: expr, $list: expr, $name_value_str: expr) => { AttributeTemplate { - word: $word, list: $list, name_value_str: $name_value_str - } }; -} - -impl AttributeGate { - fn is_deprecated(&self) -> bool { - match *self { - Gated(Stability::Deprecated(_, _), ..) => true, - _ => false, - } - } -} - -#[derive(Copy, Clone, Debug)] -pub enum Stability { - Unstable, - // First argument is tracking issue link; second argument is an optional - // help message, which defaults to "remove this attribute" - Deprecated(&'static str, Option<&'static str>), -} - -// fn() is not Debug -impl std::fmt::Debug for AttributeGate { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - Gated(ref stab, name, expl, _) => - write!(fmt, "Gated({:?}, {}, {})", stab, name, expl), - Ungated => write!(fmt, "Ungated") - } - } -} - -macro_rules! cfg_fn { - ($field: ident) => {{ - fn f(features: &Features) -> bool { - features.$field - } - f as fn(&Features) -> bool - }} -} - -pub fn deprecated_attributes() -> Vec<&'static (Symbol, AttributeType, - AttributeTemplate, AttributeGate)> { - BUILTIN_ATTRIBUTES.iter().filter(|(.., gate)| gate.is_deprecated()).collect() -} - -pub fn is_builtin_attr_name(name: ast::Name) -> bool { - BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() -} - -pub fn is_builtin_attr(attr: &ast::Attribute) -> bool { - attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).is_some() -} - -/// Attributes that have a special meaning to rustc or rustdoc -pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ - // Normal attributes - - ( - sym::warn, - Normal, - template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - Ungated - ), - ( - sym::allow, - Normal, - template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - Ungated - ), - ( - sym::forbid, - Normal, - template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - Ungated - ), - ( - sym::deny, - Normal, - template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - Ungated - ), - - (sym::macro_use, Normal, template!(Word, List: "name1, name2, ..."), Ungated), - (sym::macro_export, Normal, template!(Word, List: "local_inner_macros"), Ungated), - (sym::plugin_registrar, Normal, template!(Word), Ungated), - - (sym::cfg, Normal, template!(List: "predicate"), Ungated), - (sym::cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), Ungated), - (sym::main, Normal, template!(Word), Ungated), - (sym::start, Normal, template!(Word), Ungated), - (sym::repr, Normal, template!(List: "C, packed, ..."), Ungated), - (sym::path, Normal, template!(NameValueStr: "file"), Ungated), - (sym::automatically_derived, Normal, template!(Word), Ungated), - (sym::no_mangle, Whitelisted, template!(Word), Ungated), - (sym::no_link, Normal, template!(Word), Ungated), - (sym::derive, Normal, template!(List: "Trait1, Trait2, ..."), Ungated), - ( - sym::should_panic, - Normal, - template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), - Ungated - ), - (sym::ignore, Normal, template!(Word, NameValueStr: "reason"), Ungated), - (sym::no_implicit_prelude, Normal, template!(Word), Ungated), - (sym::reexport_test_harness_main, Normal, template!(NameValueStr: "name"), Ungated), - (sym::link_args, Normal, template!(NameValueStr: "args"), Gated(Stability::Unstable, - sym::link_args, - "the `link_args` attribute is experimental and not \ - portable across platforms, it is recommended to \ - use `#[link(name = \"foo\")] instead", - cfg_fn!(link_args))), - (sym::macro_escape, Normal, template!(Word), Ungated), - - // RFC #1445. - (sym::structural_match, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::structural_match, - "the semantics of constant patterns is \ - not yet settled", - cfg_fn!(structural_match))), - - // RFC #2008 - (sym::non_exhaustive, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::non_exhaustive, - "non exhaustive is an experimental feature", - cfg_fn!(non_exhaustive))), - - // RFC #1268 - (sym::marker, Normal, template!(Word), Gated(Stability::Unstable, - sym::marker_trait_attr, - "marker traits is an experimental feature", - cfg_fn!(marker_trait_attr))), - - (sym::plugin, CrateLevel, template!(List: "name|name(args)"), Gated(Stability::Unstable, - sym::plugin, - "compiler plugins are experimental \ - and possibly buggy", - cfg_fn!(plugin))), - - (sym::no_std, CrateLevel, template!(Word), Ungated), - (sym::no_core, CrateLevel, template!(Word), Gated(Stability::Unstable, - sym::no_core, - "no_core is experimental", - cfg_fn!(no_core))), - (sym::lang, Normal, template!(NameValueStr: "name"), Gated(Stability::Unstable, - sym::lang_items, - "language items are subject to change", - cfg_fn!(lang_items))), - (sym::linkage, Whitelisted, template!(NameValueStr: "external|internal|..."), - Gated(Stability::Unstable, - sym::linkage, - "the `linkage` attribute is experimental \ - and not portable across platforms", - cfg_fn!(linkage))), - (sym::thread_local, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::thread_local, - "`#[thread_local]` is an experimental feature, and does \ - not currently handle destructors", - cfg_fn!(thread_local))), - - (sym::rustc_on_unimplemented, Whitelisted, template!(List: - r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, - NameValueStr: "message"), - Gated(Stability::Unstable, - sym::on_unimplemented, - "the `#[rustc_on_unimplemented]` attribute \ - is an experimental feature", - cfg_fn!(on_unimplemented))), - (sym::rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), - Gated(Stability::Unstable, - sym::rustc_const_unstable, - "the `#[rustc_const_unstable]` attribute \ - is an internal feature", - cfg_fn!(rustc_const_unstable))), - (sym::default_lib_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::allocator_internals, - "the `#[default_lib_allocator]` \ - attribute is an experimental feature", - cfg_fn!(allocator_internals))), - (sym::needs_allocator, Normal, template!(Word), Gated(Stability::Unstable, - sym::allocator_internals, - "the `#[needs_allocator]` \ - attribute is an experimental \ - feature", - cfg_fn!(allocator_internals))), - (sym::panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::panic_runtime, - "the `#[panic_runtime]` attribute is \ - an experimental feature", - cfg_fn!(panic_runtime))), - (sym::needs_panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::needs_panic_runtime, - "the `#[needs_panic_runtime]` \ - attribute is an experimental \ - feature", - cfg_fn!(needs_panic_runtime))), - (sym::rustc_outlives, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_outlives]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_variance, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_variance]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_layout, Normal, template!(List: "field1, field2, ..."), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_layout]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_layout_scalar_valid_range_start, Whitelisted, template!(List: "value"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_layout_scalar_valid_range_start]` attribute \ - is just used to enable niche optimizations in libcore \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_layout_scalar_valid_range_end, Whitelisted, template!(List: "value"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_layout_scalar_valid_range_end]` attribute \ - is just used to enable niche optimizations in libcore \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_nonnull_optimization_guaranteed, Whitelisted, template!(Word), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_nonnull_optimization_guaranteed]` attribute \ - is just used to enable niche optimizations in libcore \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_regions, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_regions]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_error, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_error]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_dump_user_substs, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_if_this_changed]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_then_this_would_need, Whitelisted, template!(List: "DepNode"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_if_this_changed]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_dirty, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", - /*opt*/ except = "...""#), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_dirty]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_clean, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", - /*opt*/ except = "...""#), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_clean]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - ( - sym::rustc_partition_reused, - Whitelisted, - template!(List: r#"cfg = "...", module = "...""#), - Gated( - Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs) - ) - ), - ( - sym::rustc_partition_codegened, - Whitelisted, - template!(List: r#"cfg = "...", module = "...""#), - Gated( - Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs), - ) - ), - (sym::rustc_expected_cgu_reuse, Whitelisted, template!(List: r#"cfg = "...", module = "...", - kind = "...""#), - Gated(Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_synthetic, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_symbol_name, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal rustc attributes will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_def_path, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal rustc attributes will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_mir, Whitelisted, template!(List: "arg1, arg2, ..."), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_mir]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - ( - sym::rustc_inherit_overflow_checks, - Whitelisted, - template!(Word), - Gated( - Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_inherit_overflow_checks]` \ - attribute is just used to control \ - overflow checking behavior of several \ - libcore functions that are inlined \ - across crates and will never be stable", - cfg_fn!(rustc_attrs), - ) - ), - - (sym::rustc_dump_program_clauses, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_dump_program_clauses]` \ - attribute is just used for rustc unit \ - tests and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_dump_env_program_clauses, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_dump_env_program_clauses]` \ - attribute is just used for rustc unit \ - tests and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_object_lifetime_default, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_object_lifetime_default]` \ - attribute is just used for rustc unit \ - tests and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_test_marker, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_test_marker]` attribute \ - is used internally to track tests", - cfg_fn!(rustc_attrs))), - (sym::rustc_macro_transparency, Whitelisted, template!(NameValueStr: - "transparent|semitransparent|opaque"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "used internally for testing macro hygiene", - cfg_fn!(rustc_attrs))), - (sym::compiler_builtins, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::compiler_builtins, - "the `#[compiler_builtins]` attribute is used to \ - identify the `compiler_builtins` crate which \ - contains compiler-rt intrinsics and will never be \ - stable", - cfg_fn!(compiler_builtins))), - (sym::sanitizer_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::sanitizer_runtime, - "the `#[sanitizer_runtime]` attribute is used to \ - identify crates that contain the runtime of a \ - sanitizer and will never be stable", - cfg_fn!(sanitizer_runtime))), - (sym::profiler_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::profiler_runtime, - "the `#[profiler_runtime]` attribute is used to \ - identify the `profiler_builtins` crate which \ - contains the profiler runtime and will never be \ - stable", - cfg_fn!(profiler_runtime))), - - (sym::allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), - Gated(Stability::Unstable, - sym::allow_internal_unstable, - EXPLAIN_ALLOW_INTERNAL_UNSTABLE, - cfg_fn!(allow_internal_unstable))), - - (sym::allow_internal_unsafe, Normal, template!(Word), Gated(Stability::Unstable, - sym::allow_internal_unsafe, - EXPLAIN_ALLOW_INTERNAL_UNSAFE, - cfg_fn!(allow_internal_unsafe))), - - (sym::fundamental, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::fundamental, - "the `#[fundamental]` attribute \ - is an experimental feature", - cfg_fn!(fundamental))), - - (sym::proc_macro_derive, Normal, template!(List: "TraitName, \ - /*opt*/ attributes(name1, name2, ...)"), - Ungated), - - (sym::rustc_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_allocator_nounwind, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_builtin_macro, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_promotable, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_allow_const_fn_ptr, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_dummy, Normal, template!(Word /* doesn't matter*/), Gated(Stability::Unstable, - sym::rustc_attrs, - "used by the test suite", - cfg_fn!(rustc_attrs))), - - // FIXME: #14408 whitelist docs since rustdoc looks at them - ( - sym::doc, - Whitelisted, - template!(List: "hidden|inline|...", NameValueStr: "string"), - Ungated - ), - - // FIXME: #14406 these are processed in codegen, which happens after the - // lint pass - (sym::cold, Whitelisted, template!(Word), Ungated), - (sym::naked, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::naked_functions, - "the `#[naked]` attribute \ - is an experimental feature", - cfg_fn!(naked_functions))), - (sym::ffi_returns_twice, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::ffi_returns_twice, - "the `#[ffi_returns_twice]` attribute \ - is an experimental feature", - cfg_fn!(ffi_returns_twice))), - (sym::target_feature, Whitelisted, template!(List: r#"enable = "name""#), Ungated), - (sym::export_name, Whitelisted, template!(NameValueStr: "name"), Ungated), - (sym::inline, Whitelisted, template!(Word, List: "always|never"), Ungated), - (sym::link, Whitelisted, template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", - /*opt*/ cfg = "...""#), Ungated), - (sym::link_name, Whitelisted, template!(NameValueStr: "name"), Ungated), - (sym::link_section, Whitelisted, template!(NameValueStr: "name"), Ungated), - (sym::no_builtins, Whitelisted, template!(Word), Ungated), - (sym::no_debug, Whitelisted, template!(Word), Gated( - Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721", None), - sym::no_debug, - "the `#[no_debug]` attribute was an experimental feature that has been \ - deprecated due to lack of demand", - cfg_fn!(no_debug))), - ( - sym::omit_gdb_pretty_printer_section, - Whitelisted, - template!(Word), - Gated( - Stability::Unstable, - sym::omit_gdb_pretty_printer_section, - "the `#[omit_gdb_pretty_printer_section]` \ - attribute is just used for the Rust test \ - suite", - cfg_fn!(omit_gdb_pretty_printer_section) - ) - ), - (sym::may_dangle, - Normal, - template!(Word), - Gated(Stability::Unstable, - sym::dropck_eyepatch, - "`may_dangle` has unstable semantics and may be removed in the future", - cfg_fn!(dropck_eyepatch))), - (sym::unwind, Whitelisted, template!(List: "allowed|aborts"), Gated(Stability::Unstable, - sym::unwind_attributes, - "`#[unwind]` is experimental", - cfg_fn!(unwind_attributes))), - (sym::used, Whitelisted, template!(Word), Ungated), - - // used in resolve - (sym::prelude_import, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::prelude_import, - "`#[prelude_import]` is for use by rustc only", - cfg_fn!(prelude_import))), - - // FIXME: #14407 these are only looked at on-demand so we can't - // guarantee they'll have already been checked - ( - sym::rustc_deprecated, - Whitelisted, - template!(List: r#"since = "version", reason = "...""#), - Ungated - ), - (sym::must_use, Whitelisted, template!(Word, NameValueStr: "reason"), Ungated), - ( - sym::stable, - Whitelisted, - template!(List: r#"feature = "name", since = "version""#), - Ungated - ), - ( - sym::unstable, - Whitelisted, - template!(List: r#"feature = "name", reason = "...", issue = "N""#), - Ungated - ), - (sym::deprecated, - Normal, - template!( - Word, - List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#, - NameValueStr: "reason" - ), - Ungated - ), - - (sym::rustc_paren_sugar, Normal, template!(Word), Gated(Stability::Unstable, - sym::unboxed_closures, - "unboxed_closures are still evolving", - cfg_fn!(unboxed_closures))), - - (sym::windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console"), Ungated), - - (sym::proc_macro_attribute, Normal, template!(Word), Ungated), - (sym::proc_macro, Normal, template!(Word), Ungated), - - (sym::rustc_proc_macro_decls, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "used internally by rustc", - cfg_fn!(rustc_attrs))), - - (sym::allow_fail, Normal, template!(Word), Gated(Stability::Unstable, - sym::allow_fail, - "allow_fail attribute is currently unstable", - cfg_fn!(allow_fail))), - - (sym::rustc_std_internal_symbol, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "this is an internal attribute that will \ - never be stable", - cfg_fn!(rustc_attrs))), - - // whitelists "identity-like" conversion methods to suggest on type mismatch - (sym::rustc_conversion_suggestion, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "this is an internal attribute that will \ - never be stable", - cfg_fn!(rustc_attrs))), - - ( - sym::rustc_args_required_const, - Whitelisted, - template!(List: "N"), - Gated(Stability::Unstable, sym::rustc_attrs, "never will be stable", - cfg_fn!(rustc_attrs)) - ), - // RFC 2070 - (sym::panic_handler, Normal, template!(Word), Ungated), - - (sym::alloc_error_handler, Normal, template!(Word), Gated(Stability::Unstable, - sym::alloc_error_handler, - "`#[alloc_error_handler]` is an unstable feature", - cfg_fn!(alloc_error_handler))), - - // RFC 2412 - (sym::optimize, Whitelisted, template!(List: "size|speed"), Gated(Stability::Unstable, - sym::optimize_attribute, - "`#[optimize]` attribute is an unstable feature", - cfg_fn!(optimize_attribute))), - - // Crate level attributes - (sym::crate_name, CrateLevel, template!(NameValueStr: "name"), Ungated), - (sym::crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), Ungated), - (sym::crate_id, CrateLevel, template!(NameValueStr: "ignored"), Ungated), - (sym::feature, CrateLevel, template!(List: "name1, name1, ..."), Ungated), - (sym::no_start, CrateLevel, template!(Word), Ungated), - (sym::no_main, CrateLevel, template!(Word), Ungated), - (sym::recursion_limit, CrateLevel, template!(NameValueStr: "N"), Ungated), - (sym::type_length_limit, CrateLevel, template!(NameValueStr: "N"), Ungated), - (sym::test_runner, CrateLevel, template!(List: "path"), Gated(Stability::Unstable, - sym::custom_test_frameworks, - "custom test frameworks are an unstable feature", - cfg_fn!(custom_test_frameworks))), -]; - -pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate); - -lazy_static! { - pub static ref BUILTIN_ATTRIBUTE_MAP: FxHashMap = { - let mut map = FxHashMap::default(); - for attr in BUILTIN_ATTRIBUTES.iter() { - if map.insert(attr.0, attr).is_some() { - panic!("duplicate builtin attribute `{}`", attr.0); - } - } - map - }; -} - -// cfg(...)'s that are feature gated -const GATED_CFGS: &[(Symbol, Symbol, fn(&Features) -> bool)] = &[ - // (name in cfg, feature, function to check if the feature is enabled) - (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), - (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), - (sym::rustdoc, sym::doc_cfg, cfg_fn!(doc_cfg)), - (sym::doctest, sym::cfg_doctest, cfg_fn!(cfg_doctest)), -]; - -#[derive(Debug)] -pub struct GatedCfg { - span: Span, - index: usize, -} - -impl GatedCfg { - pub fn gate(cfg: &ast::MetaItem) -> Option { - GATED_CFGS.iter() - .position(|info| cfg.check_name(info.0)) - .map(|idx| { - GatedCfg { - span: cfg.span, - index: idx - } - }) - } - - pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) { - let (cfg, feature, has_feature) = GATED_CFGS[self.index]; - if !has_feature(features) && !self.span.allows_unstable(feature) { - let explain = format!("`cfg({})` is experimental and subject to change", cfg); - emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain); - } - } -} - -struct Context<'a> { - features: &'a Features, - parse_sess: &'a ParseSess, - plugin_attributes: &'a [(Symbol, AttributeType)], -} - -macro_rules! gate_feature_fn { - ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{ - let (cx, has_feature, span, - name, explain, level) = ($cx, $has_feature, $span, $name, $explain, $level); - let has_feature: bool = has_feature(&$cx.features); - debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); - if !has_feature && !span.allows_unstable($name) { - leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level) - .emit(); - } - }} -} - -macro_rules! gate_feature { - ($cx: expr, $feature: ident, $span: expr, $explain: expr) => { - gate_feature_fn!($cx, |x:&Features| x.$feature, $span, - sym::$feature, $explain, GateStrength::Hard) - }; - ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => { - gate_feature_fn!($cx, |x:&Features| x.$feature, $span, - sym::$feature, $explain, $level) - }; -} - -impl<'a> Context<'a> { - fn check_attribute( - &self, - attr: &ast::Attribute, - attr_info: Option<&BuiltinAttribute>, - is_macro: bool - ) { - debug!("check_attribute(attr = {:?})", attr); - if let Some(&(name, ty, _template, ref gateage)) = attr_info { - if let Gated(_, name, desc, ref has_feature) = *gateage { - if !attr.span.allows_unstable(name) { - gate_feature_fn!( - self, has_feature, attr.span, name, desc, GateStrength::Hard - ); - } - } else if name == sym::doc { - if let Some(content) = attr.meta_item_list() { - if content.iter().any(|c| c.check_name(sym::include)) { - gate_feature!(self, external_doc, attr.span, - "`#[doc(include = \"...\")]` is experimental" - ); - } - } - } - debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage); - return; - } else { - for segment in &attr.path.segments { - if segment.ident.as_str().starts_with("rustc") { - let msg = "attributes starting with `rustc` are \ - reserved for use by the `rustc` compiler"; - gate_feature!(self, rustc_attrs, segment.ident.span, msg); - } - } - } - for &(n, ty) in self.plugin_attributes { - if attr.path == n { - // Plugins can't gate attributes, so we don't check for it - // unlike the code above; we only use this loop to - // short-circuit to avoid the checks below. - debug!("check_attribute: {:?} is registered by a plugin, {:?}", attr.path, ty); - return; - } - } - if !is_macro && !attr::is_known(attr) { - // Only run the custom attribute lint during regular feature gate - // checking. Macro gating runs before the plugin attributes are - // registered, so we skip this in that case. - let msg = format!("the attribute `{}` is currently unknown to the compiler and \ - may have meaning added to it in the future", attr.path); - gate_feature!(self, custom_attribute, attr.span, &msg); - } - } -} - -pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) { - let cx = Context { features, parse_sess, plugin_attributes: &[] }; - cx.check_attribute( - attr, - attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name).map(|a| *a)), - true - ); -} - -fn find_lang_feature_issue(feature: Symbol) -> Option { - if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) { - let issue = info.2; - // FIXME (#28244): enforce that active features have issue numbers - // assert!(issue.is_some()) - issue - } else { - // search in Accepted, Removed, or Stable Removed features - let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES) - .find(|t| t.0 == feature); - match found { - Some(&(_, _, issue, _)) => issue, - None => panic!("Feature `{}` is not declared anywhere", feature), - } - } -} - -pub enum GateIssue { - Language, - Library(Option) -} - -#[derive(Debug, Copy, Clone, PartialEq)] -pub enum GateStrength { - /// A hard error. (Most feature gates should use this.) - Hard, - /// Only a warning. (Use this only as backwards-compatibility demands.) - Soft, -} - -pub fn emit_feature_err( - sess: &ParseSess, - feature: Symbol, - span: Span, - issue: GateIssue, - explain: &str, -) { - feature_err(sess, feature, span, issue, explain).emit(); -} - -pub fn feature_err<'a, S: Into>( - sess: &'a ParseSess, - feature: Symbol, - span: S, - issue: GateIssue, - explain: &str, -) -> DiagnosticBuilder<'a> { - leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard) -} - -fn leveled_feature_err<'a, S: Into>( - sess: &'a ParseSess, - feature: Symbol, - span: S, - issue: GateIssue, - explain: &str, - level: GateStrength, -) -> DiagnosticBuilder<'a> { - let diag = &sess.span_diagnostic; - - let issue = match issue { - GateIssue::Language => find_lang_feature_issue(feature), - GateIssue::Library(lib) => lib, - }; - - let mut err = match level { - GateStrength::Hard => { - diag.struct_span_err_with_code(span, explain, stringify_error_code!(E0658)) - } - GateStrength::Soft => diag.struct_span_warn(span, explain), - }; - - match issue { - None | Some(0) => {} // We still accept `0` as a stand-in for backwards compatibility - Some(n) => { - err.note(&format!( - "for more information, see https://github.com/rust-lang/rust/issues/{}", - n, - )); - } - } - - // #23973: do not suggest `#![feature(...)]` if we are in beta/stable - if sess.unstable_features.is_nightly_build() { - err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature)); - } - - // If we're on stable and only emitting a "soft" warning, add a note to - // clarify that the feature isn't "on" (rather than being on but - // warning-worthy). - if !sess.unstable_features.is_nightly_build() && level == GateStrength::Soft { - err.help("a nightly build of the compiler is required to enable this feature"); - } - - err - -} - -const EXPLAIN_BOX_SYNTAX: &str = - "box expression syntax is experimental; you can call `Box::new` instead"; - -pub const EXPLAIN_STMT_ATTR_SYNTAX: &str = - "attributes on expressions are experimental"; - -pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &str = - "allow_internal_unstable side-steps feature gating and stability checks"; -pub const EXPLAIN_ALLOW_INTERNAL_UNSAFE: &str = - "allow_internal_unsafe side-steps the unsafe_code lint"; - -pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &str = - "unsized tuple coercion is not stable enough for use and is subject to change"; - -struct PostExpansionVisitor<'a> { - context: &'a Context<'a>, - builtin_attributes: &'static FxHashMap, -} - -macro_rules! gate_feature_post { - ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{ - let (cx, span) = ($cx, $span); - if !span.allows_unstable(sym::$feature) { - gate_feature!(cx.context, $feature, span, $explain) - } - }}; - ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{ - let (cx, span) = ($cx, $span); - if !span.allows_unstable(sym::$feature) { - gate_feature!(cx.context, $feature, span, $explain, $level) - } - }} -} - -impl<'a> PostExpansionVisitor<'a> { - fn check_abi(&self, abi: Abi, span: Span) { - match abi { - Abi::RustIntrinsic => { - gate_feature_post!(&self, intrinsics, span, - "intrinsics are subject to change"); - }, - Abi::PlatformIntrinsic => { - gate_feature_post!(&self, platform_intrinsics, span, - "platform intrinsics are experimental and possibly buggy"); - }, - Abi::Vectorcall => { - gate_feature_post!(&self, abi_vectorcall, span, - "vectorcall is experimental and subject to change"); - }, - Abi::Thiscall => { - gate_feature_post!(&self, abi_thiscall, span, - "thiscall is experimental and subject to change"); - }, - Abi::RustCall => { - gate_feature_post!(&self, unboxed_closures, span, - "rust-call ABI is subject to change"); - }, - Abi::PtxKernel => { - gate_feature_post!(&self, abi_ptx, span, - "PTX ABIs are experimental and subject to change"); - }, - Abi::Unadjusted => { - gate_feature_post!(&self, abi_unadjusted, span, - "unadjusted ABI is an implementation detail and perma-unstable"); - }, - Abi::Msp430Interrupt => { - gate_feature_post!(&self, abi_msp430_interrupt, span, - "msp430-interrupt ABI is experimental and subject to change"); - }, - Abi::X86Interrupt => { - gate_feature_post!(&self, abi_x86_interrupt, span, - "x86-interrupt ABI is experimental and subject to change"); - }, - Abi::AmdGpuKernel => { - gate_feature_post!(&self, abi_amdgpu_kernel, span, - "amdgpu-kernel ABI is experimental and subject to change"); - }, - // Stable - Abi::Cdecl | - Abi::Stdcall | - Abi::Fastcall | - Abi::Aapcs | - Abi::Win64 | - Abi::SysV64 | - Abi::Rust | - Abi::C | - Abi::System => {} - } - } -} - -impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { - fn visit_attribute(&mut self, attr: &ast::Attribute) { - let attr_info = attr.ident().and_then(|ident| { - self.builtin_attributes.get(&ident.name).map(|a| *a) - }); - - // Check for gated attributes. - self.context.check_attribute(attr, attr_info, false); - - if attr.check_name(sym::doc) { - if let Some(content) = attr.meta_item_list() { - if content.len() == 1 && content[0].check_name(sym::cfg) { - gate_feature_post!(&self, doc_cfg, attr.span, - "`#[doc(cfg(...))]` is experimental" - ); - } else if content.iter().any(|c| c.check_name(sym::masked)) { - gate_feature_post!(&self, doc_masked, attr.span, - "`#[doc(masked)]` is experimental" - ); - } else if content.iter().any(|c| c.check_name(sym::spotlight)) { - gate_feature_post!(&self, doc_spotlight, attr.span, - "`#[doc(spotlight)]` is experimental" - ); - } else if content.iter().any(|c| c.check_name(sym::alias)) { - gate_feature_post!(&self, doc_alias, attr.span, - "`#[doc(alias = \"...\")]` is experimental" - ); - } else if content.iter().any(|c| c.check_name(sym::keyword)) { - gate_feature_post!(&self, doc_keyword, attr.span, - "`#[doc(keyword = \"...\")]` is experimental" - ); - } - } - } - - match attr_info { - // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. - Some(&(name, _, template, _)) if name != sym::rustc_dummy => - check_builtin_attribute(self.context.parse_sess, attr, name, template), - _ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() { - if token == token::Eq { - // All key-value attributes are restricted to meta-item syntax. - attr.parse_meta(self.context.parse_sess).map_err(|mut err| err.emit()).ok(); - } - } - } - } - - fn visit_name(&mut self, sp: Span, name: ast::Name) { - if !name.as_str().is_ascii() { - gate_feature_post!( - &self, - non_ascii_idents, - self.context.parse_sess.source_map().def_span(sp), - "non-ascii idents are not fully supported" - ); - } - } - - fn visit_item(&mut self, i: &'a ast::Item) { - match i.node { - ast::ItemKind::ForeignMod(ref foreign_module) => { - self.check_abi(foreign_module.abi, i.span); - } - - ast::ItemKind::Fn(..) => { - if attr::contains_name(&i.attrs[..], sym::plugin_registrar) { - gate_feature_post!(&self, plugin_registrar, i.span, - "compiler plugins are experimental and possibly buggy"); - } - if attr::contains_name(&i.attrs[..], sym::start) { - gate_feature_post!(&self, start, i.span, - "a `#[start]` function is an experimental \ - feature whose signature may change \ - over time"); - } - if attr::contains_name(&i.attrs[..], sym::main) { - gate_feature_post!(&self, main, i.span, - "declaration of a non-standard `#[main]` \ - function may change over time, for now \ - a top-level `fn main()` is required"); - } - } - - ast::ItemKind::Struct(..) => { - for attr in attr::filter_by_name(&i.attrs[..], sym::repr) { - for item in attr.meta_item_list().unwrap_or_else(Vec::new) { - if item.check_name(sym::simd) { - gate_feature_post!(&self, repr_simd, attr.span, - "SIMD types are experimental and possibly buggy"); - } - } - } - } - - ast::ItemKind::Enum(ast::EnumDef{ref variants, ..}, ..) => { - for variant in variants { - match (&variant.node.data, &variant.node.disr_expr) { - (ast::VariantData::Unit(..), _) => {}, - (_, Some(disr_expr)) => - gate_feature_post!( - &self, - arbitrary_enum_discriminant, - disr_expr.value.span, - "discriminants on non-unit variants are experimental"), - _ => {}, - } - } - - let has_feature = self.context.features.arbitrary_enum_discriminant; - if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) { - Parser::maybe_report_invalid_custom_discriminants( - self.context.parse_sess, - &variants, - ); - } - } - - ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => { - if polarity == ast::ImplPolarity::Negative { - gate_feature_post!(&self, optin_builtin_traits, - i.span, - "negative trait bounds are not yet fully implemented; \ - use marker types for now"); - } - - if let ast::Defaultness::Default = defaultness { - gate_feature_post!(&self, specialization, - i.span, - "specialization is unstable"); - } - } - - ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => { - gate_feature_post!(&self, optin_builtin_traits, - i.span, - "auto traits are experimental and possibly buggy"); - } - - ast::ItemKind::TraitAlias(..) => { - gate_feature_post!( - &self, - trait_alias, - i.span, - "trait aliases are experimental" - ); - } - - ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => { - let msg = "`macro` is experimental"; - gate_feature_post!(&self, decl_macro, i.span, msg); - } - - ast::ItemKind::OpaqueTy(..) => { - gate_feature_post!( - &self, - type_alias_impl_trait, - i.span, - "`impl Trait` in type aliases is unstable" - ); - } - - _ => {} - } - - visit::walk_item(self, i); - } - - fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) { - match i.node { - ast::ForeignItemKind::Fn(..) | - ast::ForeignItemKind::Static(..) => { - let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name); - let links_to_llvm = match link_name { - Some(val) => val.as_str().starts_with("llvm."), - _ => false - }; - if links_to_llvm { - gate_feature_post!(&self, link_llvm_intrinsics, i.span, - "linking to LLVM intrinsics is experimental"); - } - } - ast::ForeignItemKind::Ty => { - gate_feature_post!(&self, extern_types, i.span, - "extern types are experimental"); - } - ast::ForeignItemKind::Macro(..) => {} - } - - visit::walk_foreign_item(self, i) - } - - fn visit_ty(&mut self, ty: &'a ast::Ty) { - match ty.node { - ast::TyKind::BareFn(ref bare_fn_ty) => { - self.check_abi(bare_fn_ty.abi, ty.span); - } - ast::TyKind::Never => { - gate_feature_post!(&self, never_type, ty.span, - "The `!` type is experimental"); - } - _ => {} - } - visit::walk_ty(self, ty) - } - - fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) { - if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty { - if let ast::TyKind::Never = output_ty.node { - // Do nothing. - } else { - self.visit_ty(output_ty) - } - } - } - - fn visit_expr(&mut self, e: &'a ast::Expr) { - match e.node { - ast::ExprKind::Box(_) => { - gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX); - } - ast::ExprKind::Type(..) => { - // To avoid noise about type ascription in common syntax errors, only emit if it - // is the *only* error. - if self.context.parse_sess.span_diagnostic.err_count() == 0 { - gate_feature_post!(&self, type_ascription, e.span, - "type ascription is experimental"); - } - } - ast::ExprKind::Yield(..) => { - gate_feature_post!(&self, generators, - e.span, - "yield syntax is experimental"); - } - ast::ExprKind::TryBlock(_) => { - gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); - } - ast::ExprKind::Block(_, opt_label) => { - if let Some(label) = opt_label { - gate_feature_post!(&self, label_break_value, label.ident.span, - "labels on blocks are unstable"); - } - } - ast::ExprKind::Async(..) => { - gate_feature_post!(&self, async_await, e.span, "async blocks are unstable"); - } - ast::ExprKind::Await(_) => { - gate_feature_post!(&self, async_await, e.span, "async/await is unstable"); - } - _ => {} - } - visit::walk_expr(self, e) - } - - fn visit_arm(&mut self, arm: &'a ast::Arm) { - visit::walk_arm(self, arm) - } - - fn visit_pat(&mut self, pattern: &'a ast::Pat) { - match &pattern.node { - PatKind::Slice(pats) => { - for pat in &*pats { - let span = pat.span; - let inner_pat = match &pat.node { - PatKind::Ident(.., Some(pat)) => pat, - _ => pat, - }; - if inner_pat.is_rest() { - gate_feature_post!( - &self, - slice_patterns, - span, - "subslice patterns are unstable" - ); - } - } - } - PatKind::Box(..) => { - gate_feature_post!(&self, box_patterns, - pattern.span, - "box pattern syntax is experimental"); - } - PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => { - gate_feature_post!(&self, exclusive_range_pattern, pattern.span, - "exclusive range pattern syntax is experimental"); - } - _ => {} - } - visit::walk_pat(self, pattern) - } - - fn visit_fn(&mut self, - fn_kind: FnKind<'a>, - fn_decl: &'a ast::FnDecl, - span: Span, - _node_id: NodeId) { - if let Some(header) = fn_kind.header() { - // Check for const fn and async fn declarations. - if header.asyncness.node.is_async() { - gate_feature_post!(&self, async_await, span, "async fn is unstable"); - } - - // Stability of const fn methods are covered in - // `visit_trait_item` and `visit_impl_item` below; this is - // because default methods don't pass through this point. - self.check_abi(header.abi, span); - } - - if fn_decl.c_variadic { - gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable"); - } - - visit::walk_fn(self, fn_kind, fn_decl, span) - } - - fn visit_generic_param(&mut self, param: &'a GenericParam) { - match param.kind { - GenericParamKind::Const { .. } => - gate_feature_post!(&self, const_generics, param.ident.span, - "const generics are unstable"), - _ => {} - } - visit::walk_generic_param(self, param) - } - - fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) { - match constraint.kind { - AssocTyConstraintKind::Bound { .. } => - gate_feature_post!(&self, associated_type_bounds, constraint.span, - "associated type bounds are unstable"), - _ => {} - } - visit::walk_assoc_ty_constraint(self, constraint) - } - - fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) { - match ti.node { - ast::TraitItemKind::Method(ref sig, ref block) => { - if block.is_none() { - self.check_abi(sig.header.abi, ti.span); - } - if sig.header.asyncness.node.is_async() { - gate_feature_post!(&self, async_await, ti.span, "async fn is unstable"); - } - if sig.decl.c_variadic { - gate_feature_post!(&self, c_variadic, ti.span, - "C-variadic functions are unstable"); - } - if sig.header.constness.node == ast::Constness::Const { - gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); - } - } - ast::TraitItemKind::Type(_, ref default) => { - // We use three if statements instead of something like match guards so that all - // of these errors can be emitted if all cases apply. - if default.is_some() { - gate_feature_post!(&self, associated_type_defaults, ti.span, - "associated type defaults are unstable"); - } - if !ti.generics.params.is_empty() { - gate_feature_post!(&self, generic_associated_types, ti.span, - "generic associated types are unstable"); - } - if !ti.generics.where_clause.predicates.is_empty() { - gate_feature_post!(&self, generic_associated_types, ti.span, - "where clauses on associated types are unstable"); - } - } - _ => {} - } - visit::walk_trait_item(self, ti) - } - - fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) { - if ii.defaultness == ast::Defaultness::Default { - gate_feature_post!(&self, specialization, - ii.span, - "specialization is unstable"); - } - - match ii.node { - ast::ImplItemKind::Method(..) => {} - ast::ImplItemKind::OpaqueTy(..) => { - gate_feature_post!( - &self, - type_alias_impl_trait, - ii.span, - "`impl Trait` in type aliases is unstable" - ); - } - ast::ImplItemKind::TyAlias(_) => { - if !ii.generics.params.is_empty() { - gate_feature_post!(&self, generic_associated_types, ii.span, - "generic associated types are unstable"); - } - if !ii.generics.where_clause.predicates.is_empty() { - gate_feature_post!(&self, generic_associated_types, ii.span, - "where clauses on associated types are unstable"); - } - } - _ => {} - } - visit::walk_impl_item(self, ii) - } - - fn visit_vis(&mut self, vis: &'a ast::Visibility) { - if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node { - gate_feature_post!(&self, crate_visibility_modifier, vis.span, - "`crate` visibility modifier is experimental"); - } - visit::walk_vis(self, vis) - } -} - -pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], - crate_edition: Edition, allow_features: &Option>) -> Features { - fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) { - let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed"); - if let Some(reason) = reason { - err.span_note(span, reason); - } else { - err.span_label(span, "feature has been removed"); - } - err.emit(); - } - - let mut features = Features::new(); - let mut edition_enabled_features = FxHashMap::default(); - - for &edition in ALL_EDITIONS { - if edition <= crate_edition { - // The `crate_edition` implies its respective umbrella feature-gate - // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX). - edition_enabled_features.insert(edition.feature_name(), edition); - } - } - - for &(name, .., f_edition, set) in ACTIVE_FEATURES { - if let Some(f_edition) = f_edition { - if f_edition <= crate_edition { - set(&mut features, DUMMY_SP); - edition_enabled_features.insert(name, crate_edition); - } - } - } - - // Process the edition umbrella feature-gates first, to ensure - // `edition_enabled_features` is completed before it's queried. - for attr in krate_attrs { - if !attr.check_name(sym::feature) { - continue - } - - let list = match attr.meta_item_list() { - Some(list) => list, - None => continue, - }; - - for mi in list { - if !mi.is_word() { - continue; - } - - let name = mi.name_or_empty(); - - if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) { - if *edition <= crate_edition { - continue; - } - - for &(name, .., f_edition, set) in ACTIVE_FEATURES { - if let Some(f_edition) = f_edition { - if f_edition <= *edition { - // FIXME(Manishearth) there is currently no way to set - // lib features by edition - set(&mut features, DUMMY_SP); - edition_enabled_features.insert(name, *edition); - } - } - } - } - } - } - - for attr in krate_attrs { - if !attr.check_name(sym::feature) { - continue - } - - let list = match attr.meta_item_list() { - Some(list) => list, - None => continue, - }; - - let bad_input = |span| { - struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input") - }; - - for mi in list { - let name = match mi.ident() { - Some(ident) if mi.is_word() => ident.name, - Some(ident) => { - bad_input(mi.span()).span_suggestion( - mi.span(), - "expected just one word", - format!("{}", ident.name), - Applicability::MaybeIncorrect, - ).emit(); - continue - } - None => { - bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit(); - continue - } - }; - - if let Some(edition) = edition_enabled_features.get(&name) { - struct_span_warn!( - span_handler, - mi.span(), - E0705, - "the feature `{}` is included in the Rust {} edition", - name, - edition, - ).emit(); - continue; - } - - if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) { - // Handled in the separate loop above. - continue; - } - - 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 let Some((_, since, ..)) = ACCEPTED_FEATURES.iter().find(|f| name == f.0) { - let since = Some(Symbol::intern(since)); - features.declared_lang_features.push((name, mi.span(), since)); - continue; - } - - if let Some(allowed) = allow_features.as_ref() { - if allowed.iter().find(|f| *f == name.as_str()).is_none() { - span_err!(span_handler, mi.span(), E0725, - "the feature `{}` is not in the list of allowed features", - name); - continue; - } - } - - if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) { - set(&mut features, mi.span()); - features.declared_lang_features.push((name, mi.span(), None)); - continue; - } - - features.declared_lib_features.push((name, mi.span())); - } - } - - features -} - -fn for_each_in_lock(vec: &Lock>, f: impl Fn(&T)) { - vec.borrow().iter().for_each(f); -} - -pub fn check_crate(krate: &ast::Crate, - sess: &ParseSess, - features: &Features, - plugin_attributes: &[(Symbol, AttributeType)], - unstable: UnstableFeatures) { - maybe_stage_features(&sess.span_diagnostic, krate, unstable); - let ctx = Context { - features, - parse_sess: sess, - plugin_attributes, - }; - - for_each_in_lock(&sess.param_attr_spans, |span| gate_feature!( - &ctx, - param_attrs, - *span, - "attributes on function parameters are unstable" - )); - - for_each_in_lock(&sess.let_chains_spans, |span| gate_feature!( - &ctx, - let_chains, - *span, - "`let` expressions in this position are experimental" - )); - - for_each_in_lock(&sess.async_closure_spans, |span| gate_feature!( - &ctx, - async_closure, - *span, - "async closures are unstable" - )); - - let visitor = &mut PostExpansionVisitor { - context: &ctx, - builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP, - }; - visit::walk_crate(visitor, krate); -} - -#[derive(Clone, Copy, Hash)] -pub enum UnstableFeatures { - /// Hard errors for unstable features are active, as on beta/stable channels. - Disallow, - /// Allow features to be activated, as on nightly. - Allow, - /// Errors are bypassed for bootstrapping. This is required any time - /// during the build that feature-related lints are set to warn or above - /// because the build turns on warnings-as-errors and uses lots of unstable - /// features. As a result, this is always required for building Rust itself. - Cheat -} - -impl UnstableFeatures { - pub fn from_environment() -> UnstableFeatures { - // Whether this is a feature-staged build, i.e., on the beta or stable channel - let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); - // Whether we should enable unstable features for bootstrapping - let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok(); - match (disable_unstable_features, bootstrap) { - (_, true) => UnstableFeatures::Cheat, - (true, _) => UnstableFeatures::Disallow, - (false, _) => UnstableFeatures::Allow - } - } - - pub fn is_nightly_build(&self) -> bool { - match *self { - UnstableFeatures::Allow | UnstableFeatures::Cheat => true, - _ => false, - } - } -} - -fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, - unstable: UnstableFeatures) { - let allow_features = match unstable { - UnstableFeatures::Allow => true, - UnstableFeatures::Disallow => false, - UnstableFeatures::Cheat => true - }; - if !allow_features { - for attr in &krate.attrs { - if attr.check_name(sym::feature) { - let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"); - span_err!(span_handler, attr.span, E0554, - "`#![feature]` may not be used on the {} release channel", - release_channel); - } - } - } -} diff --git a/src/libsyntax/feature_gate/accepted.rs b/src/libsyntax/feature_gate/accepted.rs new file mode 100644 index 0000000000000..cda1ef1436ca1 --- /dev/null +++ b/src/libsyntax/feature_gate/accepted.rs @@ -0,0 +1,254 @@ +//! List of the accepted feature gates. + +use crate::symbol::sym; +use super::{State, Feature}; + +macro_rules! declare_features { + ($( + $(#[doc = $doc:tt])* (accepted, $feature:ident, $ver:expr, $issue:expr, None), + )+) => { + /// Those language feature has since been Accepted (it was once Active) + pub const ACCEPTED_FEATURES: &[Feature] = &[ + $( + Feature { + state: State::Accepted, + name: sym::$feature, + since: $ver, + issue: $issue, + edition: None, + description: concat!($($doc,)*), + } + ),+ + ]; + } +} + +declare_features! ( + // ------------------------------------------------------------------------- + // feature-group-start: for testing purposes + // ------------------------------------------------------------------------- + + /// A temporary feature gate used to enable parser extensions needed + /// to bootstrap fix for #5723. + (accepted, issue_5723_bootstrap, "1.0.0", None, None), + /// These are used to test this portion of the compiler, + /// they don't actually mean anything. + (accepted, test_accepted_feature, "1.0.0", None, None), + + // ------------------------------------------------------------------------- + // feature-group-end: for testing purposes + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + // feature-group-start: accepted features + // ------------------------------------------------------------------------- + + /// Allows using associated `type`s in `trait`s. + (accepted, associated_types, "1.0.0", None, None), + /// Allows using assigning a default type to type parameters in algebraic data type definitions. + (accepted, default_type_params, "1.0.0", None, None), + // FIXME: explain `globs`. + (accepted, globs, "1.0.0", None, None), + /// Allows `macro_rules!` items. + (accepted, macro_rules, "1.0.0", None, None), + /// Allows use of `&foo[a..b]` as a slicing syntax. + (accepted, slicing_syntax, "1.0.0", None, None), + /// Allows struct variants `Foo { baz: u8, .. }` in enums (RFC 418). + (accepted, struct_variant, "1.0.0", None, None), + /// Allows indexing tuples. + (accepted, tuple_indexing, "1.0.0", None, None), + /// Allows the use of `if let` expressions. + (accepted, if_let, "1.0.0", None, None), + /// Allows the use of `while let` expressions. + (accepted, while_let, "1.0.0", None, None), + /// Allows using `#![no_std]`. + (accepted, no_std, "1.6.0", None, None), + /// Allows overloading augmented assignment operations like `a += b`. + (accepted, augmented_assignments, "1.8.0", Some(28235), None), + /// Allows empty structs and enum variants with braces. + (accepted, braced_empty_structs, "1.8.0", Some(29720), None), + /// Allows `#[deprecated]` attribute. + (accepted, deprecated, "1.9.0", Some(29935), None), + /// Allows macros to appear in the type position. + (accepted, type_macros, "1.13.0", Some(27245), None), + /// Allows use of the postfix `?` operator in expressions. + (accepted, question_mark, "1.13.0", Some(31436), None), + /// Allows `..` in tuple (struct) patterns. + (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627), None), + /// Allows some increased flexibility in the name resolution rules, + /// especially around globs and shadowing (RFC 1560). + (accepted, item_like_imports, "1.15.0", Some(35120), None), + /// Allows using `Self` and associated types in struct expressions and patterns. + (accepted, more_struct_aliases, "1.16.0", Some(37544), None), + /// Allows elision of `'static` lifetimes in `static`s and `const`s. + (accepted, static_in_const, "1.17.0", Some(35897), None), + /// Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. + (accepted, field_init_shorthand, "1.17.0", Some(37340), None), + /// Allows the definition recursive static items. + (accepted, static_recursion, "1.17.0", Some(29719), None), + /// Allows `pub(restricted)` visibilities (RFC 1422). + (accepted, pub_restricted, "1.18.0", Some(32409), None), + /// Allows `#![windows_subsystem]`. + (accepted, windows_subsystem, "1.18.0", Some(37499), None), + /// Allows `break {expr}` with a value inside `loop`s. + (accepted, loop_break_value, "1.19.0", Some(37339), None), + /// Allows numeric fields in struct expressions and patterns. + (accepted, relaxed_adts, "1.19.0", Some(35626), None), + /// Allows coercing non capturing closures to function pointers. + (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None), + /// Allows attributes on struct literal fields. + (accepted, struct_field_attributes, "1.20.0", Some(38814), None), + /// Allows the definition of associated constants in `trait` or `impl` blocks. + (accepted, associated_consts, "1.20.0", Some(29646), None), + /// Allows usage of the `compile_error!` macro. + (accepted, compile_error, "1.20.0", Some(40872), None), + /// Allows code like `let x: &'static u32 = &42` to work (RFC 1414). + (accepted, rvalue_static_promotion, "1.21.0", Some(38865), None), + /// Allows `Drop` types in constants (RFC 1440). + (accepted, drop_types_in_const, "1.22.0", Some(33156), None), + /// Allows the sysV64 ABI to be specified on all platforms + /// instead of just the platforms on which it is the C ABI. + (accepted, abi_sysv64, "1.24.0", Some(36167), None), + /// Allows `repr(align(16))` struct attribute (RFC 1358). + (accepted, repr_align, "1.25.0", Some(33626), None), + /// Allows '|' at beginning of match arms (RFC 1925). + (accepted, match_beginning_vert, "1.25.0", Some(44101), None), + /// Allows nested groups in `use` items (RFC 2128). + (accepted, use_nested_groups, "1.25.0", Some(44494), None), + /// Allows indexing into constant arrays. + (accepted, const_indexing, "1.26.0", Some(29947), None), + /// Allows using `a..=b` and `..=b` as inclusive range syntaxes. + (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), + /// Allows `..=` in patterns (RFC 1192). + (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None), + /// Allows `fn main()` with return types which implements `Termination` (RFC 1937). + (accepted, termination_trait, "1.26.0", Some(43301), None), + /// Allows implementing `Clone` for closures where possible (RFC 2132). + (accepted, clone_closures, "1.26.0", Some(44490), None), + /// Allows implementing `Copy` for closures where possible (RFC 2132). + (accepted, copy_closures, "1.26.0", Some(44490), None), + /// Allows `impl Trait` in function arguments. + (accepted, universal_impl_trait, "1.26.0", Some(34511), None), + /// Allows `impl Trait` in function return types. + (accepted, conservative_impl_trait, "1.26.0", Some(34511), None), + /// Allows using the `u128` and `i128` types. + (accepted, i128_type, "1.26.0", Some(35118), None), + /// Allows default match binding modes (RFC 2005). + (accepted, match_default_bindings, "1.26.0", Some(42640), None), + /// Allows `'_` placeholder lifetimes. + (accepted, underscore_lifetimes, "1.26.0", Some(44524), None), + /// Allows attributes on lifetime/type formal parameters in generics (RFC 1327). + (accepted, generic_param_attrs, "1.27.0", Some(48848), None), + /// Allows `cfg(target_feature = "...")`. + (accepted, cfg_target_feature, "1.27.0", Some(29717), None), + /// Allows `#[target_feature(...)]`. + (accepted, target_feature, "1.27.0", None, None), + /// Allows using `dyn Trait` as a syntax for trait objects. + (accepted, dyn_trait, "1.27.0", Some(44662), None), + /// Allows `#[must_use]` on functions, and introduces 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), + /// Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). + (accepted, termination_trait_test, "1.27.0", Some(48854), None), + /// Allows the `#[global_allocator]` attribute. + (accepted, global_allocator, "1.28.0", Some(27389), None), + /// Allows `#[repr(transparent)]` attribute on newtype structs. + (accepted, repr_transparent, "1.28.0", Some(43036), None), + /// Allows procedural macros in `proc-macro` crates. + (accepted, proc_macro, "1.29.0", Some(38356), None), + /// Allows `foo.rs` as an alternative to `foo/mod.rs`. + (accepted, non_modrs_mods, "1.30.0", Some(44660), None), + /// Allows use of the `:vis` macro fragment specifier + (accepted, macro_vis_matcher, "1.30.0", Some(41022), None), + /// Allows importing and reexporting macros with `use`, + /// enables macro modularization in general. + (accepted, use_extern_macros, "1.30.0", Some(35896), None), + /// Allows keywords to be escaped for use as identifiers. + (accepted, raw_identifiers, "1.30.0", Some(48589), None), + /// Allows attributes scoped to tools. + (accepted, tool_attributes, "1.30.0", Some(44690), None), + /// Allows multi-segment paths in attributes and derives. + (accepted, proc_macro_path_invoc, "1.30.0", Some(38356), None), + /// Allows all literals in attribute lists and values of key-value pairs. + (accepted, attr_literals, "1.30.0", Some(34981), None), + /// Allows inferring outlives requirements (RFC 2093). + (accepted, infer_outlives_requirements, "1.30.0", Some(44493), None), + /// Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`. + /// This defines the behavior of panics. + (accepted, panic_handler, "1.30.0", Some(44489), None), + /// Allows `#[used]` to preserve symbols (see llvm.used). + (accepted, used, "1.30.0", Some(40289), None), + /// Allows `crate` in paths. + (accepted, crate_in_paths, "1.30.0", Some(45477), None), + /// Allows resolving absolute paths as paths from other crates. + (accepted, extern_absolute_paths, "1.30.0", Some(44660), None), + /// Allows access to crate names passed via `--extern` through prelude. + (accepted, extern_prelude, "1.30.0", Some(44660), None), + /// Allows parentheses in patterns. + (accepted, pattern_parentheses, "1.31.0", Some(51087), None), + /// Allows the definition of `const fn` functions. + (accepted, min_const_fn, "1.31.0", Some(53555), None), + /// Allows scoped lints. + (accepted, tool_lints, "1.31.0", Some(44690), None), + /// Allows lifetime elision in `impl` headers. For example: + /// + `impl Iterator for &mut Iterator` + /// + `impl Debug for Foo<'_>` + (accepted, impl_header_lifetime_elision, "1.31.0", Some(15872), None), + /// Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. + (accepted, extern_crate_item_prelude, "1.31.0", Some(55599), None), + /// Allows use of the `:literal` macro fragment specifier (RFC 1576). + (accepted, macro_literal_matcher, "1.32.0", Some(35625), None), + /// Allows use of `?` as the Kleene "at most one" operator in macros. + (accepted, macro_at_most_once_rep, "1.32.0", Some(48075), None), + /// Allows `Self` struct constructor (RFC 2302). + (accepted, self_struct_ctor, "1.32.0", Some(51994), None), + /// Allows `Self` in type definitions (RFC 2300). + (accepted, self_in_typedefs, "1.32.0", Some(49303), None), + /// Allows `use x::y;` to search `x` in the current scope. + (accepted, uniform_paths, "1.32.0", Some(53130), None), + /// Allows integer match exhaustiveness checking (RFC 2591). + (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907), None), + /// Allows `use path as _;` and `extern crate c as _;`. + (accepted, underscore_imports, "1.33.0", Some(48216), None), + /// Allows `#[repr(packed(N))]` attribute on structs. + (accepted, repr_packed, "1.33.0", Some(33158), None), + /// Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086). + (accepted, irrefutable_let_patterns, "1.33.0", Some(44495), None), + /// Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions. + (accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None), + /// Allows let bindings, assignments and destructuring in `const` functions and constants. + /// As long as control flow is not implemented in const eval, `&&` and `||` may not be used + /// at the same time as let bindings. + (accepted, const_let, "1.33.0", Some(48821), None), + /// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. + (accepted, cfg_attr_multi, "1.33.0", Some(54881), None), + /// Allows top level or-patterns (`p | q`) in `if let` and `while let`. + (accepted, if_while_or_patterns, "1.33.0", Some(48215), None), + /// Allows `cfg(target_vendor = "...")`. + (accepted, cfg_target_vendor, "1.33.0", Some(29718), None), + /// Allows `extern crate self as foo;`. + /// This puts local crate root into extern prelude under name `foo`. + (accepted, extern_crate_self, "1.34.0", Some(56409), None), + /// Allows arbitrary delimited token streams in non-macro attributes. + (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208), None), + /// Allows paths to enum variants on type aliases including `Self`. + (accepted, type_alias_enum_variants, "1.37.0", Some(49683), None), + /// Allows using `#[repr(align(X))]` on enums with equivalent semantics + /// to wrapping an enum in a wrapper struct with `#[repr(align(X))]`. + (accepted, repr_align_enum, "1.37.0", Some(57996), None), + /// Allows `const _: TYPE = VALUE`. + (accepted, underscore_const_names, "1.37.0", Some(54912), None), + /// Allows free and inherent `async fn`s, `async` blocks, and `.await` expressions. + (accepted, async_await, "1.39.0", Some(50547), None), + /// Allows mixing bind-by-move in patterns and references to those identifiers in guards. + (accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287), None), + /// Allows attributes in formal function parameters. + (accepted, param_attrs, "1.39.0", Some(60406), None), + // Allows macro invocations in `extern {}` blocks. + (accepted, macros_in_extern, "1.40.0", Some(49476), None), + + // ------------------------------------------------------------------------- + // feature-group-end: accepted features + // ------------------------------------------------------------------------- +); diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs new file mode 100644 index 0000000000000..94f0995566f52 --- /dev/null +++ b/src/libsyntax/feature_gate/active.rs @@ -0,0 +1,547 @@ +//! List of the active feature gates. + +use super::{State, Feature}; + +use crate::edition::Edition; +use crate::symbol::{Symbol, sym}; + +use syntax_pos::Span; + +macro_rules! set { + ($field: ident) => {{ + fn f(features: &mut Features, _: Span) { + features.$field = true; + } + f as fn(&mut Features, Span) + }} +} + +macro_rules! declare_features { + ($( + $(#[doc = $doc:tt])* (active, $feature:ident, $ver:expr, $issue:expr, $edition:expr), + )+) => { + /// Represents active features that are currently being implemented or + /// currently being considered for addition/removal. + pub const ACTIVE_FEATURES: + &[Feature] = + &[$( + // (sym::$feature, $ver, $issue, $edition, set!($feature)) + Feature { + state: State::Active { set: set!($feature) }, + name: sym::$feature, + since: $ver, + issue: $issue, + edition: $edition, + description: concat!($($doc,)*), + } + ),+]; + + /// A set of features to be used by later passes. + #[derive(Clone)] + pub struct Features { + /// `#![feature]` attrs for language features, for error reporting. + pub declared_lang_features: Vec<(Symbol, Span, Option)>, + /// `#![feature]` attrs for non-language (library) features. + pub declared_lib_features: Vec<(Symbol, Span)>, + $( + $(#[doc = $doc])* + pub $feature: bool + ),+ + } + + impl Features { + pub fn new() -> Features { + Features { + declared_lang_features: Vec::new(), + declared_lib_features: Vec::new(), + $($feature: false),+ + } + } + + pub fn walk_feature_fields(&self, mut f: F) + where F: FnMut(&str, bool) + { + $(f(stringify!($feature), self.$feature);)+ + } + } + }; +} + +impl Feature { + /// Sets this feature in `Features`. Panics if called on a non-active feature. + pub fn set(&self, features: &mut Features, span: Span) { + match self.state { + State::Active { set } => set(features, span), + _ => panic!("called `set` on feature `{}` which is not `active`", self.name) + } + } +} + +// If you change this, please modify `src/doc/unstable-book` as well. +// +// Don't ever remove anything from this list; move them to `removed.rs`. +// +// The version numbers here correspond to the version in which the current status +// was set. This is most important for knowing when a particular feature became +// stable (active). +// +// Note that the features are grouped into internal/user-facing and then +// sorted by version inside those groups. This is enforced with tidy. +// +// N.B., `tools/tidy/src/features.rs` parses this information directly out of the +// source, so take care when modifying it. + +declare_features! ( + // ------------------------------------------------------------------------- + // feature-group-start: internal feature gates + // ------------------------------------------------------------------------- + + // no-tracking-issue-start + + /// Allows using compiler's own crates. + (active, rustc_private, "1.0.0", Some(27812), None), + + /// Allows using the `rust-intrinsic`'s "ABI". + (active, intrinsics, "1.0.0", None, None), + + /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. + (active, lang_items, "1.0.0", None, None), + + /// Allows using the `#[stable]` and `#[unstable]` attributes. + (active, staged_api, "1.0.0", None, None), + + /// Allows using `#[allow_internal_unstable]`. This is an + /// attribute on `macro_rules!` and can't use the attribute handling + /// below (it has to be checked before expansion possibly makes + /// macros disappear). + (active, allow_internal_unstable, "1.0.0", None, None), + + /// Allows using `#[allow_internal_unsafe]`. This is an + /// attribute on `macro_rules!` and can't use the attribute handling + /// below (it has to be checked before expansion possibly makes + /// macros disappear). + (active, allow_internal_unsafe, "1.0.0", None, None), + + /// Allows using `#[rustc_const_unstable(feature = "foo", ..)]` which + /// lets a function to be `const` when opted into with `#![feature(foo)]`. + (active, rustc_const_unstable, "1.0.0", None, None), + + /// no-tracking-issue-end + + /// Allows using `#[link_name="llvm.*"]`. + (active, link_llvm_intrinsics, "1.0.0", Some(29602), None), + + /// Allows using `rustc_*` attributes (RFC 572). + (active, rustc_attrs, "1.0.0", Some(29642), None), + + /// Allows using `#[on_unimplemented(..)]` on traits. + (active, on_unimplemented, "1.0.0", Some(29628), None), + + /// Allows using the `box $expr` syntax. + (active, box_syntax, "1.0.0", Some(49733), None), + + /// Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls. + (active, main, "1.0.0", Some(29634), None), + + /// Allows using `#[start]` on a function indicating that it is the program entrypoint. + (active, start, "1.0.0", Some(29633), None), + + /// Allows using the `#[fundamental]` attribute. + (active, fundamental, "1.0.0", Some(29635), None), + + /// Allows using the `rust-call` ABI. + (active, unboxed_closures, "1.0.0", Some(29625), None), + + /// Allows using the `#[linkage = ".."]` attribute. + (active, linkage, "1.0.0", Some(29603), None), + + /// Allows features specific to OIBIT (auto traits). + (active, optin_builtin_traits, "1.0.0", Some(13231), None), + + /// Allows using `box` in patterns (RFC 469). + (active, box_patterns, "1.0.0", Some(29641), None), + + // no-tracking-issue-start + + /// Allows using `#[prelude_import]` on glob `use` items. + (active, prelude_import, "1.2.0", None, None), + + // no-tracking-issue-end + + // no-tracking-issue-start + + /// Allows using `#[omit_gdb_pretty_printer_section]`. + (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), + + /// Allows using the `vectorcall` ABI. + (active, abi_vectorcall, "1.7.0", None, None), + + // no-tracking-issue-end + + /// Allows using `#[structural_match]` which indicates that a type is structurally matchable. + (active, structural_match, "1.8.0", Some(31434), None), + + /// Allows using the `may_dangle` attribute (RFC 1327). + (active, dropck_eyepatch, "1.10.0", Some(34761), None), + + /// Allows using the `#![panic_runtime]` attribute. + (active, panic_runtime, "1.10.0", Some(32837), None), + + /// Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. + (active, needs_panic_runtime, "1.10.0", Some(32837), None), + + // no-tracking-issue-start + + /// Allows identifying the `compiler_builtins` crate. + (active, compiler_builtins, "1.13.0", None, None), + + /// Allows using the `unadjusted` ABI; perma-unstable. + (active, abi_unadjusted, "1.16.0", None, None), + + /// Allows identifying crates that contain sanitizer runtimes. + (active, sanitizer_runtime, "1.17.0", None, None), + + /// Used to identify crates that contain the profiler runtime. + (active, profiler_runtime, "1.18.0", None, None), + + /// Allows using the `thiscall` ABI. + (active, abi_thiscall, "1.19.0", None, None), + + /// Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`. + (active, allocator_internals, "1.20.0", None, None), + + // no-tracking-issue-end + + /// Added for testing E0705; perma-unstable. + (active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)), + + // ------------------------------------------------------------------------- + // feature-group-end: internal feature gates + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + // feature-group-start: actual feature gates (target features) + // ------------------------------------------------------------------------- + + // FIXME: Document these and merge with the list below. + + // Unstable `#[target_feature]` directives. + (active, arm_target_feature, "1.27.0", Some(44839), None), + (active, aarch64_target_feature, "1.27.0", Some(44839), None), + (active, hexagon_target_feature, "1.27.0", Some(44839), None), + (active, powerpc_target_feature, "1.27.0", Some(44839), None), + (active, mips_target_feature, "1.27.0", Some(44839), None), + (active, avx512_target_feature, "1.27.0", Some(44839), None), + (active, mmx_target_feature, "1.27.0", Some(44839), None), + (active, sse4a_target_feature, "1.27.0", Some(44839), None), + (active, tbm_target_feature, "1.27.0", Some(44839), None), + (active, wasm_target_feature, "1.30.0", Some(44839), None), + (active, adx_target_feature, "1.32.0", Some(44839), None), + (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None), + (active, movbe_target_feature, "1.34.0", Some(44839), None), + (active, rtm_target_feature, "1.35.0", Some(44839), None), + (active, f16c_target_feature, "1.36.0", Some(44839), None), + + // ------------------------------------------------------------------------- + // feature-group-end: actual feature gates (target features) + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + // feature-group-start: actual feature gates + // ------------------------------------------------------------------------- + + /// Allows using the `#[link_args]` attribute. + (active, link_args, "1.0.0", Some(29596), None), + + /// Allows defining identifiers beyond ASCII. + (active, non_ascii_idents, "1.0.0", Some(55467), None), + + /// Allows using `#[plugin_registrar]` on functions. + (active, plugin_registrar, "1.0.0", Some(29597), None), + + /// Allows using `#![plugin(myplugin)]`. + (active, plugin, "1.0.0", Some(29597), None), + + /// Allows using `#[thread_local]` on `static` items. + (active, thread_local, "1.0.0", Some(29594), None), + + /// Allows the use of SIMD types in functions declared in `extern` blocks. + (active, simd_ffi, "1.0.0", Some(27731), None), + + /// Allows using custom attributes (RFC 572). + (active, custom_attribute, "1.0.0", Some(29642), None), + + /// Allows using non lexical lifetimes (RFC 2094). + (active, nll, "1.0.0", Some(43234), None), + + /// Allows using slice patterns. + (active, slice_patterns, "1.0.0", Some(62254), None), + + /// Allows the definition of `const` functions with some advanced features. + (active, const_fn, "1.2.0", Some(57563), None), + + /// Allows associated type defaults. + (active, associated_type_defaults, "1.2.0", Some(29661), None), + + /// Allows `#![no_core]`. + (active, no_core, "1.3.0", Some(29639), None), + + /// Allows default type parameters to influence type inference. + (active, default_type_parameter_fallback, "1.3.0", Some(27336), None), + + /// Allows `repr(simd)` and importing the various simd intrinsics. + (active, repr_simd, "1.4.0", Some(27731), None), + + /// Allows `extern "platform-intrinsic" { ... }`. + (active, platform_intrinsics, "1.4.0", Some(27731), None), + + /// Allows `#[unwind(..)]`. + /// + /// Permits specifying whether a function should permit unwinding or abort on unwind. + (active, unwind_attributes, "1.4.0", Some(58760), None), + + /// Allows `#[no_debug]`. + (active, no_debug, "1.5.0", Some(29721), None), + + /// Allows attributes on expressions and non-item statements. + (active, stmt_expr_attributes, "1.6.0", Some(15701), None), + + /// Allows the use of type ascription in expressions. + (active, type_ascription, "1.6.0", Some(23416), None), + + /// Allows `cfg(target_thread_local)`. + (active, cfg_target_thread_local, "1.7.0", Some(29594), None), + + /// Allows specialization of implementations (RFC 1210). + (active, specialization, "1.7.0", Some(31844), None), + + /// Allows using `#[naked]` on functions. + (active, naked_functions, "1.9.0", Some(32408), None), + + /// Allows `cfg(target_has_atomic = "...")`. + (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), + + /// Allows `X..Y` patterns. + (active, exclusive_range_pattern, "1.11.0", Some(37854), None), + + /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. + (active, never_type, "1.13.0", Some(35121), None), + + /// Allows exhaustive pattern matching on types that contain uninhabited types. + (active, exhaustive_patterns, "1.13.0", Some(51085), None), + + /// Allows untagged unions `union U { ... }`. + (active, untagged_unions, "1.13.0", Some(32836), None), + + /// Allows `#[link(..., cfg(..))]`. + (active, link_cfg, "1.14.0", Some(37406), None), + + /// Allows `extern "ptx-*" fn()`. + (active, abi_ptx, "1.15.0", Some(38788), None), + + /// Allows the `#[repr(i128)]` attribute for enums. + (active, repr128, "1.16.0", Some(35118), None), + + /// Allows `#[link(kind="static-nobundle"...)]`. + (active, static_nobundle, "1.16.0", Some(37403), None), + + /// Allows `extern "msp430-interrupt" fn()`. + (active, abi_msp430_interrupt, "1.16.0", Some(38487), None), + + /// Allows declarative macros 2.0 (`macro`). + (active, decl_macro, "1.17.0", Some(39412), None), + + /// Allows `extern "x86-interrupt" fn()`. + (active, abi_x86_interrupt, "1.17.0", Some(40180), None), + + /// Allows overlapping impls of marker traits. + (active, overlapping_marker_traits, "1.18.0", Some(29864), None), + + /// Allows a test to fail without failing the whole suite. + (active, allow_fail, "1.19.0", Some(46488), None), + + /// Allows unsized tuple coercion. + (active, unsized_tuple_coercion, "1.20.0", Some(42877), None), + + /// Allows defining generators. + (active, generators, "1.21.0", Some(43122), None), + + /// Allows `#[doc(cfg(...))]`. + (active, doc_cfg, "1.21.0", Some(43781), None), + + /// Allows `#[doc(masked)]`. + (active, doc_masked, "1.21.0", Some(44027), None), + + /// Allows `#[doc(spotlight)]`. + (active, doc_spotlight, "1.22.0", Some(45040), None), + + /// Allows `#[doc(include = "some-file")]`. + (active, external_doc, "1.22.0", Some(44732), None), + + /// Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008). + (active, non_exhaustive, "1.22.0", Some(44109), None), + + /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. + (active, crate_visibility_modifier, "1.23.0", Some(53120), None), + + /// Allows defining `extern type`s. + (active, extern_types, "1.23.0", Some(43467), None), + + /// Allows trait methods with arbitrary self types. + (active, arbitrary_self_types, "1.23.0", Some(44874), None), + + /// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`). + (active, in_band_lifetimes, "1.23.0", Some(44524), None), + + /// Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). + (active, generic_associated_types, "1.23.0", Some(44265), None), + + /// Allows defining `trait X = A + B;` alias items. + (active, trait_alias, "1.24.0", Some(41517), None), + + /// Allows infering `'static` outlives requirements (RFC 2093). + (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None), + + /// Allows accessing fields of unions inside `const` functions. + (active, const_fn_union, "1.27.0", Some(51909), None), + + /// Allows casting raw pointers to `usize` during const eval. + (active, const_raw_ptr_to_usize_cast, "1.27.0", Some(51910), None), + + /// Allows dereferencing raw pointers during const eval. + (active, const_raw_ptr_deref, "1.27.0", Some(51911), None), + + /// Allows comparing raw pointers during const eval. + (active, const_compare_raw_pointers, "1.27.0", Some(53020), None), + + /// Allows `#[doc(alias = "...")]`. + (active, doc_alias, "1.27.0", Some(50146), None), + + /// Allows inconsistent bounds in where clauses. + (active, trivial_bounds, "1.28.0", Some(48214), None), + + /// Allows `'a: { break 'a; }`. + (active, label_break_value, "1.28.0", Some(48594), None), + + /// Allows using `#[doc(keyword = "...")]`. + (active, doc_keyword, "1.28.0", Some(51315), None), + + /// Allows reinterpretation of the bits of a value of one type as another + /// type during const eval. + (active, const_transmute, "1.29.0", Some(53605), None), + + /// Allows using `try {...}` expressions. + (active, try_blocks, "1.29.0", Some(31436), None), + + /// Allows defining an `#[alloc_error_handler]`. + (active, alloc_error_handler, "1.29.0", Some(51540), None), + + /// Allows using the `amdgpu-kernel` ABI. + (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None), + + /// Allows panicking during const eval (producing compile-time errors). + (active, const_panic, "1.30.0", Some(51999), None), + + /// Allows `#[marker]` on certain traits allowing overlapping implementations. + (active, marker_trait_attr, "1.30.0", Some(29864), None), + + /// Allows macro invocations on modules expressions and statements and + /// procedural macros to expand to non-items. + (active, proc_macro_hygiene, "1.30.0", Some(54727), None), + + /// Allows unsized rvalues at arguments and parameters. + (active, unsized_locals, "1.30.0", Some(48055), None), + + /// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. + (active, custom_test_frameworks, "1.30.0", Some(50297), None), + + /// Allows non-builtin attributes in inner attribute position. + (active, custom_inner_attributes, "1.30.0", Some(54726), None), + + /// Allows `impl Trait` in bindings (`let`, `const`, `static`). + (active, impl_trait_in_bindings, "1.30.0", Some(63065), None), + + /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. + (active, lint_reasons, "1.31.0", Some(54503), None), + + /// Allows exhaustive integer pattern matching on `usize` and `isize`. + (active, precise_pointer_size_matching, "1.32.0", Some(56354), None), + + /// Allows relaxing the coherence rules such that + /// `impl ForeignTrait for ForeignType` is permitted. + (active, re_rebalance_coherence, "1.32.0", Some(55437), None), + + /// Allows using `#[ffi_returns_twice]` on foreign functions. + (active, ffi_returns_twice, "1.34.0", Some(58314), None), + + /// Allows const generic types (e.g. `struct Foo(...);`). + (active, const_generics, "1.34.0", Some(44580), None), + + /// Allows using `#[optimize(X)]`. + (active, optimize_attribute, "1.34.0", Some(54882), None), + + /// Allows using C-variadics. + (active, c_variadic, "1.34.0", Some(44930), None), + + /// Allows the user of associated type bounds. + (active, associated_type_bounds, "1.34.0", Some(52662), None), + + /// Allows calling constructor functions in `const fn`. + (active, const_constructor, "1.37.0", Some(61456), None), + + /// Allows `if/while p && let q = r && ...` chains. + (active, let_chains, "1.37.0", Some(53667), None), + + /// Allows #[repr(transparent)] on enums (RFC 2645). + (active, transparent_enums, "1.37.0", Some(60405), None), + + /// Allows #[repr(transparent)] on unions (RFC 2645). + (active, transparent_unions, "1.37.0", Some(60405), None), + + /// Allows explicit discriminants on non-unit enum variants. + (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None), + + /// Allows `impl Trait` with multiple unrelated lifetimes. + (active, member_constraints, "1.37.0", Some(61977), None), + + /// Allows `async || body` closures. + (active, async_closure, "1.37.0", Some(62290), None), + + /// Allows the use of `#[cfg(doctest)]`; set when rustdoc is collecting doctests. + (active, cfg_doctest, "1.37.0", Some(62210), None), + + /// Allows `[x; N]` where `x` is a constant (RFC 2203). + (active, const_in_array_repeat_expressions, "1.37.0", Some(49147), None), + + /// Allows `impl Trait` to be used inside type aliases (RFC 2515). + (active, type_alias_impl_trait, "1.38.0", Some(63063), None), + + /// Allows the use of or-patterns (e.g., `0 | 1`). + (active, or_patterns, "1.38.0", Some(54883), None), + + /// Allows the definition of `const extern fn` and `const unsafe extern fn`. + (active, const_extern_fn, "1.40.0", Some(64926), None), + + // Allows the use of raw-dylibs (RFC 2627). + (active, raw_dylib, "1.40.0", Some(58713), None), + + /// Enable accurate caller location reporting during panic (RFC 2091). + (active, track_caller, "1.40.0", Some(47809), None), + + // ------------------------------------------------------------------------- + // feature-group-end: actual feature gates + // ------------------------------------------------------------------------- +); + +/// Some features are known to be incomplete and using them is likely to have +/// unanticipated results, such as compiler crashes. We warn the user about these +/// to alert them. +pub const INCOMPLETE_FEATURES: &[Symbol] = &[ + sym::impl_trait_in_bindings, + sym::generic_associated_types, + sym::const_generics, + sym::or_patterns, + sym::let_chains, + sym::raw_dylib, + sym::track_caller, +]; diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/libsyntax/feature_gate/builtin_attrs.rs new file mode 100644 index 0000000000000..ae23cc5cb933c --- /dev/null +++ b/src/libsyntax/feature_gate/builtin_attrs.rs @@ -0,0 +1,595 @@ +//! Built-in attributes and `cfg` flag gating. + +use AttributeType::*; +use AttributeGate::*; + +use super::check::{emit_feature_err, GateIssue}; +use super::check::{Stability, EXPLAIN_ALLOW_INTERNAL_UNSAFE, EXPLAIN_ALLOW_INTERNAL_UNSTABLE}; +use super::active::Features; + +use crate::ast; +use crate::attr::AttributeTemplate; +use crate::symbol::{Symbol, sym}; +use crate::parse::ParseSess; + +use syntax_pos::Span; +use rustc_data_structures::fx::FxHashMap; +use lazy_static::lazy_static; + +type GateFn = fn(&Features) -> bool; + +macro_rules! cfg_fn { + ($field: ident) => { + (|features| { features.$field }) as GateFn + } +} + +/// `cfg(...)`'s that are feature gated. +const GATED_CFGS: &[(Symbol, Symbol, GateFn)] = &[ + // (name in cfg, feature, function to check if the feature is enabled) + (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), + (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), + (sym::rustdoc, sym::doc_cfg, cfg_fn!(doc_cfg)), + (sym::doctest, sym::cfg_doctest, cfg_fn!(cfg_doctest)), +]; + +#[derive(Debug)] +pub struct GatedCfg { + span: Span, + index: usize, +} + +impl GatedCfg { + pub fn gate(cfg: &ast::MetaItem) -> Option { + GATED_CFGS.iter() + .position(|info| cfg.check_name(info.0)) + .map(|idx| { + GatedCfg { + span: cfg.span, + index: idx + } + }) + } + + pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) { + let (cfg, feature, has_feature) = GATED_CFGS[self.index]; + if !has_feature(features) && !self.span.allows_unstable(feature) { + let explain = format!("`cfg({})` is experimental and subject to change", cfg); + emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain); + } + } +} + +// If you change this, please modify `src/doc/unstable-book` as well. You must +// move that documentation into the relevant place in the other docs, and +// remove the chapter on the flag. + +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum AttributeType { + /// Normal, builtin attribute that is consumed + /// by the compiler before the unused_attribute check + Normal, + + /// Builtin attribute that may not be consumed by the compiler + /// before the unused_attribute check. These attributes + /// will be ignored by the unused_attribute lint + Whitelisted, + + /// Builtin attribute that is only allowed at the crate level + CrateLevel, +} + +#[derive(Clone, Copy)] +pub enum AttributeGate { + /// Is gated by a given feature gate, reason + /// and function to check if enabled + Gated(Stability, Symbol, &'static str, fn(&Features) -> bool), + + /// Ungated attribute, can be used on all release channels + Ungated, +} + +// fn() is not Debug +impl std::fmt::Debug for AttributeGate { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + Self::Gated(ref stab, name, expl, _) => + write!(fmt, "Gated({:?}, {}, {})", stab, name, expl), + Self::Ungated => write!(fmt, "Ungated") + } + } +} + +impl AttributeGate { + fn is_deprecated(&self) -> bool { + match *self { + Self::Gated(Stability::Deprecated(_, _), ..) => true, + _ => false, + } + } +} + +/// A convenience macro for constructing attribute templates. +/// E.g., `template!(Word, List: "description")` means that the attribute +/// supports forms `#[attr]` and `#[attr(description)]`. +macro_rules! template { + (Word) => { template!(@ true, None, None) }; + (List: $descr: expr) => { template!(@ false, Some($descr), None) }; + (NameValueStr: $descr: expr) => { template!(@ false, None, Some($descr)) }; + (Word, List: $descr: expr) => { template!(@ true, Some($descr), None) }; + (Word, NameValueStr: $descr: expr) => { template!(@ true, None, Some($descr)) }; + (List: $descr1: expr, NameValueStr: $descr2: expr) => { + template!(@ false, Some($descr1), Some($descr2)) + }; + (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => { + template!(@ true, Some($descr1), Some($descr2)) + }; + (@ $word: expr, $list: expr, $name_value_str: expr) => { AttributeTemplate { + word: $word, list: $list, name_value_str: $name_value_str + } }; +} + +macro_rules! ungated { + ($attr:ident, $typ:expr, $tpl:expr $(,)?) => { + (sym::$attr, $typ, $tpl, Ungated) + }; +} + +macro_rules! gated { + ($attr:ident, $typ:expr, $tpl:expr, $gate:ident, $msg:expr $(,)?) => { + (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate))) + }; + ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => { + (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr))) + }; +} + +macro_rules! rustc_attr { + (TEST, $attr:ident, $typ:expr, $tpl:expr $(,)?) => { + rustc_attr!( + $attr, $typ, $tpl, + concat!("the `#[", stringify!($attr), "]` attribute is just used for rustc unit tests \ + and will never be stable", + ), + ) + }; + ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => { + (sym::$attr, $typ, $tpl, + Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs))) + }; +} + +macro_rules! experimental { + ($attr:ident) => { + concat!("the `#[", stringify!($attr), "]` attribute is an experimental feature") + } +} + +const IMPL_DETAIL: &str = "internal implementation detail"; +const INTERAL_UNSTABLE: &str = "this is an internal attribute that will never be stable"; + +pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate); + +/// Attributes that have a special meaning to rustc or rustdoc. +pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ + // ========================================================================== + // Stable attributes: + // ========================================================================== + + // Condtional compilation: + ungated!(cfg, Normal, template!(List: "predicate")), + ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ...")), + + // Testing: + ungated!(ignore, Normal, template!(Word, NameValueStr: "reason")), + ungated!( + should_panic, Normal, + template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), + ), + // FIXME(Centril): This can be used on stable but shouldn't. + ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")), + + // Macros: + ungated!(derive, Normal, template!(List: "Trait1, Trait2, ...")), + ungated!(automatically_derived, Normal, template!(Word)), + // FIXME(#14407) + ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")), + ungated!(macro_escape, Normal, template!(Word)), // Deprecated synonym for `macro_use`. + ungated!(macro_export, Normal, template!(Word, List: "local_inner_macros")), + ungated!(proc_macro, Normal, template!(Word)), + ungated!( + proc_macro_derive, Normal, + template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"), + ), + ungated!(proc_macro_attribute, Normal, template!(Word)), + + // Lints: + ungated!(warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), + ungated!(allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), + ungated!(forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), + ungated!(deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), + ungated!(must_use, Whitelisted, template!(Word, NameValueStr: "reason")), + // FIXME(#14407) + ungated!( + deprecated, Normal, + template!( + Word, + List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#, + NameValueStr: "reason" + ), + ), + + // Crate properties: + ungated!(crate_name, CrateLevel, template!(NameValueStr: "name")), + ungated!(crate_type, CrateLevel, template!(NameValueStr: "bin|lib|...")), + ungated!(crate_id, CrateLevel, template!(NameValueStr: "ignored")), + + // ABI, linking, symbols, and FFI + ungated!( + link, Whitelisted, + template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ cfg = "...""#), + ), + ungated!(link_name, Whitelisted, template!(NameValueStr: "name")), + ungated!(no_link, Normal, template!(Word)), + ungated!(repr, Normal, template!(List: "C, packed, ...")), + ungated!(export_name, Whitelisted, template!(NameValueStr: "name")), + ungated!(link_section, Whitelisted, template!(NameValueStr: "name")), + ungated!(no_mangle, Whitelisted, template!(Word)), + ungated!(used, Whitelisted, template!(Word)), + + // Limits: + ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N")), + ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N")), + + // Entry point: + ungated!(main, Normal, template!(Word)), + ungated!(start, Normal, template!(Word)), + ungated!(no_start, CrateLevel, template!(Word)), + ungated!(no_main, CrateLevel, template!(Word)), + + // Modules, prelude, and resolution: + ungated!(path, Normal, template!(NameValueStr: "file")), + ungated!(no_std, CrateLevel, template!(Word)), + ungated!(no_implicit_prelude, Normal, template!(Word)), + + // Runtime + ungated!(windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console")), + ungated!(panic_handler, Normal, template!(Word)), // RFC 2070 + + // Code generation: + ungated!(inline, Whitelisted, template!(Word, List: "always|never")), + ungated!(cold, Whitelisted, template!(Word)), + ungated!(no_builtins, Whitelisted, template!(Word)), + ungated!(target_feature, Whitelisted, template!(List: r#"enable = "name""#)), + + // FIXME: #14408 whitelist docs since rustdoc looks at them + ungated!(doc, Whitelisted, template!(List: "hidden|inline|...", NameValueStr: "string")), + + // ========================================================================== + // Unstable attributes: + // ========================================================================== + + // Linking: + gated!(naked, Whitelisted, template!(Word), naked_functions, experimental!(naked)), + gated!( + link_args, Normal, template!(NameValueStr: "args"), + "the `link_args` attribute is experimental and not portable across platforms, \ + it is recommended to use `#[link(name = \"foo\")] instead", + ), + gated!( + link_ordinal, Whitelisted, template!(List: "ordinal"), raw_dylib, + experimental!(link_ordinal) + ), + + // Plugins: + ( + sym::plugin_registrar, Normal, template!(Word), + Gated( + Stability::Deprecated("https://github.com/rust-lang/rust/issues/29597", None), + sym::plugin_registrar, + "compiler plugins are deprecated", + cfg_fn!(plugin_registrar) + ) + ), + ( + sym::plugin, CrateLevel, template!(List: "name|name(args)"), + Gated( + Stability::Deprecated("https://github.com/rust-lang/rust/issues/29597", None), + sym::plugin, + "compiler plugins are deprecated", + cfg_fn!(plugin) + ) + ), + + // Testing: + gated!(allow_fail, Normal, template!(Word), experimental!(allow_fail)), + gated!( + test_runner, CrateLevel, template!(List: "path"), custom_test_frameworks, + "custom test frameworks are an unstable feature", + ), + + // RFC #2008 + gated!(non_exhaustive, Whitelisted, template!(Word), experimental!(non_exhaustive)), + // RFC #1268 + gated!(marker, Normal, template!(Word), marker_trait_attr, experimental!(marker)), + gated!( + thread_local, Whitelisted, template!(Word), + "`#[thread_local]` is an experimental feature, and does not currently handle destructors", + ), + gated!(no_core, CrateLevel, template!(Word), experimental!(no_core)), + // RFC 2412 + gated!( + optimize, Whitelisted, template!(List: "size|speed"), optimize_attribute, + experimental!(optimize), + ), + + gated!(ffi_returns_twice, Whitelisted, template!(Word), experimental!(ffi_returns_twice)), + gated!(track_caller, Whitelisted, template!(Word), experimental!(track_caller)), + + // ========================================================================== + // Internal attributes: Stability, deprecation, and unsafe: + // ========================================================================== + + ungated!(feature, CrateLevel, template!(List: "name1, name1, ...")), + // FIXME(#14407) -- only looked at on-demand so we can't + // guarantee they'll have already been checked. + ungated!( + rustc_deprecated, Whitelisted, + template!(List: r#"since = "version", reason = "...""#) + ), + // FIXME(#14407) + ungated!(stable, Whitelisted, template!(List: r#"feature = "name", since = "version""#)), + // FIXME(#14407) + ungated!( + unstable, Whitelisted, + template!(List: r#"feature = "name", reason = "...", issue = "N""#), + ), + gated!( + rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), + "the `#[rustc_const_unstable]` attribute is an internal feature", + ), + gated!( + allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), + EXPLAIN_ALLOW_INTERNAL_UNSTABLE, + ), + gated!(allow_internal_unsafe, Normal, template!(Word), EXPLAIN_ALLOW_INTERNAL_UNSAFE), + + // ========================================================================== + // Internal attributes: Type system related: + // ========================================================================== + + gated!(fundamental, Whitelisted, template!(Word), experimental!(fundamental)), + gated!( + // RFC #1445. + structural_match, Whitelisted, template!(Word), + "the semantics of constant patterns is not yet settled", + ), + gated!( + may_dangle, Normal, template!(Word), dropck_eyepatch, + "`may_dangle` has unstable semantics and may be removed in the future", + ), + + // ========================================================================== + // Internal attributes: Runtime related: + // ========================================================================== + + rustc_attr!(rustc_allocator, Whitelisted, template!(Word), IMPL_DETAIL), + rustc_attr!(rustc_allocator_nounwind, Whitelisted, template!(Word), IMPL_DETAIL), + gated!(alloc_error_handler, Normal, template!(Word), experimental!(alloc_error_handler)), + gated!( + default_lib_allocator, Whitelisted, template!(Word), allocator_internals, + experimental!(default_lib_allocator), + ), + gated!( + needs_allocator, Normal, template!(Word), allocator_internals, + experimental!(needs_allocator), + ), + gated!(panic_runtime, Whitelisted, template!(Word), experimental!(panic_runtime)), + gated!(needs_panic_runtime, Whitelisted, template!(Word), experimental!(needs_panic_runtime)), + gated!( + unwind, Whitelisted, template!(List: "allowed|aborts"), unwind_attributes, + experimental!(unwind), + ), + gated!( + compiler_builtins, Whitelisted, template!(Word), + "the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \ + which contains compiler-rt intrinsics and will never be stable", + ), + gated!( + sanitizer_runtime, Whitelisted, template!(Word), + "the `#[sanitizer_runtime]` attribute is used to identify crates that contain the runtime \ + of a sanitizer and will never be stable", + ), + gated!( + profiler_runtime, Whitelisted, template!(Word), + "the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \ + which contains the profiler runtime and will never be stable", + ), + + // ========================================================================== + // Internal attributes, Linkage: + // ========================================================================== + + gated!( + linkage, Whitelisted, template!(NameValueStr: "external|internal|..."), + "the `linkage` attribute is experimental and not portable across platforms", + ), + rustc_attr!(rustc_std_internal_symbol, Whitelisted, template!(Word), INTERAL_UNSTABLE), + + // ========================================================================== + // Internal attributes, Macro related: + // ========================================================================== + + rustc_attr!(rustc_builtin_macro, Whitelisted, template!(Word), IMPL_DETAIL), + rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERAL_UNSTABLE), + rustc_attr!( + rustc_macro_transparency, Whitelisted, + template!(NameValueStr: "transparent|semitransparent|opaque"), + "used internally for testing macro hygiene", + ), + + // ========================================================================== + // Internal attributes, Diagnostics related: + // ========================================================================== + + gated!( + rustc_on_unimplemented, Whitelisted, + template!( + List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, + NameValueStr: "message" + ), + on_unimplemented, + experimental!(rustc_on_unimplemented), + ), + // Whitelists "identity-like" conversion methods to suggest on type mismatch. + rustc_attr!(rustc_conversion_suggestion, Whitelisted, template!(Word), INTERAL_UNSTABLE), + + // ========================================================================== + // Internal attributes, Const related: + // ========================================================================== + + rustc_attr!(rustc_promotable, Whitelisted, template!(Word), IMPL_DETAIL), + rustc_attr!(rustc_allow_const_fn_ptr, Whitelisted, template!(Word), IMPL_DETAIL), + rustc_attr!(rustc_args_required_const, Whitelisted, template!(List: "N"), INTERAL_UNSTABLE), + + // ========================================================================== + // Internal attributes, Layout related: + // ========================================================================== + + rustc_attr!( + rustc_layout_scalar_valid_range_start, Whitelisted, template!(List: "value"), + "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \ + niche optimizations in libcore and will never be stable", + ), + rustc_attr!( + rustc_layout_scalar_valid_range_end, Whitelisted, template!(List: "value"), + "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \ + niche optimizations in libcore and will never be stable", + ), + rustc_attr!( + rustc_nonnull_optimization_guaranteed, Whitelisted, template!(Word), + "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \ + niche optimizations in libcore and will never be stable", + ), + + // ========================================================================== + // Internal attributes, Misc: + // ========================================================================== + gated!( + lang, Normal, template!(NameValueStr: "name"), lang_items, + "language items are subject to change", + ), + ( + sym::rustc_diagnostic_item, + Normal, + template!(NameValueStr: "name"), + Gated( + Stability::Unstable, + sym::rustc_attrs, + "diagnostic items compiler internal support for linting", + cfg_fn!(rustc_attrs), + ), + ), + ( + sym::no_debug, Whitelisted, template!(Word), + Gated( + Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721", None), + sym::no_debug, + "the `#[no_debug]` attribute was an experimental feature that has been \ + deprecated due to lack of demand", + cfg_fn!(no_debug) + ) + ), + gated!( + // Used in resolve: + prelude_import, Whitelisted, template!(Word), + "`#[prelude_import]` is for use by rustc only", + ), + gated!( + rustc_paren_sugar, Normal, template!(Word), unboxed_closures, + "unboxed_closures are still evolving", + ), + rustc_attr!( + rustc_inherit_overflow_checks, Whitelisted, template!(Word), + "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \ + overflow checking behavior of several libcore functions that are inlined \ + across crates and will never be stable", + ), + rustc_attr!(rustc_reservation_impl, Normal, template!(NameValueStr: "reservation message"), + "the `#[rustc_reservation_impl]` attribute is internally used \ + for reserving for `for From for T` impl" + ), + rustc_attr!( + rustc_test_marker, Normal, template!(Word), + "the `#[rustc_test_marker]` attribute is used internally to track tests", + ), + + // ========================================================================== + // Internal attributes, Testing: + // ========================================================================== + + rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)), + rustc_attr!(TEST, rustc_variance, Normal, template!(Word)), + rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")), + rustc_attr!(TEST, rustc_regions, Normal, template!(Word)), + rustc_attr!(TEST, rustc_error, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_dump_user_substs, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode")), + rustc_attr!(TEST, rustc_then_this_would_need, Whitelisted, template!(List: "DepNode")), + rustc_attr!( + TEST, rustc_dirty, Whitelisted, + template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), + ), + rustc_attr!( + TEST, rustc_clean, Whitelisted, + template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), + ), + rustc_attr!( + TEST, rustc_partition_reused, Whitelisted, + template!(List: r#"cfg = "...", module = "...""#), + ), + rustc_attr!( + TEST, rustc_partition_codegened, Whitelisted, + template!(List: r#"cfg = "...", module = "...""#), + ), + rustc_attr!( + TEST, rustc_expected_cgu_reuse, Whitelisted, + template!(List: r#"cfg = "...", module = "...", kind = "...""#), + ), + rustc_attr!(TEST, rustc_synthetic, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_symbol_name, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_def_path, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_mir, Whitelisted, template!(List: "arg1, arg2, ...")), + rustc_attr!(TEST, rustc_dump_program_clauses, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_dump_env_program_clauses, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_object_lifetime_default, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/)), + gated!( + omit_gdb_pretty_printer_section, Whitelisted, template!(Word), + "the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite", + ), +]; + +pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> { + BUILTIN_ATTRIBUTES.iter().filter(|(.., gate)| gate.is_deprecated()).collect() +} + +pub fn is_builtin_attr_name(name: ast::Name) -> bool { + BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() +} + +pub fn is_builtin_attr(attr: &ast::Attribute) -> bool { + attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).is_some() +} + +lazy_static! { + pub static ref BUILTIN_ATTRIBUTE_MAP: FxHashMap = { + let mut map = FxHashMap::default(); + for attr in BUILTIN_ATTRIBUTES.iter() { + if map.insert(attr.0, attr).is_some() { + panic!("duplicate builtin attribute `{}`", attr.0); + } + } + map + }; +} diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs new file mode 100644 index 0000000000000..9e40b1a26ac1a --- /dev/null +++ b/src/libsyntax/feature_gate/check.rs @@ -0,0 +1,879 @@ +use super::{active::{ACTIVE_FEATURES, Features}, Feature, State as FeatureState}; +use super::accepted::ACCEPTED_FEATURES; +use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; +use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP}; + +use crate::ast::{ + self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind, + PatKind, RangeEnd, +}; +use crate::attr::{self, check_builtin_attribute}; +use crate::source_map::Spanned; +use crate::edition::{ALL_EDITIONS, Edition}; +use crate::visit::{self, FnKind, Visitor}; +use crate::parse::{token, ParseSess}; +use crate::parse::parser::Parser; +use crate::symbol::{Symbol, sym}; +use crate::tokenstream::TokenTree; + +use errors::{Applicability, DiagnosticBuilder, Handler}; +use rustc_data_structures::fx::FxHashMap; +use rustc_target::spec::abi::Abi; +use syntax_pos::{Span, DUMMY_SP, MultiSpan}; +use log::debug; + +use std::env; + +#[derive(Copy, Clone, Debug)] +pub enum Stability { + Unstable, + // First argument is tracking issue link; second argument is an optional + // help message, which defaults to "remove this attribute" + Deprecated(&'static str, Option<&'static str>), +} + +macro_rules! gate_feature_fn { + ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{ + let (cx, has_feature, span, + name, explain, level) = (&*$cx, $has_feature, $span, $name, $explain, $level); + let has_feature: bool = has_feature(&$cx.features); + debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); + if !has_feature && !span.allows_unstable($name) { + leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level) + .emit(); + } + }} +} + +macro_rules! gate_feature { + ($cx: expr, $feature: ident, $span: expr, $explain: expr) => { + gate_feature_fn!($cx, |x:&Features| x.$feature, $span, + sym::$feature, $explain, GateStrength::Hard) + }; + ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => { + gate_feature_fn!($cx, |x:&Features| x.$feature, $span, + sym::$feature, $explain, $level) + }; +} + +crate fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) { + PostExpansionVisitor { parse_sess, features }.visit_attribute(attr) +} + +fn find_lang_feature_issue(feature: Symbol) -> Option { + if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) { + // FIXME (#28244): enforce that active features have issue numbers + // assert!(info.issue.is_some()) + info.issue + } else { + // search in Accepted, Removed, or Stable Removed features + let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES) + .find(|t| t.name == feature); + match found { + Some(&Feature { issue, .. }) => issue, + None => panic!("Feature `{}` is not declared anywhere", feature), + } + } +} + +pub enum GateIssue { + Language, + Library(Option) +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum GateStrength { + /// A hard error. (Most feature gates should use this.) + Hard, + /// Only a warning. (Use this only as backwards-compatibility demands.) + Soft, +} + +pub fn emit_feature_err( + sess: &ParseSess, + feature: Symbol, + span: Span, + issue: GateIssue, + explain: &str, +) { + feature_err(sess, feature, span, issue, explain).emit(); +} + +pub fn feature_err<'a, S: Into>( + sess: &'a ParseSess, + feature: Symbol, + span: S, + issue: GateIssue, + explain: &str, +) -> DiagnosticBuilder<'a> { + leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard) +} + +fn leveled_feature_err<'a, S: Into>( + sess: &'a ParseSess, + feature: Symbol, + span: S, + issue: GateIssue, + explain: &str, + level: GateStrength, +) -> DiagnosticBuilder<'a> { + let diag = &sess.span_diagnostic; + + let issue = match issue { + GateIssue::Language => find_lang_feature_issue(feature), + GateIssue::Library(lib) => lib, + }; + + let mut err = match level { + GateStrength::Hard => { + diag.struct_span_err_with_code(span, explain, stringify_error_code!(E0658)) + } + GateStrength::Soft => diag.struct_span_warn(span, explain), + }; + + match issue { + None | Some(0) => {} // We still accept `0` as a stand-in for backwards compatibility + Some(n) => { + err.note(&format!( + "for more information, see https://github.com/rust-lang/rust/issues/{}", + n, + )); + } + } + + // #23973: do not suggest `#![feature(...)]` if we are in beta/stable + if sess.unstable_features.is_nightly_build() { + err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature)); + } + + // If we're on stable and only emitting a "soft" warning, add a note to + // clarify that the feature isn't "on" (rather than being on but + // warning-worthy). + if !sess.unstable_features.is_nightly_build() && level == GateStrength::Soft { + err.help("a nightly build of the compiler is required to enable this feature"); + } + + err + +} + +const EXPLAIN_BOX_SYNTAX: &str = + "box expression syntax is experimental; you can call `Box::new` instead"; + +pub const EXPLAIN_STMT_ATTR_SYNTAX: &str = + "attributes on expressions are experimental"; + +pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &str = + "allow_internal_unstable side-steps feature gating and stability checks"; +pub const EXPLAIN_ALLOW_INTERNAL_UNSAFE: &str = + "allow_internal_unsafe side-steps the unsafe_code lint"; + +pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &str = + "unsized tuple coercion is not stable enough for use and is subject to change"; + +struct PostExpansionVisitor<'a> { + parse_sess: &'a ParseSess, + features: &'a Features, +} + +macro_rules! gate_feature_post { + ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{ + let (cx, span) = ($cx, $span); + if !span.allows_unstable(sym::$feature) { + gate_feature!(cx, $feature, span, $explain) + } + }}; + ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{ + let (cx, span) = ($cx, $span); + if !span.allows_unstable(sym::$feature) { + gate_feature!(cx, $feature, span, $explain, $level) + } + }} +} + +impl<'a> PostExpansionVisitor<'a> { + fn check_abi(&self, abi: Abi, span: Span) { + match abi { + Abi::RustIntrinsic => { + gate_feature_post!(&self, intrinsics, span, + "intrinsics are subject to change"); + }, + Abi::PlatformIntrinsic => { + gate_feature_post!(&self, platform_intrinsics, span, + "platform intrinsics are experimental and possibly buggy"); + }, + Abi::Vectorcall => { + gate_feature_post!(&self, abi_vectorcall, span, + "vectorcall is experimental and subject to change"); + }, + Abi::Thiscall => { + gate_feature_post!(&self, abi_thiscall, span, + "thiscall is experimental and subject to change"); + }, + Abi::RustCall => { + gate_feature_post!(&self, unboxed_closures, span, + "rust-call ABI is subject to change"); + }, + Abi::PtxKernel => { + gate_feature_post!(&self, abi_ptx, span, + "PTX ABIs are experimental and subject to change"); + }, + Abi::Unadjusted => { + gate_feature_post!(&self, abi_unadjusted, span, + "unadjusted ABI is an implementation detail and perma-unstable"); + }, + Abi::Msp430Interrupt => { + gate_feature_post!(&self, abi_msp430_interrupt, span, + "msp430-interrupt ABI is experimental and subject to change"); + }, + Abi::X86Interrupt => { + gate_feature_post!(&self, abi_x86_interrupt, span, + "x86-interrupt ABI is experimental and subject to change"); + }, + Abi::AmdGpuKernel => { + gate_feature_post!(&self, abi_amdgpu_kernel, span, + "amdgpu-kernel ABI is experimental and subject to change"); + }, + // Stable + Abi::Cdecl | + Abi::Stdcall | + Abi::Fastcall | + Abi::Aapcs | + Abi::Win64 | + Abi::SysV64 | + Abi::Rust | + Abi::C | + Abi::System => {} + } + } +} + +impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { + fn visit_attribute(&mut self, attr: &ast::Attribute) { + let attr_info = + attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a); + // Check feature gates for built-in attributes. + if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info { + gate_feature_fn!(self, has_feature, attr.span, name, descr, GateStrength::Hard); + } + // Check input tokens for built-in and key-value attributes. + match attr_info { + // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. + Some((name, _, template, _)) if name != sym::rustc_dummy => + check_builtin_attribute(self.parse_sess, attr, name, template), + _ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() { + if token == token::Eq { + // All key-value attributes are restricted to meta-item syntax. + attr.parse_meta(self.parse_sess).map_err(|mut err| err.emit()).ok(); + } + } + } + // Check unstable flavors of the `#[doc]` attribute. + if attr.check_name(sym::doc) { + for nested_meta in attr.meta_item_list().unwrap_or_default() { + macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => { + $(if nested_meta.check_name(sym::$name) { + let msg = concat!("`#[doc(", stringify!($name), ")]` is experimental"); + gate_feature!(self, $feature, attr.span, msg); + })* + }} + + gate_doc!( + include => external_doc + cfg => doc_cfg + masked => doc_masked + spotlight => doc_spotlight + alias => doc_alias + keyword => doc_keyword + ); + } + } + } + + fn visit_name(&mut self, sp: Span, name: ast::Name) { + if !name.as_str().is_ascii() { + gate_feature_post!( + &self, + non_ascii_idents, + self.parse_sess.source_map().def_span(sp), + "non-ascii idents are not fully supported" + ); + } + } + + fn visit_item(&mut self, i: &'a ast::Item) { + match i.kind { + ast::ItemKind::ForeignMod(ref foreign_module) => { + self.check_abi(foreign_module.abi, i.span); + } + + ast::ItemKind::Fn(..) => { + if attr::contains_name(&i.attrs[..], sym::plugin_registrar) { + gate_feature_post!(&self, plugin_registrar, i.span, + "compiler plugins are experimental and possibly buggy"); + } + if attr::contains_name(&i.attrs[..], sym::start) { + gate_feature_post!(&self, start, i.span, + "a `#[start]` function is an experimental \ + feature whose signature may change \ + over time"); + } + if attr::contains_name(&i.attrs[..], sym::main) { + gate_feature_post!(&self, main, i.span, + "declaration of a non-standard `#[main]` \ + function may change over time, for now \ + a top-level `fn main()` is required"); + } + } + + ast::ItemKind::Struct(..) => { + for attr in attr::filter_by_name(&i.attrs[..], sym::repr) { + for item in attr.meta_item_list().unwrap_or_else(Vec::new) { + if item.check_name(sym::simd) { + gate_feature_post!(&self, repr_simd, attr.span, + "SIMD types are experimental and possibly buggy"); + } + } + } + } + + ast::ItemKind::Enum(ast::EnumDef{ref variants, ..}, ..) => { + for variant in variants { + match (&variant.data, &variant.disr_expr) { + (ast::VariantData::Unit(..), _) => {}, + (_, Some(disr_expr)) => + gate_feature_post!( + &self, + arbitrary_enum_discriminant, + disr_expr.value.span, + "discriminants on non-unit variants are experimental"), + _ => {}, + } + } + + let has_feature = self.features.arbitrary_enum_discriminant; + if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) { + Parser::maybe_report_invalid_custom_discriminants(self.parse_sess, &variants); + } + } + + ast::ItemKind::Impl(_, polarity, defaultness, ..) => { + if polarity == ast::ImplPolarity::Negative { + gate_feature_post!(&self, optin_builtin_traits, + i.span, + "negative trait bounds are not yet fully implemented; \ + use marker types for now"); + } + + if let ast::Defaultness::Default = defaultness { + gate_feature_post!(&self, specialization, + i.span, + "specialization is unstable"); + } + } + + ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => { + gate_feature_post!(&self, optin_builtin_traits, + i.span, + "auto traits are experimental and possibly buggy"); + } + + ast::ItemKind::TraitAlias(..) => { + gate_feature_post!( + &self, + trait_alias, + i.span, + "trait aliases are experimental" + ); + } + + ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => { + let msg = "`macro` is experimental"; + gate_feature_post!(&self, decl_macro, i.span, msg); + } + + ast::ItemKind::OpaqueTy(..) => { + gate_feature_post!( + &self, + type_alias_impl_trait, + i.span, + "`impl Trait` in type aliases is unstable" + ); + } + + _ => {} + } + + visit::walk_item(self, i); + } + + fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) { + match i.kind { + ast::ForeignItemKind::Fn(..) | + ast::ForeignItemKind::Static(..) => { + let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name); + let links_to_llvm = match link_name { + Some(val) => val.as_str().starts_with("llvm."), + _ => false + }; + if links_to_llvm { + gate_feature_post!(&self, link_llvm_intrinsics, i.span, + "linking to LLVM intrinsics is experimental"); + } + } + ast::ForeignItemKind::Ty => { + gate_feature_post!(&self, extern_types, i.span, + "extern types are experimental"); + } + ast::ForeignItemKind::Macro(..) => {} + } + + visit::walk_foreign_item(self, i) + } + + fn visit_ty(&mut self, ty: &'a ast::Ty) { + match ty.kind { + ast::TyKind::BareFn(ref bare_fn_ty) => { + self.check_abi(bare_fn_ty.abi, ty.span); + } + ast::TyKind::Never => { + gate_feature_post!(&self, never_type, ty.span, + "The `!` type is experimental"); + } + _ => {} + } + visit::walk_ty(self, ty) + } + + fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) { + if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty { + if let ast::TyKind::Never = output_ty.kind { + // Do nothing. + } else { + self.visit_ty(output_ty) + } + } + } + + fn visit_expr(&mut self, e: &'a ast::Expr) { + match e.kind { + ast::ExprKind::Box(_) => { + gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX); + } + ast::ExprKind::Type(..) => { + // To avoid noise about type ascription in common syntax errors, only emit if it + // is the *only* error. + if self.parse_sess.span_diagnostic.err_count() == 0 { + gate_feature_post!(&self, type_ascription, e.span, + "type ascription is experimental"); + } + } + ast::ExprKind::TryBlock(_) => { + gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); + } + ast::ExprKind::Block(_, opt_label) => { + if let Some(label) = opt_label { + gate_feature_post!(&self, label_break_value, label.ident.span, + "labels on blocks are unstable"); + } + } + _ => {} + } + visit::walk_expr(self, e) + } + + fn visit_arm(&mut self, arm: &'a ast::Arm) { + visit::walk_arm(self, arm) + } + + fn visit_pat(&mut self, pattern: &'a ast::Pat) { + match &pattern.kind { + PatKind::Slice(pats) => { + for pat in &*pats { + let span = pat.span; + let inner_pat = match &pat.kind { + PatKind::Ident(.., Some(pat)) => pat, + _ => pat, + }; + if inner_pat.is_rest() { + gate_feature_post!( + &self, + slice_patterns, + span, + "subslice patterns are unstable" + ); + } + } + } + PatKind::Box(..) => { + gate_feature_post!(&self, box_patterns, + pattern.span, + "box pattern syntax is experimental"); + } + PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => { + gate_feature_post!(&self, exclusive_range_pattern, pattern.span, + "exclusive range pattern syntax is experimental"); + } + _ => {} + } + visit::walk_pat(self, pattern) + } + + fn visit_fn(&mut self, + fn_kind: FnKind<'a>, + fn_decl: &'a ast::FnDecl, + span: Span, + _node_id: NodeId) { + if let Some(header) = fn_kind.header() { + // Stability of const fn methods are covered in + // `visit_trait_item` and `visit_impl_item` below; this is + // because default methods don't pass through this point. + self.check_abi(header.abi, span); + } + + if fn_decl.c_variadic() { + gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable"); + } + + visit::walk_fn(self, fn_kind, fn_decl, span) + } + + fn visit_generic_param(&mut self, param: &'a GenericParam) { + match param.kind { + GenericParamKind::Const { .. } => + gate_feature_post!(&self, const_generics, param.ident.span, + "const generics are unstable"), + _ => {} + } + visit::walk_generic_param(self, param) + } + + fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) { + match constraint.kind { + AssocTyConstraintKind::Bound { .. } => + gate_feature_post!(&self, associated_type_bounds, constraint.span, + "associated type bounds are unstable"), + _ => {} + } + visit::walk_assoc_ty_constraint(self, constraint) + } + + fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) { + match ti.kind { + ast::TraitItemKind::Method(ref sig, ref block) => { + if block.is_none() { + self.check_abi(sig.header.abi, ti.span); + } + if sig.decl.c_variadic() { + gate_feature_post!(&self, c_variadic, ti.span, + "C-variadic functions are unstable"); + } + if sig.header.constness.node == ast::Constness::Const { + gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); + } + } + ast::TraitItemKind::Type(_, ref default) => { + // We use three if statements instead of something like match guards so that all + // of these errors can be emitted if all cases apply. + if default.is_some() { + gate_feature_post!(&self, associated_type_defaults, ti.span, + "associated type defaults are unstable"); + } + if !ti.generics.params.is_empty() { + gate_feature_post!(&self, generic_associated_types, ti.span, + "generic associated types are unstable"); + } + if !ti.generics.where_clause.predicates.is_empty() { + gate_feature_post!(&self, generic_associated_types, ti.span, + "where clauses on associated types are unstable"); + } + } + _ => {} + } + visit::walk_trait_item(self, ti) + } + + fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) { + if ii.defaultness == ast::Defaultness::Default { + gate_feature_post!(&self, specialization, + ii.span, + "specialization is unstable"); + } + + match ii.kind { + ast::ImplItemKind::Method(ref sig, _) => { + if sig.decl.c_variadic() { + gate_feature_post!(&self, c_variadic, ii.span, + "C-variadic functions are unstable"); + } + } + ast::ImplItemKind::OpaqueTy(..) => { + gate_feature_post!( + &self, + type_alias_impl_trait, + ii.span, + "`impl Trait` in type aliases is unstable" + ); + } + ast::ImplItemKind::TyAlias(_) => { + if !ii.generics.params.is_empty() { + gate_feature_post!(&self, generic_associated_types, ii.span, + "generic associated types are unstable"); + } + if !ii.generics.where_clause.predicates.is_empty() { + gate_feature_post!(&self, generic_associated_types, ii.span, + "where clauses on associated types are unstable"); + } + } + _ => {} + } + visit::walk_impl_item(self, ii) + } + + fn visit_vis(&mut self, vis: &'a ast::Visibility) { + if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node { + gate_feature_post!(&self, crate_visibility_modifier, vis.span, + "`crate` visibility modifier is experimental"); + } + visit::walk_vis(self, vis) + } +} + +pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], + crate_edition: Edition, allow_features: &Option>) -> Features { + fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) { + let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed"); + if let Some(reason) = reason { + err.span_note(span, reason); + } else { + err.span_label(span, "feature has been removed"); + } + err.emit(); + } + + let mut features = Features::new(); + let mut edition_enabled_features = FxHashMap::default(); + + for &edition in ALL_EDITIONS { + if edition <= crate_edition { + // The `crate_edition` implies its respective umbrella feature-gate + // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX). + edition_enabled_features.insert(edition.feature_name(), edition); + } + } + + for feature in active_features_up_to(crate_edition) { + feature.set(&mut features, DUMMY_SP); + edition_enabled_features.insert(feature.name, crate_edition); + } + + // Process the edition umbrella feature-gates first, to ensure + // `edition_enabled_features` is completed before it's queried. + for attr in krate_attrs { + if !attr.check_name(sym::feature) { + continue + } + + let list = match attr.meta_item_list() { + Some(list) => list, + None => continue, + }; + + for mi in list { + if !mi.is_word() { + continue; + } + + let name = mi.name_or_empty(); + + let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied(); + if let Some(edition) = edition { + if edition <= crate_edition { + continue; + } + + for feature in active_features_up_to(edition) { + // FIXME(Manishearth) there is currently no way to set + // lib features by edition + feature.set(&mut features, DUMMY_SP); + edition_enabled_features.insert(feature.name, edition); + } + } + } + } + + for attr in krate_attrs { + if !attr.check_name(sym::feature) { + continue + } + + let list = match attr.meta_item_list() { + Some(list) => list, + None => continue, + }; + + let bad_input = |span| { + struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input") + }; + + for mi in list { + let name = match mi.ident() { + Some(ident) if mi.is_word() => ident.name, + Some(ident) => { + bad_input(mi.span()).span_suggestion( + mi.span(), + "expected just one word", + format!("{}", ident.name), + Applicability::MaybeIncorrect, + ).emit(); + continue + } + None => { + bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit(); + continue + } + }; + + if let Some(edition) = edition_enabled_features.get(&name) { + struct_span_warn!( + span_handler, + mi.span(), + E0705, + "the feature `{}` is included in the Rust {} edition", + name, + edition, + ).emit(); + continue; + } + + if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) { + // Handled in the separate loop above. + continue; + } + + let removed = REMOVED_FEATURES.iter().find(|f| name == f.name); + let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.name); + if let Some(Feature { state, .. }) = removed.or(stable_removed) { + if let FeatureState::Removed { reason } + | FeatureState::Stabilized { reason } = state + { + feature_removed(span_handler, mi.span(), *reason); + continue; + } + } + + if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) { + let since = Some(Symbol::intern(since)); + features.declared_lang_features.push((name, mi.span(), since)); + continue; + } + + if let Some(allowed) = allow_features.as_ref() { + if allowed.iter().find(|f| *f == name.as_str()).is_none() { + span_err!(span_handler, mi.span(), E0725, + "the feature `{}` is not in the list of allowed features", + name); + continue; + } + } + + if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) { + f.set(&mut features, mi.span()); + features.declared_lang_features.push((name, mi.span(), None)); + continue; + } + + features.declared_lib_features.push((name, mi.span())); + } + } + + features +} + +fn active_features_up_to(edition: Edition) -> impl Iterator { + ACTIVE_FEATURES.iter() + .filter(move |feature| { + if let Some(feature_edition) = feature.edition { + feature_edition <= edition + } else { + false + } + }) +} + +pub fn check_crate(krate: &ast::Crate, + parse_sess: &ParseSess, + features: &Features, + unstable: UnstableFeatures) { + maybe_stage_features(&parse_sess.span_diagnostic, krate, unstable); + let mut visitor = PostExpansionVisitor { parse_sess, features }; + + macro_rules! gate_all { + ($gate:ident, $msg:literal) => { gate_all!($gate, $gate, $msg); }; + ($spans:ident, $gate:ident, $msg:literal) => { + for span in &*parse_sess.gated_spans.$spans.borrow() { + gate_feature!(&visitor, $gate, *span, $msg); + } + } + } + + gate_all!(let_chains, "`let` expressions in this position are experimental"); + gate_all!(async_closure, "async closures are unstable"); + gate_all!(yields, generators, "yield syntax is experimental"); + gate_all!(or_patterns, "or-patterns syntax is experimental"); + gate_all!(const_extern_fn, "`const extern fn` definitions are unstable"); + + visit::walk_crate(&mut visitor, krate); +} + +#[derive(Clone, Copy, Hash)] +pub enum UnstableFeatures { + /// Hard errors for unstable features are active, as on beta/stable channels. + Disallow, + /// Allow features to be activated, as on nightly. + Allow, + /// Errors are bypassed for bootstrapping. This is required any time + /// during the build that feature-related lints are set to warn or above + /// because the build turns on warnings-as-errors and uses lots of unstable + /// features. As a result, this is always required for building Rust itself. + Cheat +} + +impl UnstableFeatures { + pub fn from_environment() -> UnstableFeatures { + // `true` if this is a feature-staged build, i.e., on the beta or stable channel. + let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); + // `true` if we should enable unstable features for bootstrapping. + let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok(); + match (disable_unstable_features, bootstrap) { + (_, true) => UnstableFeatures::Cheat, + (true, _) => UnstableFeatures::Disallow, + (false, _) => UnstableFeatures::Allow + } + } + + pub fn is_nightly_build(&self) -> bool { + match *self { + UnstableFeatures::Allow | UnstableFeatures::Cheat => true, + _ => false, + } + } +} + +fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, unstable: UnstableFeatures) { + let allow_features = match unstable { + UnstableFeatures::Allow => true, + UnstableFeatures::Disallow => false, + UnstableFeatures::Cheat => true + }; + if !allow_features { + for attr in &krate.attrs { + if attr.check_name(sym::feature) { + let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"); + span_err!(span_handler, attr.span, E0554, + "`#![feature]` may not be used on the {} release channel", + release_channel); + } + } + } +} diff --git a/src/libsyntax/feature_gate/mod.rs b/src/libsyntax/feature_gate/mod.rs new file mode 100644 index 0000000000000..ca13ab3620508 --- /dev/null +++ b/src/libsyntax/feature_gate/mod.rs @@ -0,0 +1,65 @@ +//! # Feature gating +//! +//! This module implements the gating necessary for preventing certain compiler +//! features from being used by default. This module will crawl a pre-expanded +//! AST to ensure that there are no features which are used that are not +//! enabled. +//! +//! Features are enabled in programs via the crate-level attributes of +//! `#![feature(...)]` with a comma-separated list of features. +//! +//! For the purpose of future feature-tracking, once code for detection of feature +//! gate usage is added, *do not remove it again* even once the feature +//! becomes stable. + +mod accepted; +mod removed; +mod active; +mod builtin_attrs; +mod check; + +use std::fmt; +use crate::{edition::Edition, symbol::Symbol}; +use syntax_pos::Span; + +#[derive(Clone, Copy)] +pub enum State { + Accepted, + Active { set: fn(&mut Features, Span) }, + Removed { reason: Option<&'static str> }, + Stabilized { reason: Option<&'static str> }, +} + +impl fmt::Debug for State { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + State::Accepted { .. } => write!(f, "accepted"), + State::Active { .. } => write!(f, "active"), + State::Removed { .. } => write!(f, "removed"), + State::Stabilized { .. } => write!(f, "stabilized"), + } + } +} + +#[derive(Debug, Clone)] +pub struct Feature { + state: State, + name: Symbol, + since: &'static str, + issue: Option, + edition: Option, + description: &'static str, +} + +pub use active::{Features, INCOMPLETE_FEATURES}; +pub use builtin_attrs::{ + AttributeGate, AttributeType, GatedCfg, + BuiltinAttribute, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, + deprecated_attributes, is_builtin_attr, is_builtin_attr_name, +}; +pub use check::{ + check_crate, get_features, feature_err, emit_feature_err, + Stability, GateIssue, UnstableFeatures, + EXPLAIN_STMT_ATTR_SYNTAX, EXPLAIN_UNSIZED_TUPLE_COERCION, +}; +crate use check::check_attribute; diff --git a/src/libsyntax/feature_gate/removed.rs b/src/libsyntax/feature_gate/removed.rs new file mode 100644 index 0000000000000..2c29e1ebf1493 --- /dev/null +++ b/src/libsyntax/feature_gate/removed.rs @@ -0,0 +1,110 @@ +//! List of the removed feature gates. + +use crate::symbol::sym; +use super::{State, Feature}; + +macro_rules! declare_features { + ($( + $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, None, $reason:expr), + )+) => { + /// Represents unstable features which have since been removed (it was once Active) + pub const REMOVED_FEATURES: &[Feature] = &[ + $( + Feature { + state: State::Removed { reason: $reason }, + name: sym::$feature, + since: $ver, + issue: $issue, + edition: None, + description: concat!($($doc,)*), + } + ),+ + ]; + }; + + ($( + $(#[doc = $doc:tt])* (stable_removed, $feature:ident, $ver:expr, $issue:expr, None), + )+) => { + /// Represents stable features which have since been removed (it was once Accepted) + pub const STABLE_REMOVED_FEATURES: &[Feature] = &[ + $( + Feature { + state: State::Stabilized { reason: None }, + name: sym::$feature, + since: $ver, + issue: $issue, + edition: None, + description: concat!($($doc,)*), + } + ),+ + ]; + }; +} + +declare_features! ( + // ------------------------------------------------------------------------- + // feature-group-start: removed features + // ------------------------------------------------------------------------- + + (removed, import_shadowing, "1.0.0", None, None, None), + (removed, managed_boxes, "1.0.0", None, None, None), + /// Allows use of unary negate on unsigned integers, e.g., -e for e: u8 + (removed, negate_unsigned, "1.0.0", Some(29645), None, None), + (removed, reflect, "1.0.0", Some(27749), None, None), + /// A way to temporarily opt out of opt in copy. This will *never* be accepted. + (removed, opt_out_copy, "1.0.0", None, None, None), + (removed, quad_precision_float, "1.0.0", None, None, None), + (removed, struct_inherit, "1.0.0", None, None, None), + (removed, test_removed_feature, "1.0.0", None, None, None), + (removed, visible_private_types, "1.0.0", None, None, None), + (removed, unsafe_no_drop_flag, "1.0.0", None, None, None), + /// Allows using items which are missing stability attributes + (removed, unmarked_api, "1.0.0", None, None, None), + (removed, allocator, "1.0.0", None, None, None), + (removed, simd, "1.0.0", Some(27731), None, + Some("removed in favor of `#[repr(simd)]`")), + (removed, advanced_slice_patterns, "1.0.0", Some(62254), None, + Some("merged into `#![feature(slice_patterns)]`")), + (removed, macro_reexport, "1.0.0", Some(29638), None, + Some("subsumed by `pub use`")), + (removed, pushpop_unsafe, "1.2.0", None, None, None), + (removed, needs_allocator, "1.4.0", Some(27389), None, + Some("subsumed by `#![feature(allocator_internals)]`")), + (removed, proc_macro_mod, "1.27.0", Some(54727), None, + Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + (removed, proc_macro_expr, "1.27.0", Some(54727), None, + Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + (removed, proc_macro_non_items, "1.27.0", Some(54727), None, + Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + (removed, proc_macro_gen, "1.27.0", Some(54727), None, + Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + (removed, panic_implementation, "1.28.0", Some(44489), None, + Some("subsumed by `#[panic_handler]`")), + /// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`. + (removed, custom_derive, "1.32.0", Some(29644), None, + Some("subsumed by `#[proc_macro_derive]`")), + /// Paths of the form: `extern::foo::bar` + (removed, extern_in_paths, "1.33.0", Some(55600), None, + Some("subsumed by `::foo::bar` paths")), + (removed, quote, "1.33.0", Some(29601), None, None), + /// Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238). + (removed, dropck_parametricity, "1.38.0", Some(28498), None, None), + (removed, await_macro, "1.38.0", Some(50547), None, + Some("subsumed by `.await` syntax")), + /// Allows defining `existential type`s. + (removed, existential_type, "1.38.0", Some(63063), None, + Some("removed in favor of `#![feature(type_alias_impl_trait)]`")), + /// Allows using the macros: + /// + `__diagnostic_used` + /// + `__register_diagnostic` + /// +`__build_diagnostic_array` + (removed, rustc_diagnostic_macros, "1.38.0", None, None, None), + + // ------------------------------------------------------------------------- + // feature-group-end: removed features + // ------------------------------------------------------------------------- +); + +declare_features! ( + (stable_removed, no_stack_check, "1.0.0", None, None), +); diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index 83c9c692bd30c..2423e1070fc3e 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -12,7 +12,7 @@ use crate::source_map::{SourceMap, FilePathMapping}; use errors::registry::Registry; -use errors::{DiagnosticBuilder, SubDiagnostic, CodeSuggestion, SourceMapper}; +use errors::{SubDiagnostic, CodeSuggestion, SourceMapper}; use errors::{DiagnosticId, Applicability}; use errors::emitter::{Emitter, HumanReadableErrorType}; @@ -32,6 +32,7 @@ pub struct JsonEmitter { pretty: bool, ui_testing: bool, json_rendered: HumanReadableErrorType, + external_macro_backtrace: bool, } impl JsonEmitter { @@ -40,6 +41,7 @@ impl JsonEmitter { source_map: Lrc, pretty: bool, json_rendered: HumanReadableErrorType, + external_macro_backtrace: bool, ) -> JsonEmitter { JsonEmitter { dst: Box::new(io::stderr()), @@ -48,13 +50,18 @@ impl JsonEmitter { pretty, ui_testing: false, json_rendered, + external_macro_backtrace, } } - pub fn basic(pretty: bool, json_rendered: HumanReadableErrorType) -> JsonEmitter { + pub fn basic( + pretty: bool, + json_rendered: HumanReadableErrorType, + external_macro_backtrace: bool, + ) -> JsonEmitter { let file_path_mapping = FilePathMapping::empty(); JsonEmitter::stderr(None, Lrc::new(SourceMap::new(file_path_mapping)), - pretty, json_rendered) + pretty, json_rendered, external_macro_backtrace) } pub fn new( @@ -63,6 +70,7 @@ impl JsonEmitter { source_map: Lrc, pretty: bool, json_rendered: HumanReadableErrorType, + external_macro_backtrace: bool, ) -> JsonEmitter { JsonEmitter { dst, @@ -71,6 +79,7 @@ impl JsonEmitter { pretty, ui_testing: false, json_rendered, + external_macro_backtrace, } } @@ -80,8 +89,8 @@ impl JsonEmitter { } impl Emitter for JsonEmitter { - fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) { - let data = Diagnostic::from_diagnostic_builder(db, self); + fn emit_diagnostic(&mut self, db: &errors::Diagnostic) { + let data = Diagnostic::from_errors_diagnostic(db, self); let result = if self.pretty { writeln!(&mut self.dst, "{}", as_pretty_json(&data)) } else { @@ -103,6 +112,13 @@ impl Emitter for JsonEmitter { panic!("failed to print notification: {:?}", e); } } + + fn should_show_explain(&self) -> bool { + match self.json_rendered { + HumanReadableErrorType::Short(_) => false, + _ => true, + } + } } // The following data types are provided just for serialisation. @@ -189,7 +205,7 @@ struct ArtifactNotification<'a> { } impl Diagnostic { - fn from_diagnostic_builder(db: &DiagnosticBuilder<'_>, + fn from_errors_diagnostic(db: &errors::Diagnostic, je: &JsonEmitter) -> Diagnostic { let sugg = db.suggestions.iter().map(|sugg| { @@ -219,8 +235,9 @@ impl Diagnostic { } let buf = BufWriter::default(); let output = buf.clone(); - je.json_rendered.new_emitter(Box::new(buf), Some(je.sm.clone()), false) - .ui_testing(je.ui_testing).emit_diagnostic(db); + je.json_rendered.new_emitter( + Box::new(buf), Some(je.sm.clone()), false, None, je.external_macro_backtrace + ).ui_testing(je.ui_testing).emit_diagnostic(db); let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap(); let output = String::from_utf8(output).unwrap(); diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 8ac48d8d74a42..03b00188e255e 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -7,18 +7,15 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] -#![feature(bind_by_move_pattern_guards)] #![feature(box_syntax)] #![feature(const_fn)] #![feature(const_transmute)] #![feature(crate_visibility_modifier)] #![feature(label_break_value)] -#![feature(mem_take)] #![feature(nll)] #![feature(proc_macro_diagnostic)] #![feature(proc_macro_internals)] #![feature(proc_macro_span)] -#![feature(rustc_diagnostic_macros)] #![feature(try_trait)] #![feature(unicode_internals)] @@ -28,7 +25,7 @@ extern crate proc_macro; pub use errors; use rustc_data_structures::sync::Lock; -use rustc_data_structures::bit_set::GrowableBitSet; +use rustc_index::bit_set::GrowableBitSet; pub use rustc_data_structures::thin_vec::ThinVec; use ast::AttrId; use syntax_pos::edition::Edition; @@ -61,12 +58,12 @@ macro_rules! panictry { macro_rules! panictry_buffer { ($handler:expr, $e:expr) => ({ use std::result::Result::{Ok, Err}; - use errors::{FatalError, DiagnosticBuilder}; + use errors::FatalError; match $e { Ok(e) => e, Err(errs) => { for e in errs { - DiagnosticBuilder::new_diagnostic($handler, e).emit(); + $handler.emit_diagnostic(&e); } FatalError.raise() } @@ -123,12 +120,8 @@ scoped_tls::scoped_thread_local!(pub static GLOBALS: Globals); pub mod diagnostics { #[macro_use] pub mod macros; - pub mod plugin; - pub mod metadata; } -// N.B., this module needs to be declared first so diagnostics are -// registered before they are used. pub mod error_codes; pub mod util { @@ -167,21 +160,14 @@ pub mod ext { mod proc_macro_server; pub use syntax_pos::hygiene; + pub use mbe::macro_rules::compile_declarative_macro; pub mod allocator; pub mod base; pub mod build; pub mod expand; pub mod proc_macro; - pub mod tt { - pub mod transcribe; - pub mod macro_check; - pub mod macro_parser; - pub mod macro_rules; - pub mod quoted; - } + crate mod mbe; } pub mod early_buffered_lints; - -__build_diagnostic_array! { libsyntax, DIAGNOSTICS } diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index be04c6a76b06d..3923b9f297b9f 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -1,10 +1,10 @@ -//! A MutVisitor represents an AST modification; it accepts an AST piece and -//! and mutates it in place. So, for instance, macro expansion is a MutVisitor +//! A `MutVisitor` represents an AST modification; it accepts an AST piece and +//! and mutates it in place. So, for instance, macro expansion is a `MutVisitor` //! that walks over an AST and modifies it. //! -//! Note: using a MutVisitor (other than the MacroExpander MutVisitor) on +//! Note: using a `MutVisitor` (other than the `MacroExpander` `MutVisitor`) on //! an AST before macro expansion is probably a bad idea. For instance, -//! a MutVisitor renaming item names in a module will miss all of those +//! a `MutVisitor` renaming item names in a module will miss all of those //! that are created by the expansion of a macro. use crate::ast::*; @@ -98,8 +98,8 @@ pub trait MutVisitor: Sized { noop_visit_fn_header(header, self); } - fn visit_struct_field(&mut self, sf: &mut StructField) { - noop_visit_struct_field(sf, self); + fn flat_map_struct_field(&mut self, sf: StructField) -> SmallVec<[StructField; 1]> { + noop_flat_map_struct_field(sf, self) } fn visit_item_kind(&mut self, i: &mut ItemKind) { @@ -130,8 +130,8 @@ pub trait MutVisitor: Sized { noop_flat_map_stmt(s, self) } - fn visit_arm(&mut self, a: &mut Arm) { - noop_visit_arm(a, self); + fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> { + noop_flat_map_arm(arm, self) } fn visit_pat(&mut self, p: &mut P) { @@ -174,8 +174,8 @@ pub trait MutVisitor: Sized { noop_visit_foreign_mod(nm, self); } - fn visit_variant(&mut self, v: &mut Variant) { - noop_visit_variant(v, self); + fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> { + noop_flat_map_variant(v, self) } fn visit_ident(&mut self, i: &mut Ident) { @@ -225,8 +225,8 @@ pub trait MutVisitor: Sized { noop_visit_attribute(at, self); } - fn visit_arg(&mut self, a: &mut Arg) { - noop_visit_arg(a, self); + fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> { + noop_flat_map_param(param, self) } fn visit_generics(&mut self, generics: &mut Generics) { @@ -245,12 +245,8 @@ pub trait MutVisitor: Sized { noop_visit_variant_data(vdata, self); } - fn visit_generic_param(&mut self, param: &mut GenericParam) { - noop_visit_generic_param(param, self); - } - - fn visit_generic_params(&mut self, params: &mut Vec) { - noop_visit_generic_params(params, self); + fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> { + noop_flat_map_generic_param(param, self) } fn visit_tt(&mut self, tt: &mut TokenTree) { @@ -277,8 +273,8 @@ pub trait MutVisitor: Sized { noop_visit_mt(mt, self); } - fn visit_field(&mut self, field: &mut Field) { - noop_visit_field(field, self); + fn flat_map_field(&mut self, f: Field) -> SmallVec<[Field; 1]> { + noop_flat_map_field(f, self) } fn visit_where_clause(&mut self, where_clause: &mut WhereClause) { @@ -300,6 +296,10 @@ pub trait MutVisitor: Sized { fn visit_span(&mut self, _sp: &mut Span) { // Do nothing. } + + fn flat_map_field_pattern(&mut self, fp: FieldPat) -> SmallVec<[FieldPat; 1]> { + noop_flat_map_field_pattern(fp, self) + } } /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful @@ -362,6 +362,27 @@ pub fn visit_method_sig(MethodSig { header, decl }: &mut MethodSi vis.visit_fn_decl(decl); } +pub fn noop_flat_map_field_pattern( + mut fp: FieldPat, + vis: &mut T, +) -> SmallVec<[FieldPat; 1]> { + let FieldPat { + attrs, + id, + ident, + is_placeholder: _, + is_shorthand: _, + pat, + span, + } = &mut fp; + vis.visit_id(id); + vis.visit_ident(ident); + vis.visit_pat(pat); + vis.visit_span(span); + visit_thin_attrs(attrs, vis); + smallvec![fp] +} + pub fn noop_visit_use_tree(use_tree: &mut UseTree, vis: &mut T) { let UseTree { prefix, kind, span } = use_tree; vis.visit_path(prefix); @@ -382,15 +403,15 @@ pub fn noop_visit_use_tree(use_tree: &mut UseTree, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_arm( - Arm { attrs, pats, guard, body, span }: &mut Arm, - vis: &mut T, -) { +pub fn noop_flat_map_arm(mut arm: Arm, vis: &mut T) -> SmallVec<[Arm; 1]> { + let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = &mut arm; visit_attrs(attrs, vis); - visit_vec(pats, |pat| vis.visit_pat(pat)); + vis.visit_id(id); + vis.visit_pat(pat); visit_opt(guard, |guard| vis.visit_expr(guard)); vis.visit_expr(body); vis.visit_span(span); + smallvec![arm] } pub fn noop_visit_ty_constraint( @@ -411,9 +432,9 @@ pub fn noop_visit_ty_constraint( } pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { - let Ty { id, node, span } = ty.deref_mut(); + let Ty { id, kind, span } = ty.deref_mut(); vis.visit_id(id); - match node { + match kind { TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err | TyKind::Never | TyKind::CVarArgs => {} TyKind::Slice(ty) => vis.visit_ty(ty), @@ -424,7 +445,7 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { } TyKind::BareFn(bft) => { let BareFnTy { unsafety: _, abi: _, generic_params, decl } = bft.deref_mut(); - vis.visit_generic_params(generic_params); + generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_fn_decl(decl); } TyKind::Tup(tys) => visit_vec(tys, |ty| vis.visit_ty(ty)), @@ -454,14 +475,17 @@ pub fn noop_visit_foreign_mod(foreign_mod: &mut ForeignMod, vis: items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); } -pub fn noop_visit_variant(variant: &mut Variant, vis: &mut T) { - let Spanned { node: Variant_ { ident, attrs, id, data, disr_expr }, span } = variant; +pub fn noop_flat_map_variant(mut variant: Variant, vis: &mut T) + -> SmallVec<[Variant; 1]> +{ + let Variant { ident, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant; vis.visit_ident(ident); visit_attrs(attrs, vis); vis.visit_id(id); vis.visit_variant_data(data); visit_opt(disr_expr, |disr_expr| vis.visit_anon_const(disr_expr)); vis.visit_span(span); + smallvec![variant] } pub fn noop_visit_ident(Ident { name: _, span }: &mut Ident, vis: &mut T) { @@ -526,14 +550,15 @@ pub fn noop_visit_local(local: &mut P, vis: &mut T) { } pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { - let Attribute { id: _, style: _, path, tokens, is_sugared_doc: _, span } = attr; + let Attribute { item: AttrItem { path, tokens }, id: _, style: _, is_sugared_doc: _, span } + = attr; vis.visit_path(path); vis.visit_tts(tokens); vis.visit_span(span); } -pub fn noop_visit_mac(Spanned { node, span }: &mut Mac, vis: &mut T) { - let Mac_ { path, delim: _, tts, .. } = node; +pub fn noop_visit_mac(mac: &mut Mac, vis: &mut T) { + let Mac { path, delim: _, tts, span, prior_type_ascription: _ } = mac; vis.visit_path(path); vis.visit_tts(tts); vis.visit_span(span); @@ -552,8 +577,8 @@ pub fn noop_visit_meta_list_item(li: &mut NestedMetaItem, vis: &m } pub fn noop_visit_meta_item(mi: &mut MetaItem, vis: &mut T) { - let MetaItem { path: _, node, span } = mi; - match node { + let MetaItem { path: _, kind, span } = mi; + match kind { MetaItemKind::Word => {} MetaItemKind::List(mis) => visit_vec(mis, |mi| vis.visit_meta_list_item(mi)), MetaItemKind::NameValue(_s) => {} @@ -561,12 +586,14 @@ pub fn noop_visit_meta_item(mi: &mut MetaItem, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_arg(Arg { attrs, id, pat, span, ty }: &mut Arg, vis: &mut T) { +pub fn noop_flat_map_param(mut param: Param, vis: &mut T) -> SmallVec<[Param; 1]> { + let Param { attrs, id, pat, span, ty, is_placeholder: _ } = &mut param; vis.visit_id(id); visit_thin_attrs(attrs, vis); vis.visit_pat(pat); vis.visit_span(span); vis.visit_ty(ty); + smallvec![param] } pub fn noop_visit_tt(tt: &mut TokenTree, vis: &mut T) { @@ -589,7 +616,7 @@ pub fn noop_visit_tts(TokenStream(tts): &mut TokenStream, vis: &m }) } -// Apply ident visitor if it's an ident, apply other visits to interpolated nodes. +// Applies ident visitor if it's an ident; applies other visits to interpolated nodes. // In practice the ident part is not actually used by specific visitors right now, // but there's a test below checking that it works. pub fn noop_visit_token(t: &mut Token, vis: &mut T) { @@ -600,7 +627,7 @@ pub fn noop_visit_token(t: &mut Token, vis: &mut T) { vis.visit_ident(&mut ident); *name = ident.name; *span = ident.span; - return; // avoid visiting the span for the second time + return; // Avoid visiting the span for the second time. } token::Interpolated(nt) => { let mut nt = Lrc::make_mut(nt); @@ -611,28 +638,28 @@ pub fn noop_visit_token(t: &mut Token, vis: &mut T) { vis.visit_span(span); } -/// Apply visitor to elements of interpolated nodes. +/// Applies the visitor to elements of interpolated nodes. // // N.B., this can occur only when applying a visitor to partially expanded // code, where parsed pieces have gotten implanted ito *other* macro // invocations. This is relevant for macro hygiene, but possibly not elsewhere. // // One problem here occurs because the types for flat_map_item, flat_map_stmt, -// etc. allow the visitor to return *multiple* items; this is a problem for the +// etc., allow the visitor to return *multiple* items; this is a problem for the // nodes here, because they insist on having exactly one piece. One solution // would be to mangle the MutVisitor trait to include one-to-many and // one-to-one versions of these entry points, but that would probably confuse a // lot of people and help very few. Instead, I'm just going to put in dynamic // checks. I think the performance impact of this will be pretty much -// nonexistent. The danger is that someone will apply a MutVisitor to a +// nonexistent. The danger is that someone will apply a `MutVisitor` to a // partially expanded node, and will be confused by the fact that their -// "flat_map_item" or "flat_map_stmt" isn't getting called on NtItem or NtStmt +// `flat_map_item` or `flat_map_stmt` isn't getting called on `NtItem` or `NtStmt` // nodes. Hopefully they'll wind up reading this comment, and doing something // appropriate. // -// BTW, design choice: I considered just changing the type of, e.g., NtItem to +// BTW, design choice: I considered just changing the type of, e.g., `NtItem` to // contain multiple items, but decided against it when I looked at -// parse_item_or_view_item and tried to figure out what I would do with +// `parse_item_or_view_item` and tried to figure out what I would do with // multiple items there.... pub fn noop_visit_interpolated(nt: &mut token::Nonterminal, vis: &mut T) { match nt { @@ -655,7 +682,10 @@ pub fn noop_visit_interpolated(nt: &mut token::Nonterminal, vis: token::NtIdent(ident, _is_raw) => vis.visit_ident(ident), token::NtLifetime(ident) => vis.visit_ident(ident), token::NtLiteral(expr) => vis.visit_expr(expr), - token::NtMeta(meta) => vis.visit_meta_item(meta), + token::NtMeta(AttrItem { path, tokens }) => { + vis.visit_path(path); + vis.visit_tts(tokens); + } token::NtPath(path) => vis.visit_path(path), token::NtTT(tt) => vis.visit_tt(tt), token::NtImplItem(item) => @@ -691,8 +721,8 @@ pub fn noop_visit_asyncness(asyncness: &mut IsAsync, vis: &mut T) } pub fn noop_visit_fn_decl(decl: &mut P, vis: &mut T) { - let FnDecl { inputs, output, c_variadic: _ } = decl.deref_mut(); - visit_vec(inputs, |input| vis.visit_arg(input)); + let FnDecl { inputs, output } = decl.deref_mut(); + inputs.flat_map_in_place(|param| vis.flat_map_param(param)); match output { FunctionRetTy::Default(span) => vis.visit_span(span), FunctionRetTy::Ty(ty) => vis.visit_ty(ty), @@ -706,8 +736,12 @@ pub fn noop_visit_param_bound(pb: &mut GenericBound, vis: &mut T) } } -pub fn noop_visit_generic_param(param: &mut GenericParam, vis: &mut T) { - let GenericParam { id, ident, attrs, bounds, kind } = param; +pub fn noop_flat_map_generic_param( + mut param: GenericParam, + vis: &mut T +) -> SmallVec<[GenericParam; 1]> +{ + let GenericParam { id, ident, attrs, bounds, kind, is_placeholder: _ } = &mut param; vis.visit_id(id); vis.visit_ident(ident); visit_thin_attrs(attrs, vis); @@ -721,10 +755,7 @@ pub fn noop_visit_generic_param(param: &mut GenericParam, vis: &m vis.visit_ty(ty); } } -} - -pub fn noop_visit_generic_params(params: &mut Vec, vis: &mut T){ - visit_vec(params, |param| vis.visit_generic_param(param)); + smallvec![param] } pub fn noop_visit_label(Label { ident }: &mut Label, vis: &mut T) { @@ -738,7 +769,7 @@ fn noop_visit_lifetime(Lifetime { id, ident }: &mut Lifetime, vis pub fn noop_visit_generics(generics: &mut Generics, vis: &mut T) { let Generics { params, where_clause, span } = generics; - vis.visit_generic_params(params); + params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_where_clause(where_clause); vis.visit_span(span); } @@ -754,7 +785,7 @@ pub fn noop_visit_where_predicate(pred: &mut WherePredicate, vis: WherePredicate::BoundPredicate(bp) => { let WhereBoundPredicate { span, bound_generic_params, bounded_ty, bounds } = bp; vis.visit_span(span); - vis.visit_generic_params(bound_generic_params); + bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_ty(bounded_ty); visit_vec(bounds, |bound| vis.visit_param_bound(bound)); } @@ -776,9 +807,11 @@ pub fn noop_visit_where_predicate(pred: &mut WherePredicate, vis: pub fn noop_visit_variant_data(vdata: &mut VariantData, vis: &mut T) { match vdata { - VariantData::Struct(fields, ..) => visit_vec(fields, |field| vis.visit_struct_field(field)), + VariantData::Struct(fields, ..) => { + fields.flat_map_in_place(|field| vis.flat_map_struct_field(field)); + }, VariantData::Tuple(fields, id) => { - visit_vec(fields, |field| vis.visit_struct_field(field)); + fields.flat_map_in_place(|field| vis.flat_map_struct_field(field)); vis.visit_id(id); }, VariantData::Unit(id) => vis.visit_id(id), @@ -792,27 +825,32 @@ pub fn noop_visit_trait_ref(TraitRef { path, ref_id }: &mut Trait pub fn noop_visit_poly_trait_ref(p: &mut PolyTraitRef, vis: &mut T) { let PolyTraitRef { bound_generic_params, trait_ref, span } = p; - vis.visit_generic_params(bound_generic_params); + bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_trait_ref(trait_ref); vis.visit_span(span); } -pub fn noop_visit_struct_field(f: &mut StructField, visitor: &mut T) { - let StructField { span, ident, vis, id, ty, attrs } = f; +pub fn noop_flat_map_struct_field(mut sf: StructField, visitor: &mut T) + -> SmallVec<[StructField; 1]> +{ + let StructField { span, ident, vis, id, ty, attrs, is_placeholder: _ } = &mut sf; visitor.visit_span(span); visit_opt(ident, |ident| visitor.visit_ident(ident)); visitor.visit_vis(vis); visitor.visit_id(id); visitor.visit_ty(ty); visit_attrs(attrs, visitor); + smallvec![sf] } -pub fn noop_visit_field(f: &mut Field, vis: &mut T) { - let Field { ident, expr, span, is_shorthand: _, attrs } = f; +pub fn noop_flat_map_field(mut f: Field, vis: &mut T) -> SmallVec<[Field; 1]> { + let Field { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = &mut f; vis.visit_ident(ident); vis.visit_expr(expr); + vis.visit_id(id); vis.visit_span(span); visit_thin_attrs(attrs, vis); + smallvec![f] } pub fn noop_visit_mt(MutTy { ty, mutbl: _ }: &mut MutTy, vis: &mut T) { @@ -856,7 +894,7 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { vis.visit_generics(generics); } ItemKind::Enum(EnumDef { variants }, generics) => { - visit_vec(variants, |variant| vis.visit_variant(variant)); + variants.flat_map_in_place(|variant| vis.flat_map_variant(variant)); vis.visit_generics(generics); } ItemKind::Struct(variant_data, generics) | @@ -887,12 +925,12 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { pub fn noop_flat_map_trait_item(mut item: TraitItem, vis: &mut T) -> SmallVec<[TraitItem; 1]> { - let TraitItem { id, ident, attrs, generics, node, span, tokens: _ } = &mut item; + let TraitItem { id, ident, attrs, generics, kind, span, tokens: _ } = &mut item; vis.visit_id(id); vis.visit_ident(ident); visit_attrs(attrs, vis); vis.visit_generics(generics); - match node { + match kind { TraitItemKind::Const(ty, default) => { vis.visit_ty(ty); visit_opt(default, |default| vis.visit_expr(default)); @@ -917,14 +955,14 @@ pub fn noop_flat_map_trait_item(mut item: TraitItem, vis: &mut T) pub fn noop_flat_map_impl_item(mut item: ImplItem, visitor: &mut T) -> SmallVec<[ImplItem; 1]> { - let ImplItem { id, ident, vis, defaultness: _, attrs, generics, node, span, tokens: _ } = + let ImplItem { id, ident, vis, defaultness: _, attrs, generics, kind, span, tokens: _ } = &mut item; visitor.visit_id(id); visitor.visit_ident(ident); visitor.visit_vis(vis); visit_attrs(attrs, visitor); visitor.visit_generics(generics); - match node { + match kind { ImplItemKind::Const(ty, expr) => { visitor.visit_ty(ty); visitor.visit_expr(expr); @@ -960,7 +998,7 @@ pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { id: DUMMY_NODE_ID, vis: respan(span.shrink_to_lo(), VisibilityKind::Public), span, - node: ItemKind::Mod(module), + kind: ItemKind::Mod(module), tokens: None, }); let items = vis.flat_map_item(item); @@ -970,8 +1008,8 @@ pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { let module = Mod { inner: span, items: vec![], inline: true }; Crate { module, attrs: vec![], span } } else if len == 1 { - let Item { attrs, span, node, .. } = items.into_iter().next().unwrap().into_inner(); - match node { + let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner(); + match kind { ItemKind::Mod(module) => Crate { module, attrs, span }, _ => panic!("visitor converted a module to not a module"), } @@ -981,14 +1019,14 @@ pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { }); } -// Mutate one item into possibly many items. +// Mutates one item into possibly many items. pub fn noop_flat_map_item(mut item: P, visitor: &mut T) -> SmallVec<[P; 1]> { - let Item { ident, attrs, id, node, vis, span, tokens: _ } = item.deref_mut(); + let Item { ident, attrs, id, kind, vis, span, tokens: _ } = item.deref_mut(); visitor.visit_ident(ident); visit_attrs(attrs, visitor); visitor.visit_id(id); - visitor.visit_item_kind(node); + visitor.visit_item_kind(kind); visitor.visit_vis(vis); visitor.visit_span(span); @@ -1001,10 +1039,10 @@ pub fn noop_flat_map_item(mut item: P, visitor: &mut T) pub fn noop_flat_map_foreign_item(mut item: ForeignItem, visitor: &mut T) -> SmallVec<[ForeignItem; 1]> { - let ForeignItem { ident, attrs, node, id, span, vis } = &mut item; + let ForeignItem { ident, attrs, kind, id, span, vis } = &mut item; visitor.visit_ident(ident); visit_attrs(attrs, visitor); - match node { + match kind { ForeignItemKind::Fn(fdec, generics) => { visitor.visit_fn_decl(fdec); visitor.visit_generics(generics); @@ -1021,9 +1059,9 @@ pub fn noop_flat_map_foreign_item(mut item: ForeignItem, visitor: } pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { - let Pat { id, node, span } = pat.deref_mut(); + let Pat { id, kind, span } = pat.deref_mut(); vis.visit_id(id); - match node { + match kind { PatKind::Wild | PatKind::Rest => {} PatKind::Ident(_binding_mode, ident, sub) => { vis.visit_ident(ident); @@ -1040,14 +1078,8 @@ pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { } PatKind::Struct(path, fields, _etc) => { vis.visit_path(path); - for Spanned { node: FieldPat { ident, pat, is_shorthand: _, attrs }, span } in fields { - vis.visit_ident(ident); - vis.visit_pat(pat); - visit_thin_attrs(attrs, vis); - vis.visit_span(span); - }; - } - PatKind::Tuple(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)), + fields.flat_map_in_place(|field| vis.flat_map_field_pattern(field)); + } PatKind::Box(inner) => vis.visit_pat(inner), PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner), PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => { @@ -1055,7 +1087,9 @@ pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { vis.visit_expr(e2); vis.visit_span(span); } - PatKind::Slice(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)), + PatKind::Tuple(elems) + | PatKind::Slice(elems) + | PatKind::Or(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)), PatKind::Paren(inner) => vis.visit_pat(inner), PatKind::Mac(mac) => vis.visit_mac(mac), } @@ -1067,8 +1101,8 @@ pub fn noop_visit_anon_const(AnonConst { id, value }: &mut AnonCo vis.visit_expr(value); } -pub fn noop_visit_expr(Expr { node, id, span, attrs }: &mut Expr, vis: &mut T) { - match node { +pub fn noop_visit_expr(Expr { kind, id, span, attrs }: &mut Expr, vis: &mut T) { + match kind { ExprKind::Box(expr) => vis.visit_expr(expr), ExprKind::Array(exprs) => visit_exprs(exprs, vis), ExprKind::Repeat(expr, count) => { @@ -1100,8 +1134,8 @@ pub fn noop_visit_expr(Expr { node, id, span, attrs }: &mut Expr, vis.visit_ty(ty); } ExprKind::AddrOf(_m, ohs) => vis.visit_expr(ohs), - ExprKind::Let(pats, scrutinee) => { - visit_vec(pats, |pat| vis.visit_pat(pat)); + ExprKind::Let(pat, scrutinee) => { + vis.visit_pat(pat); vis.visit_expr(scrutinee); } ExprKind::If(cond, tr, fl) => { @@ -1126,7 +1160,7 @@ pub fn noop_visit_expr(Expr { node, id, span, attrs }: &mut Expr, } ExprKind::Match(expr, arms) => { vis.visit_expr(expr); - visit_vec(arms, |arm| vis.visit_arm(arm)); + arms.flat_map_in_place(|arm| vis.flat_map_arm(arm)); } ExprKind::Closure(_capture_by, asyncness, _movability, decl, body, span) => { vis.visit_asyncness(asyncness); @@ -1179,7 +1213,7 @@ pub fn noop_visit_expr(Expr { node, id, span, attrs }: &mut Expr, } ExprKind::InlineAsm(asm) => { let InlineAsm { asm: _, asm_str_style: _, outputs, inputs, clobbers: _, volatile: _, - alignstack: _, dialect: _, ctxt: _ } = asm.deref_mut(); + alignstack: _, dialect: _ } = asm.deref_mut(); for out in outputs { let InlineAsmOutput { constraint: _, expr, is_rw: _, is_indirect: _ } = out; vis.visit_expr(expr); @@ -1189,13 +1223,13 @@ pub fn noop_visit_expr(Expr { node, id, span, attrs }: &mut Expr, ExprKind::Mac(mac) => vis.visit_mac(mac), ExprKind::Struct(path, fields, expr) => { vis.visit_path(path); - visit_vec(fields, |field| vis.visit_field(field)); + fields.flat_map_in_place(|field| vis.flat_map_field(field)); visit_opt(expr, |expr| vis.visit_expr(expr)); }, ExprKind::Paren(expr) => { vis.visit_expr(expr); - // Nodes that are equal modulo `Paren` sugar no-ops should have the same ids. + // Nodes that are equal modulo `Paren` sugar no-ops should have the same IDs. *id = expr.id; vis.visit_span(span); visit_thin_attrs(attrs, vis); @@ -1217,19 +1251,19 @@ pub fn noop_filter_map_expr(mut e: P, vis: &mut T) -> Optio Some({ vis.visit_expr(&mut e); e }) } -pub fn noop_flat_map_stmt(Stmt { node, mut span, mut id }: Stmt, vis: &mut T) +pub fn noop_flat_map_stmt(Stmt { kind, mut span, mut id }: Stmt, vis: &mut T) -> SmallVec<[Stmt; 1]> { vis.visit_id(&mut id); vis.visit_span(&mut span); - noop_flat_map_stmt_kind(node, vis).into_iter().map(|node| { - Stmt { id, node, span } + noop_flat_map_stmt_kind(kind, vis).into_iter().map(|kind| { + Stmt { id, kind, span } }).collect() } -pub fn noop_flat_map_stmt_kind(node: StmtKind, vis: &mut T) +pub fn noop_flat_map_stmt_kind(kind: StmtKind, vis: &mut T) -> SmallVec<[StmtKind; 1]> { - match node { + match kind { StmtKind::Local(mut local) => smallvec![StmtKind::Local({ vis.visit_local(&mut local); local })], StmtKind::Item(item) => vis.flat_map_item(item).into_iter().map(StmtKind::Item).collect(), diff --git a/src/libsyntax/mut_visit/tests.rs b/src/libsyntax/mut_visit/tests.rs index 6868736976b25..f779e0d0a6014 100644 --- a/src/libsyntax/mut_visit/tests.rs +++ b/src/libsyntax/mut_visit/tests.rs @@ -6,13 +6,13 @@ use crate::print::pprust; use crate::mut_visit; use crate::with_default_globals; -// this version doesn't care about getting comments or docstrings in. +// This version doesn't care about getting comments or doc-strings in. fn fake_print_crate(s: &mut pprust::State<'_>, krate: &ast::Crate) { s.print_mod(&krate.module, &krate.attrs) } -// change every identifier to "zz" +// Change every identifier to "zz". struct ToZzIdentMutVisitor; impl MutVisitor for ToZzIdentMutVisitor { @@ -24,7 +24,7 @@ impl MutVisitor for ToZzIdentMutVisitor { } } -// maybe add to expand.rs... +// Maybe add to `expand.rs`. macro_rules! assert_pred { ($pred:expr, $predname:expr, $a:expr , $b:expr) => ( { @@ -39,7 +39,7 @@ macro_rules! assert_pred { ) } -// make sure idents get transformed everywhere +// Make sure idents get transformed everywhere. #[test] fn ident_transformation () { with_default_globals(|| { let mut zz_visitor = ToZzIdentMutVisitor; @@ -54,7 +54,7 @@ macro_rules! assert_pred { }) } -// even inside macro defs.... +// Make sure idents get transformed even inside macro defs. #[test] fn ident_transformation_in_defs () { with_default_globals(|| { let mut zz_visitor = ToZzIdentMutVisitor; diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index a42da1123600a..e74f3045db804 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -19,15 +19,7 @@ const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \ permitted in this context"; impl<'a> Parser<'a> { - crate fn parse_arg_attributes(&mut self) -> PResult<'a, Vec> { - let attrs = self.parse_outer_attributes()?; - attrs.iter().for_each(|a| - self.sess.param_attr_spans.borrow_mut().push(a.span) - ); - Ok(attrs) - } - - /// Parse attributes that appear before an item + /// Parses attributes that appear before an item. crate fn parse_outer_attributes(&mut self) -> PResult<'a, Vec> { let mut attrs: Vec = Vec::new(); let mut just_parsed_doc_comment = false; @@ -70,10 +62,10 @@ impl<'a> Parser<'a> { Ok(attrs) } - /// Matches `attribute = # ! [ meta_item ]` + /// Matches `attribute = # ! [ meta_item ]`. /// - /// If permit_inner is true, then a leading `!` indicates an inner - /// attribute + /// If `permit_inner` is `true`, then a leading `!` indicates an inner + /// attribute. pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> { debug!("parse_attribute: permit_inner={:?} self.token={:?}", permit_inner, @@ -98,7 +90,7 @@ impl<'a> Parser<'a> { debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}", inner_parse_policy, self.token); - let (span, path, tokens, style) = match self.token.kind { + let (span, item, style) = match self.token.kind { token::Pound => { let lo = self.token.span; self.bump(); @@ -115,7 +107,7 @@ impl<'a> Parser<'a> { }; self.expect(&token::OpenDelim(token::Bracket))?; - let (path, tokens) = self.parse_meta_item_unrestricted()?; + let item = self.parse_attr_item()?; self.expect(&token::CloseDelim(token::Bracket))?; let hi = self.prev_span; @@ -150,7 +142,7 @@ impl<'a> Parser<'a> { } } - (attr_sp, path, tokens, style) + (attr_sp, item, style) } _ => { let token_str = self.this_token_to_string(); @@ -159,35 +151,34 @@ impl<'a> Parser<'a> { }; Ok(ast::Attribute { + item, id: attr::mk_attr_id(), style, - path, - tokens, is_sugared_doc: false, span, }) } - /// Parse an inner part of attribute - path and following tokens. + /// Parses an inner part of an attribute (the path and following tokens). /// The tokens must be either a delimited token stream, or empty token stream, /// or the "legacy" key-value form. - /// PATH `(` TOKEN_STREAM `)` - /// PATH `[` TOKEN_STREAM `]` - /// PATH `{` TOKEN_STREAM `}` - /// PATH - /// PATH `=` TOKEN_TREE + /// PATH `(` TOKEN_STREAM `)` + /// PATH `[` TOKEN_STREAM `]` + /// PATH `{` TOKEN_STREAM `}` + /// PATH + /// PATH `=` UNSUFFIXED_LIT /// The delimiters or `=` are still put into the resulting token stream. - crate fn parse_meta_item_unrestricted(&mut self) -> PResult<'a, (ast::Path, TokenStream)> { - let meta = match self.token.kind { + pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> { + let item = match self.token.kind { token::Interpolated(ref nt) => match **nt { - Nonterminal::NtMeta(ref meta) => Some(meta.clone()), + Nonterminal::NtMeta(ref item) => Some(item.clone()), _ => None, }, _ => None, }; - Ok(if let Some(meta) = meta { + Ok(if let Some(item) = item { self.bump(); - (meta.path, meta.node.tokens(meta.span)) + item } else { let path = self.parse_path(PathStyle::Mod)?; let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) || @@ -214,15 +205,15 @@ impl<'a> Parser<'a> { } else { TokenStream::empty() }; - (path, tokens) + ast::AttrItem { path, tokens } }) } - /// Parse attributes that appear after the opening of an item. These should + /// Parses attributes that appear after the opening of an item. These should /// be preceded by an exclamation mark, but we accept and warn about one /// terminated by a semicolon. - - /// matches inner_attrs* + /// + /// Matches `inner_attrs*`. crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec> { let mut attrs: Vec = vec![]; loop { @@ -238,7 +229,7 @@ impl<'a> Parser<'a> { attrs.push(attr); } token::DocComment(s) => { - // we need to get the position of this token before we bump. + // We need to get the position of this token before we bump. let attr = attr::mk_sugared_doc_attr(s, self.token.span); if attr.style == ast::AttrStyle::Inner { attrs.push(attr); @@ -257,7 +248,7 @@ impl<'a> Parser<'a> { let lit = self.parse_lit()?; debug!("checking if {:?} is unusuffixed", lit); - if !lit.node.is_unsuffixed() { + if !lit.kind.is_unsuffixed() { let msg = "suffixed literals are not allowed in attributes"; self.diagnostic().struct_span_err(lit.span, msg) .help("instead of using a suffixed literal \ @@ -269,10 +260,10 @@ impl<'a> Parser<'a> { Ok(lit) } - /// Per RFC#1559, matches the following grammar: + /// Matches the following grammar (per RFC 1559). /// - /// meta_item : IDENT ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; - /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; + /// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; + /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { let nt_meta = match self.token.kind { token::Interpolated(ref nt) => match **nt { @@ -282,16 +273,21 @@ impl<'a> Parser<'a> { _ => None, }; - if let Some(meta) = nt_meta { - self.bump(); - return Ok(meta); + if let Some(item) = nt_meta { + return match item.meta(item.path.span) { + Some(meta) => { + self.bump(); + Ok(meta) + } + None => self.unexpected(), + } } let lo = self.token.span; let path = self.parse_path(PathStyle::Mod)?; - let node = self.parse_meta_item_kind()?; + let kind = self.parse_meta_item_kind()?; let span = lo.to(self.prev_span); - Ok(ast::MetaItem { path, node, span }) + Ok(ast::MetaItem { path, kind, span }) } crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { @@ -304,20 +300,20 @@ impl<'a> Parser<'a> { }) } - /// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ; + /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`. fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { match self.parse_unsuffixed_lit() { Ok(lit) => { return Ok(ast::NestedMetaItem::Literal(lit)) } - Err(ref mut err) => self.diagnostic().cancel(err) + Err(ref mut err) => err.cancel(), } match self.parse_meta_item() { Ok(mi) => { return Ok(ast::NestedMetaItem::MetaItem(mi)) } - Err(ref mut err) => self.diagnostic().cancel(err) + Err(ref mut err) => err.cancel(), } let found = self.this_token_to_string(); @@ -325,7 +321,7 @@ impl<'a> Parser<'a> { Err(self.diagnostic().struct_span_err(self.token.span, &msg)) } - /// matches meta_seq = ( COMMASEP(meta_item_inner) ) + /// Matches `meta_seq = ( COMMASEP(meta_item_inner) )`. fn parse_meta_seq(&mut self) -> PResult<'a, Vec> { self.parse_seq_to_end(&token::CloseDelim(token::Paren), SeqSep::trailing_allowed(token::Comma), diff --git a/src/libsyntax/parse/classify.rs b/src/libsyntax/parse/classify.rs index 6ebfab3a133ef..4456068875019 100644 --- a/src/libsyntax/parse/classify.rs +++ b/src/libsyntax/parse/classify.rs @@ -12,7 +12,7 @@ use crate::ast; /// |x| 5 /// isn't parsed as (if true {...} else {...} | x) | 5 pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool { - match e.node { + match e.kind { ast::ExprKind::If(..) | ast::ExprKind::Match(..) | ast::ExprKind::Block(..) | diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 730efb5ef013c..f376c19a66ccd 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -1,5 +1,5 @@ use crate::ast::{ - self, Arg, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind, + self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, VariantData, }; use crate::feature_gate::{feature_err, UnstableFeatures}; @@ -8,29 +8,36 @@ use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType, Token use crate::parse::token::{self, TokenKind}; use crate::print::pprust; use crate::ptr::P; -use crate::source_map::Spanned; use crate::symbol::{kw, sym}; use crate::ThinVec; use crate::util::parser::AssocOp; -use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use errors::{Applicability, DiagnosticBuilder, DiagnosticId, pluralise}; use rustc_data_structures::fx::FxHashSet; use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError}; use log::{debug, trace}; use std::mem; +const TURBOFISH: &'static str = "use `::<...>` instead of `<...>` to specify type arguments"; /// Creates a placeholder argument. -crate fn dummy_arg(ident: Ident) -> Arg { +crate fn dummy_arg(ident: Ident) -> Param { let pat = P(Pat { id: ast::DUMMY_NODE_ID, - node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None), + kind: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None), span: ident.span, }); let ty = Ty { - node: TyKind::Err, + kind: TyKind::Err, span: ident.span, id: ast::DUMMY_NODE_ID }; - Arg { attrs: ThinVec::default(), id: ast::DUMMY_NODE_ID, pat, span: ident.span, ty: P(ty) } + Param { + attrs: ThinVec::default(), + id: ast::DUMMY_NODE_ID, + pat, + span: ident.span, + ty: P(ty), + is_placeholder: false, + } } pub enum Error { @@ -129,7 +136,7 @@ impl RecoverQPath for Ty { fn recovered(qself: Option, path: ast::Path) -> Self { Self { span: path.span, - node: TyKind::Path(qself, path), + kind: TyKind::Path(qself, path), id: ast::DUMMY_NODE_ID, } } @@ -142,7 +149,7 @@ impl RecoverQPath for Pat { fn recovered(qself: Option, path: ast::Path) -> Self { Self { span: path.span, - node: PatKind::Path(qself, path), + kind: PatKind::Path(qself, path), id: ast::DUMMY_NODE_ID, } } @@ -155,7 +162,7 @@ impl RecoverQPath for Expr { fn recovered(qself: Option, path: ast::Path) -> Self { Self { span: path.span, - node: ExprKind::Path(qself, path), + kind: ExprKind::Path(qself, path), attrs: ThinVec::new(), id: ast::DUMMY_NODE_ID, } @@ -191,10 +198,6 @@ impl<'a> Parser<'a> { self.sess.span_diagnostic.span_bug(sp, m) } - crate fn cancel(&self, err: &mut DiagnosticBuilder<'_>) { - self.sess.span_diagnostic.cancel(err) - } - crate fn diagnostic(&self) -> &'a errors::Handler { &self.sess.span_diagnostic } @@ -241,7 +244,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, bool /* recovered */> { fn tokens_to_string(tokens: &[TokenType]) -> String { let mut i = tokens.iter(); - // This might be a sign we need a connect method on Iterator. + // This might be a sign we need a connect method on `Iterator`. let b = i.next() .map_or(String::new(), |t| t.to_string()); i.enumerate().fold(b, |mut b, (i, a)| { @@ -302,7 +305,7 @@ impl<'a> Parser<'a> { ); } let sp = if self.token == token::Eof { - // This is EOF, don't want to point at the following char, but rather the last token + // This is EOF; don't want to point at the following char, but rather the last token. self.prev_span } else { label_sp @@ -318,9 +321,9 @@ impl<'a> Parser<'a> { } let is_semi_suggestable = expected.iter().any(|t| match t { - TokenType::Token(token::Semi) => true, // we expect a `;` here + TokenType::Token(token::Semi) => true, // We expect a `;` here. _ => false, - }) && ( // a `;` would be expected before the current keyword + }) && ( // A `;` would be expected before the current keyword. self.token.is_keyword(kw::Break) || self.token.is_keyword(kw::Continue) || self.token.is_keyword(kw::For) || @@ -420,15 +423,13 @@ impl<'a> Parser<'a> { /// Eats and discards tokens until one of `kets` is encountered. Respects token trees, /// passes through any errors encountered. Used for error recovery. crate fn eat_to_tokens(&mut self, kets: &[&TokenKind]) { - let handler = self.diagnostic(); - if let Err(ref mut err) = self.parse_seq_to_before_tokens( kets, SeqSep::none(), TokenExpectType::Expect, |p| Ok(p.parse_token_tree()), ) { - handler.cancel(err); + err.cancel(); } } @@ -526,15 +527,15 @@ impl<'a> Parser<'a> { self.eat_to_tokens(&[&end]); let span = lo.until(self.token.span); - let plural = number_of_gt > 1 || number_of_shr >= 1; + let total_num_of_gt = number_of_gt + number_of_shr * 2; self.diagnostic() .struct_span_err( span, - &format!("unmatched angle bracket{}", if plural { "s" } else { "" }), + &format!("unmatched angle bracket{}", pluralise!(total_num_of_gt)), ) .span_suggestion( span, - &format!("remove extra angle bracket{}", if plural { "s" } else { "" }), + &format!("remove extra angle bracket{}", pluralise!(total_num_of_gt)), String::new(), Applicability::MachineApplicable, ) @@ -542,33 +543,155 @@ impl<'a> Parser<'a> { } } - /// Produce an error if comparison operators are chained (RFC #558). - /// We only need to check lhs, not rhs, because all comparison ops - /// have same precedence and are left-associative - crate fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) { - debug_assert!(outer_op.is_comparison(), - "check_no_chained_comparison: {:?} is not comparison", - outer_op); - match lhs.node { + /// Produces an error if comparison operators are chained (RFC #558). + /// We only need to check the LHS, not the RHS, because all comparison ops have same + /// precedence (see `fn precedence`) and are left-associative (see `fn fixity`). + /// + /// This can also be hit if someone incorrectly writes `foo()` when they should have used + /// the turbofish (`foo::()`) syntax. We attempt some heuristic recovery if that is the + /// case. + /// + /// Keep in mind that given that `outer_op.is_comparison()` holds and comparison ops are left + /// associative we can infer that we have: + /// + /// outer_op + /// / \ + /// inner_op r2 + /// / \ + /// l1 r1 + crate fn check_no_chained_comparison( + &mut self, + lhs: &Expr, + outer_op: &AssocOp, + ) -> PResult<'a, Option>> { + debug_assert!( + outer_op.is_comparison(), + "check_no_chained_comparison: {:?} is not comparison", + outer_op, + ); + + let mk_err_expr = |this: &Self, span| { + Ok(Some(this.mk_expr(span, ExprKind::Err, ThinVec::new()))) + }; + + match lhs.kind { ExprKind::Binary(op, _, _) if op.node.is_comparison() => { - // respan to include both operators - let op_span = op.span.to(self.token.span); + // Respan to include both operators. + let op_span = op.span.to(self.prev_span); let mut err = self.struct_span_err( op_span, "chained comparison operators require parentheses", ); + + let suggest = |err: &mut DiagnosticBuilder<'_>| { + err.span_suggestion_verbose( + op_span.shrink_to_lo(), + TURBOFISH, + "::".to_string(), + Applicability::MaybeIncorrect, + ); + }; + if op.node == BinOpKind::Lt && *outer_op == AssocOp::Less || // Include `<` to provide this recommendation *outer_op == AssocOp::Greater // even in a case like the following: { // Foo>> - err.help( - "use `::<...>` instead of `<...>` if you meant to specify type arguments"); - err.help("or use `(...)` if you meant to specify fn arguments"); + if *outer_op == AssocOp::Less { + let snapshot = self.clone(); + self.bump(); + // So far we have parsed `foo(` or `foo< bar >::`, so we rewind the + // parser and bail out. + mem::replace(self, snapshot.clone()); + } + } + return if token::ModSep == self.token.kind { + // We have some certainty that this was a bad turbofish at this point. + // `foo< bar >::` + suggest(&mut err); + + let snapshot = self.clone(); + self.bump(); // `::` + + // Consume the rest of the likely `foo::new()` or return at `foo`. + match self.parse_expr() { + Ok(_) => { + // 99% certain that the suggestion is correct, continue parsing. + err.emit(); + // FIXME: actually check that the two expressions in the binop are + // paths and resynthesize new fn call expression instead of using + // `ExprKind::Err` placeholder. + mk_err_expr(self, lhs.span.to(self.prev_span)) + } + Err(mut expr_err) => { + expr_err.cancel(); + // Not entirely sure now, but we bubble the error up with the + // suggestion. + mem::replace(self, snapshot); + Err(err) + } + } + } else if token::OpenDelim(token::Paren) == self.token.kind { + // We have high certainty that this was a bad turbofish at this point. + // `foo< bar >(` + suggest(&mut err); + // Consume the fn call arguments. + match self.consume_fn_args() { + Err(()) => Err(err), + Ok(()) => { + err.emit(); + // FIXME: actually check that the two expressions in the binop are + // paths and resynthesize new fn call expression instead of using + // `ExprKind::Err` placeholder. + mk_err_expr(self, lhs.span.to(self.prev_span)) + } + } + } else { + // All we know is that this is `foo < bar >` and *nothing* else. Try to + // be helpful, but don't attempt to recover. + err.help(TURBOFISH); + err.help("or use `(...)` if you meant to specify fn arguments"); + // These cases cause too many knock-down errors, bail out (#61329). + Err(err) + }; } err.emit(); } _ => {} } + Ok(None) + } + + fn consume_fn_args(&mut self) -> Result<(), ()> { + let snapshot = self.clone(); + self.bump(); // `(` + + // Consume the fn call arguments. + let modifiers = [ + (token::OpenDelim(token::Paren), 1), + (token::CloseDelim(token::Paren), -1), + ]; + self.consume_tts(1, &modifiers[..]); + + if self.token.kind == token::Eof { + // Not entirely sure that what we consumed were fn arguments, rollback. + mem::replace(self, snapshot); + Err(()) + } else { + // 99% certain that the suggestion is correct, continue parsing. + Ok(()) + } } crate fn maybe_report_ambiguous_plus( @@ -592,18 +715,18 @@ impl<'a> Parser<'a> { crate fn maybe_report_invalid_custom_discriminants( sess: &ParseSess, - variants: &[Spanned], + variants: &[ast::Variant], ) { - let has_fields = variants.iter().any(|variant| match variant.node.data { + let has_fields = variants.iter().any(|variant| match variant.data { VariantData::Tuple(..) | VariantData::Struct(..) => true, VariantData::Unit(..) => false, }); - let discriminant_spans = variants.iter().filter(|variant| match variant.node.data { + let discriminant_spans = variants.iter().filter(|variant| match variant.data { VariantData::Tuple(..) | VariantData::Struct(..) => false, VariantData::Unit(..) => true, }) - .filter_map(|variant| variant.node.disr_expr.as_ref().map(|c| c.value.span)) + .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span)) .collect::>(); if !discriminant_spans.is_empty() && has_fields { @@ -618,7 +741,7 @@ impl<'a> Parser<'a> { err.span_label(sp, "disallowed custom discriminant"); } for variant in variants.iter() { - match &variant.node.data { + match &variant.data { VariantData::Struct(..) => { err.span_label( variant.span, @@ -660,7 +783,7 @@ impl<'a> Parser<'a> { pprust::ty_to_string(ty) ); - match ty.node { + match ty.kind { TyKind::Rptr(ref lifetime, ref mut_ty) => { let sum_with_parens = pprust::to_string(|s| { s.s.word("&"); @@ -689,9 +812,9 @@ impl<'a> Parser<'a> { Ok(()) } - /// Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`. - /// Attempt to convert the base expression/pattern/type into a type, parse the `::AssocItem` - /// tail, and combine them into a `::AssocItem` expression/pattern/type. + /// Tries to recover from associated item paths like `[T]::AssocItem` / `(T, U)::AssocItem`. + /// Attempts to convert the base expression/pattern/type into a type, parses the `::AssocItem` + /// tail, and combines them into a `::AssocItem` expression/pattern/type. crate fn maybe_recover_from_bad_qpath( &mut self, base: P, @@ -706,8 +829,8 @@ impl<'a> Parser<'a> { Ok(base) } - /// Given an already parsed `Ty` parse the `::AssocItem` tail and - /// combine them into a `::AssocItem` expression/pattern/type. + /// Given an already parsed `Ty`, parses the `::AssocItem` tail and + /// combines them into a `::AssocItem` expression/pattern/type. crate fn maybe_recover_from_bad_qpath_stage_2( &mut self, ty_span: Span, @@ -728,7 +851,7 @@ impl<'a> Parser<'a> { self.diagnostic() .struct_span_err(path.span, "missing angle brackets in associated item path") .span_suggestion( - // this is a best-effort recovery + // This is a best-effort recovery. path.span, "try", format!("<{}>::{}", ty_str, path), @@ -736,7 +859,7 @@ impl<'a> Parser<'a> { ) .emit(); - let path_span = ty_span.shrink_to_hi(); // use an empty path since `position` == 0 + let path_span = ty_span.shrink_to_hi(); // Use an empty path since `position == 0`. Ok(P(T::recovered( Some(QSelf { ty, @@ -758,9 +881,9 @@ impl<'a> Parser<'a> { ); if !items.is_empty() { let previous_item = &items[items.len() - 1]; - let previous_item_kind_name = match previous_item.node { - // say "braced struct" because tuple-structs and - // braceless-empty-struct declarations do take a semicolon + let previous_item_kind_name = match previous_item.kind { + // Say "braced struct" because tuple-structs and + // braceless-empty-struct declarations do take a semicolon. ItemKind::Struct(..) => Some("braced struct"), ItemKind::Enum(..) => Some("enum"), ItemKind::Trait(..) => Some("trait"), @@ -781,7 +904,7 @@ impl<'a> Parser<'a> { } } - /// Create a `DiagnosticBuilder` for an unexpected token `t` and try to recover if it is a + /// Creates a `DiagnosticBuilder` for an unexpected token `t` and tries to recover if it is a /// closing delimiter. pub fn unexpected_try_recover( &mut self, @@ -839,7 +962,7 @@ impl<'a> Parser<'a> { extern_sp: Span, ) -> PResult<'a, ()> { if self.token != token::Semi { - // this might be an incorrect fn definition (#62109) + // This might be an incorrect fn definition (#62109). let parser_snapshot = self.clone(); match self.parse_inner_attrs_and_block() { Ok((_, body)) => { @@ -869,7 +992,7 @@ impl<'a> Parser<'a> { Ok(()) } - /// Consume alternative await syntaxes like `await!()`, `await `, + /// Consumes alternative await syntaxes like `await!()`, `await `, /// `await? `, `await()`, and `await { }`. crate fn parse_incorrect_await_syntax( &mut self, @@ -912,7 +1035,7 @@ impl<'a> Parser<'a> { .unwrap_or_else(|_| pprust::expr_to_string(&expr)); let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" }); let sp = lo.to(hi); - let app = match expr.node { + let app = match expr.kind { ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await ?` _ => Applicability::MachineApplicable, }; @@ -922,7 +1045,7 @@ impl<'a> Parser<'a> { sp } - /// If encountering `future.await()`, consume and emit error. + /// If encountering `future.await()`, consumes and emits an error. crate fn recover_from_await_method_call(&mut self) { if self.token == token::OpenDelim(token::Paren) && self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren)) @@ -942,7 +1065,7 @@ impl<'a> Parser<'a> { } } - /// Recover a situation like `for ( $pat in $expr )` + /// Recovers a situation like `for ( $pat in $expr )` /// and suggest writing `for $pat in $expr` instead. /// /// This should be called before parsing the `$block`. @@ -975,7 +1098,7 @@ impl<'a> Parser<'a> { .emit(); // Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint. - pat.and_then(|pat| match pat.node { + pat.and_then(|pat| match pat.kind { PatKind::Paren(pat) => pat, _ => P(pat), }) @@ -1008,7 +1131,7 @@ impl<'a> Parser<'a> { Ok(x) => x, Err(mut err) => { err.emit(); - // recover from parse error + // Recover from parse error. self.consume_block(delim); self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new()) } @@ -1021,7 +1144,7 @@ impl<'a> Parser<'a> { mut err: DiagnosticBuilder<'a>, ) -> PResult<'a, bool> { let mut pos = None; - // we want to use the last closing delim that would apply + // We want to use the last closing delim that would apply. for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() { if tokens.contains(&token::CloseDelim(unmatched.expected_delim)) && Some(self.token.span) > unmatched.unclosed_span @@ -1039,7 +1162,7 @@ impl<'a> Parser<'a> { let unmatched = self.unclosed_delims.remove(pos); let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim)); - // We want to suggest the inclusion of the closing delimiter where it makes + // We want to suggest the inclusion of the closing delimiter where it makes // the most sense, which is immediately after the last token: // // {foo(bar {}} @@ -1065,7 +1188,7 @@ impl<'a> Parser<'a> { } } - /// Recover from `pub` keyword in places where it seems _reasonable_ but isn't valid. + /// Recovers from `pub` keyword in places where it seems _reasonable_ but isn't valid. crate fn eat_bad_pub(&mut self) { if self.token.is_keyword(kw::Pub) { match self.parse_visibility(false) { @@ -1080,21 +1203,21 @@ impl<'a> Parser<'a> { } } - // Eat tokens until we can be relatively sure we reached the end of the - // statement. This is something of a best-effort heuristic. - // - // We terminate when we find an unmatched `}` (without consuming it). + /// Eats tokens until we can be relatively sure we reached the end of the + /// statement. This is something of a best-effort heuristic. + /// + /// We terminate when we find an unmatched `}` (without consuming it). crate fn recover_stmt(&mut self) { self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore) } - // If `break_on_semi` is `Break`, then we will stop consuming tokens after - // finding (and consuming) a `;` outside of `{}` or `[]` (note that this is - // approximate - it can mean we break too early due to macros, but that - // should only lead to sub-optimal recovery, not inaccurate parsing). - // - // If `break_on_block` is `Break`, then we will stop consuming tokens - // after finding (and consuming) a brace-delimited block. + /// If `break_on_semi` is `Break`, then we will stop consuming tokens after + /// finding (and consuming) a `;` outside of `{}` or `[]` (note that this is + /// approximate -- it can mean we break too early due to macros, but that + /// should only lead to sub-optimal recovery, not inaccurate parsing). + /// + /// If `break_on_block` is `Break`, then we will stop consuming tokens + /// after finding (and consuming) a brace-delimited block. crate fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) { let mut brace_depth = 0; let mut bracket_depth = 0; @@ -1177,14 +1300,14 @@ impl<'a> Parser<'a> { } } - crate fn expected_semi_or_open_brace(&mut self) -> PResult<'a, ast::TraitItem> { + crate fn expected_semi_or_open_brace(&mut self) -> PResult<'a, T> { let token_str = self.this_token_descr(); let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", token_str)); err.span_label(self.token.span, "expected `;` or `{`"); Err(err) } - crate fn eat_incorrect_doc_comment_for_arg_type(&mut self) { + crate fn eat_incorrect_doc_comment_for_param_type(&mut self) { if let token::DocComment(_) = self.token.kind { self.struct_span_err( self.token.span, @@ -1212,11 +1335,12 @@ impl<'a> Parser<'a> { } } - crate fn argument_without_type( + crate fn parameter_without_type( &mut self, err: &mut DiagnosticBuilder<'_>, pat: P, require_name: bool, + is_self_allowed: bool, is_trait_item: bool, ) -> Option { // If we find a pattern followed by an identifier, it could be an (incorrect) @@ -1234,18 +1358,31 @@ impl<'a> Parser<'a> { Applicability::HasPlaceholders, ); return Some(ident); - } else if let PatKind::Ident(_, ident, _) = pat.node { + } else if let PatKind::Ident(_, ident, _) = pat.kind { if require_name && ( is_trait_item || self.token == token::Comma || + self.token == token::Lt || self.token == token::CloseDelim(token::Paren) - ) { // `fn foo(a, b) {}` or `fn foo(usize, usize) {}` - err.span_suggestion( - pat.span, - "if this was a parameter name, give it a type", - format!("{}: TypeName", ident), - Applicability::HasPlaceholders, - ); + ) { // `fn foo(a, b) {}`, `fn foo(a, b) {}` or `fn foo(usize, usize) {}` + if is_self_allowed { + err.span_suggestion( + pat.span, + "if this is a `self` type, give it a parameter name", + format!("self: {}", ident), + Applicability::MaybeIncorrect, + ); + } + // Avoid suggesting that `fn foo(HashMap)` is fixed with a change to + // `fn foo(HashMap: TypeName)`. + if self.token != token::Lt { + err.span_suggestion( + pat.span, + "if this was a parameter name, give it a type", + format!("{}: TypeName", ident), + Applicability::HasPlaceholders, + ); + } err.span_suggestion( pat.span, "if this is a type, explicitly ignore the parameter name", @@ -1253,7 +1390,9 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ); err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)"); - return Some(ident); + + // Don't attempt to recover by using the `X` in `X` as the parameter name. + return if self.token == token::Lt { None } else { Some(ident) }; } } None @@ -1280,20 +1419,20 @@ impl<'a> Parser<'a> { // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. let pat = P(Pat { - node: PatKind::Wild, + kind: PatKind::Wild, span: pat.span, id: ast::DUMMY_NODE_ID }); Ok((pat, ty)) } - crate fn recover_bad_self_arg( + crate fn recover_bad_self_param( &mut self, - mut arg: ast::Arg, + mut param: ast::Param, is_trait_item: bool, - ) -> PResult<'a, ast::Arg> { - let sp = arg.pat.span; - arg.ty.node = TyKind::Err; + ) -> PResult<'a, ast::Param> { + let sp = param.pat.span; + param.ty.kind = TyKind::Err; let mut err = self.struct_span_err(sp, "unexpected `self` parameter in function"); if is_trait_item { err.span_label(sp, "must be the first associated function parameter"); @@ -1302,7 +1441,7 @@ impl<'a> Parser<'a> { err.note("`self` is only valid as the first parameter of an associated function"); } err.emit(); - Ok(arg) + Ok(param) } crate fn consume_block(&mut self, delim: token::DelimToken) { @@ -1345,19 +1484,36 @@ impl<'a> Parser<'a> { err } - /// Replace duplicated recovered arguments with `_` pattern to avoid unecessary errors. + fn consume_tts( + &mut self, + mut acc: i64, // `i64` because malformed code can have more closing delims than opening. + // Not using `FxHashMap` due to `token::TokenKind: !Eq + !Hash`. + modifier: &[(token::TokenKind, i64)], + ) { + while acc > 0 { + if let Some((_, val)) = modifier.iter().find(|(t, _)| *t == self.token.kind) { + acc += *val; + } + if self.token.kind == token::Eof { + break; + } + self.bump(); + } + } + + /// Replace duplicated recovered parameters with `_` pattern to avoid unecessary errors. /// /// This is necessary because at this point we don't know whether we parsed a function with - /// anonymous arguments or a function with names but no types. In order to minimize - /// unecessary errors, we assume the arguments are in the shape of `fn foo(a, b, c)` where - /// the arguments are *names* (so we don't emit errors about not being able to find `b` in + /// anonymous parameters or a function with names but no types. In order to minimize + /// unecessary errors, we assume the parameters are in the shape of `fn foo(a, b, c)` where + /// the parameters are *names* (so we don't emit errors about not being able to find `b` in /// the local scope), but if we find the same name multiple times, like in `fn foo(i8, i8)`, - /// we deduplicate them to not complain about duplicated argument names. - crate fn deduplicate_recovered_arg_names(&self, fn_inputs: &mut Vec) { + /// we deduplicate them to not complain about duplicated parameter names. + crate fn deduplicate_recovered_params_names(&self, fn_inputs: &mut Vec) { let mut seen_inputs = FxHashSet::default(); for input in fn_inputs.iter_mut() { let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err) = ( - &input.pat.node, &input.ty.node, + &input.pat.kind, &input.ty.kind, ) { Some(*ident) } else { @@ -1365,7 +1521,7 @@ impl<'a> Parser<'a> { }; if let Some(ident) = opt_ident { if seen_inputs.contains(&ident) { - input.pat.node = PatKind::Wild; + input.pat.kind = PatKind::Wild; } seen_inputs.insert(ident); } diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index e86d4c7fde683..ac3feadce3ae6 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -4,13 +4,11 @@ use crate::symbol::{sym, Symbol}; use crate::parse::unescape_error_reporting::{emit_unescape_error, push_escaped_char}; use errors::{FatalError, DiagnosticBuilder}; -use syntax_pos::{BytePos, Pos, Span, NO_EXPANSION}; +use syntax_pos::{BytePos, Pos, Span}; use rustc_lexer::Base; use rustc_lexer::unescape; -use std::borrow::Cow; use std::char; -use std::iter; use std::convert::TryInto; use rustc_data_structures::sync::Lrc; use log::debug; @@ -49,7 +47,7 @@ impl<'a> StringReader<'a> { source_file: Lrc, override_span: Option) -> Self { if source_file.src.is_none() { - sess.span_diagnostic.bug(&format!("Cannot lex source_file without source: {}", + sess.span_diagnostic.bug(&format!("cannot lex `source_file` without source: {}", source_file.name)); } @@ -84,7 +82,7 @@ impl<'a> StringReader<'a> { fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span { - self.override_span.unwrap_or_else(|| Span::new(lo, hi, NO_EXPANSION)) + self.override_span.unwrap_or_else(|| Span::with_root_ctxt(lo, hi)) } /// Returns the next token, including trivia like whitespace or comments. @@ -181,18 +179,7 @@ impl<'a> StringReader<'a> { let string = self.str_from(start); // comments with only more "/"s are not doc comments let tok = if is_doc_comment(string) { - let mut idx = 0; - loop { - idx = match string[idx..].find('\r') { - None => break, - Some(it) => idx + it + 1 - }; - if string[idx..].chars().next() != Some('\n') { - self.err_span_(start + BytePos(idx as u32 - 1), - start + BytePos(idx as u32), - "bare CR not allowed in doc-comment"); - } - } + self.forbid_bare_cr(start, string, "bare CR not allowed in doc-comment"); token::DocComment(Symbol::intern(string)) } else { token::Comment @@ -217,15 +204,10 @@ impl<'a> StringReader<'a> { } let tok = if is_doc_comment { - let has_cr = string.contains('\r'); - let string = if has_cr { - self.translate_crlf(start, - string, - "bare CR not allowed in block doc-comment") - } else { - string.into() - }; - token::DocComment(Symbol::intern(&string[..])) + self.forbid_bare_cr(start, + string, + "bare CR not allowed in block doc-comment"); + token::DocComment(Symbol::intern(string)) } else { token::Comment }; @@ -291,9 +273,6 @@ impl<'a> StringReader<'a> { } rustc_lexer::TokenKind::Semi => token::Semi, rustc_lexer::TokenKind::Comma => token::Comma, - rustc_lexer::TokenKind::DotDotDot => token::DotDotDot, - rustc_lexer::TokenKind::DotDotEq => token::DotDotEq, - rustc_lexer::TokenKind::DotDot => token::DotDot, rustc_lexer::TokenKind::Dot => token::Dot, rustc_lexer::TokenKind::OpenParen => token::OpenDelim(token::Paren), rustc_lexer::TokenKind::CloseParen => token::CloseDelim(token::Paren), @@ -305,42 +284,20 @@ impl<'a> StringReader<'a> { rustc_lexer::TokenKind::Pound => token::Pound, rustc_lexer::TokenKind::Tilde => token::Tilde, rustc_lexer::TokenKind::Question => token::Question, - rustc_lexer::TokenKind::ColonColon => token::ModSep, rustc_lexer::TokenKind::Colon => token::Colon, rustc_lexer::TokenKind::Dollar => token::Dollar, - rustc_lexer::TokenKind::EqEq => token::EqEq, rustc_lexer::TokenKind::Eq => token::Eq, - rustc_lexer::TokenKind::FatArrow => token::FatArrow, - rustc_lexer::TokenKind::Ne => token::Ne, rustc_lexer::TokenKind::Not => token::Not, - rustc_lexer::TokenKind::Le => token::Le, - rustc_lexer::TokenKind::LArrow => token::LArrow, rustc_lexer::TokenKind::Lt => token::Lt, - rustc_lexer::TokenKind::ShlEq => token::BinOpEq(token::Shl), - rustc_lexer::TokenKind::Shl => token::BinOp(token::Shl), - rustc_lexer::TokenKind::Ge => token::Ge, rustc_lexer::TokenKind::Gt => token::Gt, - rustc_lexer::TokenKind::ShrEq => token::BinOpEq(token::Shr), - rustc_lexer::TokenKind::Shr => token::BinOp(token::Shr), - rustc_lexer::TokenKind::RArrow => token::RArrow, rustc_lexer::TokenKind::Minus => token::BinOp(token::Minus), - rustc_lexer::TokenKind::MinusEq => token::BinOpEq(token::Minus), rustc_lexer::TokenKind::And => token::BinOp(token::And), - rustc_lexer::TokenKind::AndEq => token::BinOpEq(token::And), - rustc_lexer::TokenKind::AndAnd => token::AndAnd, rustc_lexer::TokenKind::Or => token::BinOp(token::Or), - rustc_lexer::TokenKind::OrEq => token::BinOpEq(token::Or), - rustc_lexer::TokenKind::OrOr => token::OrOr, rustc_lexer::TokenKind::Plus => token::BinOp(token::Plus), - rustc_lexer::TokenKind::PlusEq => token::BinOpEq(token::Plus), rustc_lexer::TokenKind::Star => token::BinOp(token::Star), - rustc_lexer::TokenKind::StarEq => token::BinOpEq(token::Star), rustc_lexer::TokenKind::Slash => token::BinOp(token::Slash), - rustc_lexer::TokenKind::SlashEq => token::BinOpEq(token::Slash), rustc_lexer::TokenKind::Caret => token::BinOp(token::Caret), - rustc_lexer::TokenKind::CaretEq => token::BinOpEq(token::Caret), rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent), - rustc_lexer::TokenKind::PercentEq => token::BinOpEq(token::Percent), rustc_lexer::TokenKind::Unknown => { let c = self.str_from(start).chars().next().unwrap(); @@ -516,49 +473,16 @@ impl<'a> StringReader<'a> { &self.src[self.src_index(start)..self.src_index(end)] } - /// Converts CRLF to LF in the given string, raising an error on bare CR. - fn translate_crlf<'b>(&self, start: BytePos, s: &'b str, errmsg: &'b str) -> Cow<'b, str> { - let mut chars = s.char_indices().peekable(); - while let Some((i, ch)) = chars.next() { - if ch == '\r' { - if let Some((lf_idx, '\n')) = chars.peek() { - return translate_crlf_(self, start, s, *lf_idx, chars, errmsg).into(); - } - let pos = start + BytePos(i as u32); - let end_pos = start + BytePos((i + ch.len_utf8()) as u32); - self.err_span_(pos, end_pos, errmsg); - } - } - return s.into(); - - fn translate_crlf_(rdr: &StringReader<'_>, - start: BytePos, - s: &str, - mut j: usize, - mut chars: iter::Peekable>, - errmsg: &str) - -> String { - let mut buf = String::with_capacity(s.len()); - // Skip first CR - buf.push_str(&s[.. j - 1]); - while let Some((i, ch)) = chars.next() { - if ch == '\r' { - if j < i { - buf.push_str(&s[j..i]); - } - let next = i + ch.len_utf8(); - j = next; - if chars.peek().map(|(_, ch)| *ch) != Some('\n') { - let pos = start + BytePos(i as u32); - let end_pos = start + BytePos(next as u32); - rdr.err_span_(pos, end_pos, errmsg); - } - } - } - if j < s.len() { - buf.push_str(&s[j..]); - } - buf + fn forbid_bare_cr(&self, start: BytePos, s: &str, errmsg: &str) { + let mut idx = 0; + loop { + idx = match s[idx..].find('\r') { + None => break, + Some(it) => idx + it + 1 + }; + self.err_span_(start + BytePos(idx as u32 - 1), + start + BytePos(idx as u32), + errmsg); } } diff --git a/src/libsyntax/parse/lexer/tests.rs b/src/libsyntax/parse/lexer/tests.rs index fc47e4f0b185a..de301b1fc499d 100644 --- a/src/libsyntax/parse/lexer/tests.rs +++ b/src/libsyntax/parse/lexer/tests.rs @@ -1,44 +1,29 @@ use super::*; -use crate::ast::CrateConfig; use crate::symbol::Symbol; use crate::source_map::{SourceMap, FilePathMapping}; -use crate::feature_gate::UnstableFeatures; use crate::parse::token; -use crate::diagnostics::plugin::ErrorMap; use crate::with_default_globals; + +use errors::{Handler, emitter::EmitterWriter}; use std::io; use std::path::PathBuf; -use syntax_pos::{BytePos, Span, NO_EXPANSION, edition::Edition}; -use rustc_data_structures::fx::{FxHashSet, FxHashMap}; -use rustc_data_structures::sync::{Lock, Once}; +use syntax_pos::{BytePos, Span}; fn mk_sess(sm: Lrc) -> ParseSess { - let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()), - Some(sm.clone()), - false, - false, - false); - ParseSess { - span_diagnostic: errors::Handler::with_emitter(true, None, Box::new(emitter)), - unstable_features: UnstableFeatures::from_environment(), - config: CrateConfig::default(), - included_mod_stack: Lock::new(Vec::new()), - source_map: sm, - missing_fragment_specifiers: Lock::new(FxHashSet::default()), - raw_identifier_spans: Lock::new(Vec::new()), - registered_diagnostics: Lock::new(ErrorMap::new()), - buffered_lints: Lock::new(vec![]), - edition: Edition::from_session(), - ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), - param_attr_spans: Lock::new(Vec::new()), - let_chains_spans: Lock::new(Vec::new()), - async_closure_spans: Lock::new(Vec::new()), - injected_crate_name: Once::new(), - } + let emitter = EmitterWriter::new( + Box::new(io::sink()), + Some(sm.clone()), + false, + false, + false, + None, + false, + ); + ParseSess::with_span_handler(Handler::with_emitter(true, None, Box::new(emitter)), sm) } -// open a string reader for the given string +// Creates a string reader for the given string. fn setup<'a>(sm: &SourceMap, sess: &'a ParseSess, teststr: String) @@ -52,26 +37,27 @@ fn t1() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - let mut string_reader = setup(&sm, - &sh, - "/* my source file */ fn main() { println!(\"zebra\"); }\n" - .to_string()); + let mut string_reader = setup( + &sm, + &sh, + "/* my source file */ fn main() { println!(\"zebra\"); }\n".to_string(), + ); assert_eq!(string_reader.next_token(), token::Comment); assert_eq!(string_reader.next_token(), token::Whitespace); let tok1 = string_reader.next_token(); let tok2 = Token::new( mk_ident("fn"), - Span::new(BytePos(21), BytePos(23), NO_EXPANSION), + Span::with_root_ctxt(BytePos(21), BytePos(23)), ); assert_eq!(tok1.kind, tok2.kind); assert_eq!(tok1.span, tok2.span); assert_eq!(string_reader.next_token(), token::Whitespace); - // read another token: + // Read another token. let tok3 = string_reader.next_token(); assert_eq!(string_reader.pos.clone(), BytePos(28)); let tok4 = Token::new( mk_ident("main"), - Span::new(BytePos(24), BytePos(28), NO_EXPANSION), + Span::with_root_ctxt(BytePos(24), BytePos(28)), ); assert_eq!(tok3.kind, tok4.kind); assert_eq!(tok3.span, tok4.span); @@ -81,15 +67,15 @@ fn t1() { }) } -// check that the given reader produces the desired stream -// of tokens (stop checking after exhausting the expected vec) +// Checks that the given reader produces the desired stream +// of tokens (stop checking after exhausting `expected`). fn check_tokenization(mut string_reader: StringReader<'_>, expected: Vec) { for expected_tok in &expected { assert_eq!(&string_reader.next_token(), expected_tok); } } -// make the identifier by looking up the string in the interner +// Makes the identifier by looking up the string in the interner. fn mk_ident(id: &str) -> TokenKind { token::Ident(Symbol::intern(id), false) } @@ -99,42 +85,50 @@ fn mk_lit(kind: token::LitKind, symbol: &str, suffix: Option<&str>) -> TokenKind } #[test] -fn doublecolonparsing() { +fn doublecolon_parsing() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - check_tokenization(setup(&sm, &sh, "a b".to_string()), - vec![mk_ident("a"), token::Whitespace, mk_ident("b")]); + check_tokenization( + setup(&sm, &sh, "a b".to_string()), + vec![mk_ident("a"), token::Whitespace, mk_ident("b")], + ); }) } #[test] -fn dcparsing_2() { +fn doublecolon_parsing_2() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - check_tokenization(setup(&sm, &sh, "a::b".to_string()), - vec![mk_ident("a"), token::ModSep, mk_ident("b")]); + check_tokenization( + setup(&sm, &sh, "a::b".to_string()), + vec![mk_ident("a"), token::Colon, token::Colon, mk_ident("b")], + ); }) } #[test] -fn dcparsing_3() { +fn doublecolon_parsing_3() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - check_tokenization(setup(&sm, &sh, "a ::b".to_string()), - vec![mk_ident("a"), token::Whitespace, token::ModSep, mk_ident("b")]); + check_tokenization( + setup(&sm, &sh, "a ::b".to_string()), + vec![mk_ident("a"), token::Whitespace, token::Colon, token::Colon, mk_ident("b")], + ); }) } #[test] -fn dcparsing_4() { +fn doublecolon_parsing_4() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - check_tokenization(setup(&sm, &sh, "a:: b".to_string()), - vec![mk_ident("a"), token::ModSep, token::Whitespace, mk_ident("b")]); + check_tokenization( + setup(&sm, &sh, "a:: b".to_string()), + vec![mk_ident("a"), token::Colon, token::Colon, token::Whitespace, mk_ident("b")], + ); }) } @@ -143,8 +137,10 @@ fn character_a() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'a'".to_string()).next_token(), - mk_lit(token::Char, "a", None)); + assert_eq!( + setup(&sm, &sh, "'a'".to_string()).next_token(), + mk_lit(token::Char, "a", None), + ); }) } @@ -153,8 +149,10 @@ fn character_space() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "' '".to_string()).next_token(), - mk_lit(token::Char, " ", None)); + assert_eq!( + setup(&sm, &sh, "' '".to_string()).next_token(), + mk_lit(token::Char, " ", None), + ); }) } @@ -163,8 +161,10 @@ fn character_escaped() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'\\n'".to_string()).next_token(), - mk_lit(token::Char, "\\n", None)); + assert_eq!( + setup(&sm, &sh, "'\\n'".to_string()).next_token(), + mk_lit(token::Char, "\\n", None), + ); }) } @@ -173,8 +173,10 @@ fn lifetime_name() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'abc".to_string()).next_token(), - token::Lifetime(Symbol::intern("'abc"))); + assert_eq!( + setup(&sm, &sh, "'abc".to_string()).next_token(), + token::Lifetime(Symbol::intern("'abc")), + ); }) } @@ -183,8 +185,10 @@ fn raw_string() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token(), - mk_lit(token::StrRaw(3), "\"#a\\b\x00c\"", None)); + assert_eq!( + setup(&sm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token(), + mk_lit(token::StrRaw(3), "\"#a\\b\x00c\"", None), + ); }) } @@ -195,11 +199,15 @@ fn literal_suffixes() { let sh = mk_sess(sm.clone()); macro_rules! test { ($input: expr, $tok_type: ident, $tok_contents: expr) => {{ - assert_eq!(setup(&sm, &sh, format!("{}suffix", $input)).next_token(), - mk_lit(token::$tok_type, $tok_contents, Some("suffix"))); - // with a whitespace separator: - assert_eq!(setup(&sm, &sh, format!("{} suffix", $input)).next_token(), - mk_lit(token::$tok_type, $tok_contents, None)); + assert_eq!( + setup(&sm, &sh, format!("{}suffix", $input)).next_token(), + mk_lit(token::$tok_type, $tok_contents, Some("suffix")), + ); + // with a whitespace separator + assert_eq!( + setup(&sm, &sh, format!("{} suffix", $input)).next_token(), + mk_lit(token::$tok_type, $tok_contents, None), + ); }} } @@ -213,12 +221,18 @@ fn literal_suffixes() { test!("1.0", Float, "1.0"); test!("1.0e10", Float, "1.0e10"); - assert_eq!(setup(&sm, &sh, "2us".to_string()).next_token(), - mk_lit(token::Integer, "2", Some("us"))); - assert_eq!(setup(&sm, &sh, "r###\"raw\"###suffix".to_string()).next_token(), - mk_lit(token::StrRaw(3), "raw", Some("suffix"))); - assert_eq!(setup(&sm, &sh, "br###\"raw\"###suffix".to_string()).next_token(), - mk_lit(token::ByteStrRaw(3), "raw", Some("suffix"))); + assert_eq!( + setup(&sm, &sh, "2us".to_string()).next_token(), + mk_lit(token::Integer, "2", Some("us")), + ); + assert_eq!( + setup(&sm, &sh, "r###\"raw\"###suffix".to_string()).next_token(), + mk_lit(token::StrRaw(3), "raw", Some("suffix")), + ); + assert_eq!( + setup(&sm, &sh, "br###\"raw\"###suffix".to_string()).next_token(), + mk_lit(token::ByteStrRaw(3), "raw", Some("suffix")), + ); }) } diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index 37e67a2729e6d..e5ba7e45309dd 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -39,29 +39,29 @@ struct TokenTreesReader<'a> { impl<'a> TokenTreesReader<'a> { // Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`. fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> { - let mut tts = Vec::new(); + let mut buf = TokenStreamBuilder::default(); self.real_token(); while self.token != token::Eof { - tts.push(self.parse_token_tree()?); + buf.push(self.parse_token_tree()?); } - Ok(TokenStream::new(tts)) + Ok(buf.into_token_stream()) } // Parse a stream of tokens into a list of `TokenTree`s, up to a `CloseDelim`. fn parse_token_trees_until_close_delim(&mut self) -> TokenStream { - let mut tts = vec![]; + let mut buf = TokenStreamBuilder::default(); loop { if let token::CloseDelim(..) = self.token.kind { - return TokenStream::new(tts); + return buf.into_token_stream(); } match self.parse_token_tree() { - Ok(tree) => tts.push(tree), + Ok(tree) => buf.push(tree), Err(mut e) => { e.emit(); - return TokenStream::new(tts); + return buf.into_token_stream(); } } } @@ -223,8 +223,32 @@ impl<'a> TokenTreesReader<'a> { _ => { self.token = token; return; - }, + } + } + } + } +} + +#[derive(Default)] +struct TokenStreamBuilder { + buf: Vec, +} + +impl TokenStreamBuilder { + fn push(&mut self, (tree, joint): TreeAndJoint) { + if let Some((TokenTree::Token(prev_token), Joint)) = self.buf.last() { + if let TokenTree::Token(token) = &tree { + if let Some(glued) = prev_token.glue(token) { + self.buf.pop(); + self.buf.push((TokenTree::Token(glued), joint)); + return; + } } } + self.buf.push((tree, joint)) + } + + fn into_token_stream(self) -> TokenStream { + TokenStream::new(self.buf) } } diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs index eaa736c6a3517..525b4215affb1 100644 --- a/src/libsyntax/parse/lexer/unicode_chars.rs +++ b/src/libsyntax/parse/lexer/unicode_chars.rs @@ -3,7 +3,7 @@ use super::StringReader; use errors::{Applicability, DiagnosticBuilder}; -use syntax_pos::{BytePos, Pos, Span, NO_EXPANSION, symbol::kw}; +use syntax_pos::{BytePos, Pos, Span, symbol::kw}; use crate::parse::token; #[rustfmt::skip] // for line breaks @@ -343,7 +343,7 @@ crate fn check_for_substitution<'a>( None => return None, }; - let span = Span::new(pos, pos + Pos::from_usize(ch.len_utf8()), NO_EXPANSION); + let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8())); let (ascii_name, token) = match ASCII_ARRAY.iter().find(|&&(c, _, _)| c == ascii_char) { Some((_ascii_char, ascii_name, token)) => (ascii_name, token), @@ -362,10 +362,9 @@ crate fn check_for_substitution<'a>( ascii_char, ascii_name ); err.span_suggestion( - Span::new( + Span::with_root_ctxt( pos, pos + Pos::from_usize('“'.len_utf8() + s.len() + '”'.len_utf8()), - NO_EXPANSION, ), &msg, format!("\"{}\"", s), diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs index 6409acba573ad..fcd5b2782fd61 100644 --- a/src/libsyntax/parse/literal.rs +++ b/src/libsyntax/parse/literal.rs @@ -104,7 +104,7 @@ impl LitKind { Ok(match kind { token::Bool => { - assert!(symbol == kw::True || symbol == kw::False); + assert!(symbol.is_bool_lit()); LitKind::Bool(symbol == kw::True) } token::Byte => return unescape_byte(&symbol.as_str()) @@ -255,19 +255,19 @@ impl LitKind { impl Lit { /// Converts literal token into an AST literal. fn from_lit_token(token: token::Lit, span: Span) -> Result { - Ok(Lit { token, node: LitKind::from_lit_token(token)?, span }) + Ok(Lit { token, kind: LitKind::from_lit_token(token)?, span }) } /// Converts arbitrary token into an AST literal. crate fn from_token(token: &Token) -> Result { let lit = match token.kind { - token::Ident(name, false) if name == kw::True || name == kw::False => + token::Ident(name, false) if name.is_bool_lit() => token::Lit::new(token::Bool, name, None), token::Literal(lit) => lit, token::Interpolated(ref nt) => { if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt { - if let ast::ExprKind::Lit(lit) = &expr.node { + if let ast::ExprKind::Lit(lit) = &expr.kind { return Ok(lit.clone()); } } @@ -282,8 +282,8 @@ impl Lit { /// Attempts to recover an AST literal from semantic literal. /// This function is used when the original token doesn't exist (e.g. the literal is created /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing). - pub fn from_lit_kind(node: LitKind, span: Span) -> Lit { - Lit { token: node.to_lit_token(), node, span } + pub fn from_lit_kind(kind: LitKind, span: Span) -> Lit { + Lit { token: kind.to_lit_token(), kind, span } } /// Losslessly convert an AST literal into a token stream. diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 80aa7a35266eb..1518da23b096f 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -8,16 +8,18 @@ use crate::parse::parser::Parser; use crate::parse::parser::emit_unclosed_delims; use crate::parse::token::TokenKind; use crate::tokenstream::{TokenStream, TokenTree}; -use crate::diagnostics::plugin::ErrorMap; use crate::print::pprust; use crate::symbol::Symbol; use errors::{Applicability, FatalError, Level, Handler, ColorConfig, Diagnostic, DiagnosticBuilder}; +use rustc_data_structures::fx::{FxHashSet, FxHashMap}; +#[cfg(target_arch = "x86_64")] +use rustc_data_structures::static_assert_size; use rustc_data_structures::sync::{Lrc, Lock, Once}; use syntax_pos::{Span, SourceFile, FileName, MultiSpan}; use syntax_pos::edition::Edition; +use syntax_pos::hygiene::ExpnId; -use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use std::borrow::Cow; use std::path::{Path, PathBuf}; use std::str; @@ -38,6 +40,27 @@ crate mod unescape_error_reporting; pub type PResult<'a, T> = Result>; +// `PResult` is used a lot. Make sure it doesn't unintentionally get bigger. +// (See also the comment on `DiagnosticBuilderInner`.) +#[cfg(target_arch = "x86_64")] +static_assert_size!(PResult<'_, bool>, 16); + +/// Collected spans during parsing for places where a certain feature was +/// used and should be feature gated accordingly in `check_crate`. +#[derive(Default)] +pub struct GatedSpans { + /// Spans collected for gating `let_chains`, e.g. `if a && let b = c {}`. + pub let_chains: Lock>, + /// Spans collected for gating `async_closure`, e.g. `async || ..`. + pub async_closure: Lock>, + /// Spans collected for gating `yield e?` expressions (`generators` gate). + pub yields: Lock>, + /// Spans collected for gating `or_patterns`, e.g. `Some(Foo | Bar)`. + pub or_patterns: Lock>, + /// Spans collected for gating `const_extern_fn`, e.g. `const extern fn foo`. + pub const_extern_fn: Lock>, +} + /// Info about a parsing session. pub struct ParseSess { pub span_diagnostic: Handler, @@ -47,8 +70,6 @@ pub struct ParseSess { pub missing_fragment_specifiers: Lock>, /// Places where raw identifiers were used. This is used for feature-gating raw identifiers. pub raw_identifier_spans: Lock>, - /// The registered diagnostics codes. - crate registered_diagnostics: Lock, /// Used to determine and report recursive module inclusions. included_mod_stack: Lock>, source_map: Lrc, @@ -57,41 +78,36 @@ pub struct ParseSess { /// operation token that followed it, but that the parser cannot identify without further /// analysis. pub ambiguous_block_expr_parse: Lock>, - pub param_attr_spans: Lock>, - // Places where `let` exprs were used and should be feature gated according to `let_chains`. - pub let_chains_spans: Lock>, - // Places where `async || ..` exprs were used and should be feature gated. - pub async_closure_spans: Lock>, pub injected_crate_name: Once, + pub gated_spans: GatedSpans, } impl ParseSess { pub fn new(file_path_mapping: FilePathMapping) -> Self { let cm = Lrc::new(SourceMap::new(file_path_mapping)); - let handler = Handler::with_tty_emitter(ColorConfig::Auto, - true, - None, - Some(cm.clone())); + let handler = Handler::with_tty_emitter( + ColorConfig::Auto, + true, + None, + Some(cm.clone()), + ); ParseSess::with_span_handler(handler, cm) } - pub fn with_span_handler(handler: Handler, source_map: Lrc) -> ParseSess { - ParseSess { + pub fn with_span_handler(handler: Handler, source_map: Lrc) -> Self { + Self { span_diagnostic: handler, unstable_features: UnstableFeatures::from_environment(), config: FxHashSet::default(), + edition: ExpnId::root().expn_data().edition, missing_fragment_specifiers: Lock::new(FxHashSet::default()), raw_identifier_spans: Lock::new(Vec::new()), - registered_diagnostics: Lock::new(ErrorMap::new()), included_mod_stack: Lock::new(vec![]), source_map, buffered_lints: Lock::new(vec![]), - edition: Edition::from_session(), ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), - param_attr_spans: Lock::new(Vec::new()), - let_chains_spans: Lock::new(Vec::new()), - async_closure_spans: Lock::new(Vec::new()), injected_crate_name: Once::new(), + gated_spans: GatedSpans::default(), } } @@ -144,17 +160,17 @@ pub struct Directory<'a> { #[derive(Copy, Clone)] pub enum DirectoryOwnership { Owned { - // None if `mod.rs`, `Some("foo")` if we're in `foo.rs` + // None if `mod.rs`, `Some("foo")` if we're in `foo.rs`. relative: Option, }, UnownedViaBlock, UnownedViaMod(bool /* legacy warnings? */), } -// a bunch of utility functions of the form parse__from_ +// A bunch of utility functions of the form `parse__from_` // where includes crate, expr, item, stmt, tts, and one that // uses a HOF to parse anything, and includes file and -// source_str. +// `source_str`. pub fn parse_crate_from_file<'a>(input: &Path, sess: &'a ParseSess) -> PResult<'a, ast::Crate> { let mut parser = new_parser_from_file(sess, input); @@ -208,14 +224,13 @@ pub fn maybe_new_parser_from_source_str(sess: &ParseSess, name: FileName, source Ok(parser) } -/// Creates a new parser, handling errors as appropriate -/// if the file doesn't exist +/// Creates a new parser, handling errors as appropriate if the file doesn't exist. pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path) -> Parser<'a> { source_file_to_parser(sess, file_to_source_file(sess, path, None)) } -/// Creates a new parser, returning buffered diagnostics if the file doesn't -/// exist or from lexing the initial token stream. +/// Creates a new parser, returning buffered diagnostics if the file doesn't exist, +/// or from lexing the initial token stream. pub fn maybe_new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path) -> Result, Vec> { let file = try_file_to_source_file(sess, path, None).map_err(|db| vec![db])?; @@ -223,8 +238,8 @@ pub fn maybe_new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path) } /// Given a session, a crate config, a path, and a span, add -/// the file at the given path to the source_map, and return a parser. -/// On an error, use the given span as the source of the problem. +/// the file at the given path to the `source_map`, and returns a parser. +/// On an error, uses the given span as the source of the problem. pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess, path: &Path, directory_ownership: DirectoryOwnership, @@ -236,13 +251,13 @@ pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess, p } -/// Given a source_file and config, return a parser +/// Given a `source_file` and config, returns a parser. fn source_file_to_parser(sess: &ParseSess, source_file: Lrc) -> Parser<'_> { panictry_buffer!(&sess.span_diagnostic, maybe_source_file_to_parser(sess, source_file)) } -/// Given a source_file and config, return a parser. Returns any buffered errors from lexing the +/// Given a `source_file` and config, return a parser. Returns any buffered errors from lexing the /// initial token stream. fn maybe_source_file_to_parser( sess: &ParseSess, @@ -259,14 +274,14 @@ fn maybe_source_file_to_parser( Ok(parser) } -// must preserve old name for now, because quote! from the *existing* -// compiler expands into it +// Must preserve old name for now, because `quote!` from the *existing* +// compiler expands into it. pub fn new_parser_from_tts(sess: &ParseSess, tts: Vec) -> Parser<'_> { stream_to_parser(sess, tts.into_iter().collect(), crate::MACRO_ARGUMENTS) } -// base abstractions +// Base abstractions /// Given a session and a path and an optional span (for error reporting), /// add the path to the session's source_map and return the new source_file or @@ -285,19 +300,19 @@ fn try_file_to_source_file(sess: &ParseSess, path: &Path, spanopt: Option) } /// Given a session and a path and an optional span (for error reporting), -/// add the path to the session's `source_map` and return the new `source_file`. +/// adds the path to the session's `source_map` and returns the new `source_file`. fn file_to_source_file(sess: &ParseSess, path: &Path, spanopt: Option) -> Lrc { match try_file_to_source_file(sess, path, spanopt) { Ok(source_file) => source_file, Err(d) => { - DiagnosticBuilder::new_diagnostic(&sess.span_diagnostic, d).emit(); + sess.span_diagnostic.emit_diagnostic(&d); FatalError.raise(); } } } -/// Given a source_file, produces a sequence of token trees. +/// Given a `source_file`, produces a sequence of token trees. pub fn source_file_to_stream( sess: &ParseSess, source_file: Lrc, @@ -341,7 +356,7 @@ pub fn maybe_file_to_stream( } } -/// Given stream and the `ParseSess`, produces a parser. +/// Given a stream and the `ParseSess`, produces a parser. pub fn stream_to_parser<'a>( sess: &'a ParseSess, stream: TokenStream, @@ -350,7 +365,7 @@ pub fn stream_to_parser<'a>( Parser::new(sess, stream, None, true, false, subparser_name) } -/// Given stream, the `ParseSess` and the base directory, produces a parser. +/// Given a stream, the `ParseSess` and the base directory, produces a parser. /// /// Use this function when you are creating a parser from the token stream /// and also care about the current working directory of the parser (e.g., diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d85c2df16a350..4a457f5a43caa 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1,74 +1,40 @@ -// ignore-tidy-filelength - -use crate::ast::{AngleBracketedArgs, ParenthesizedArgs, AttrStyle, BareFnTy}; -use crate::ast::{GenericBound, TraitBoundModifier}; -use crate::ast::Unsafety; -use crate::ast::{Mod, AnonConst, Arg, Arm, Attribute, BindingMode, TraitItemKind}; -use crate::ast::Block; -use crate::ast::{BlockCheckMode, CaptureBy, Movability}; -use crate::ast::{Constness, Crate}; -use crate::ast::Defaultness; -use crate::ast::EnumDef; -use crate::ast::{Expr, ExprKind, RangeLimits}; -use crate::ast::{Field, FnDecl, FnHeader}; -use crate::ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; -use crate::ast::{GenericParam, GenericParamKind}; -use crate::ast::GenericArg; -use crate::ast::{Ident, ImplItem, IsAsync, IsAuto, Item, ItemKind}; -use crate::ast::{Label, Lifetime}; -use crate::ast::Local; -use crate::ast::MacStmtStyle; -use crate::ast::{Mac, Mac_, MacDelimiter}; -use crate::ast::{MutTy, Mutability}; -use crate::ast::{Pat, PatKind, PathSegment}; -use crate::ast::{PolyTraitRef, QSelf}; -use crate::ast::{Stmt, StmtKind}; -use crate::ast::{VariantData, StructField}; -use crate::ast::StrStyle; -use crate::ast::SelfKind; -use crate::ast::{TraitItem, TraitRef, TraitObjectSyntax}; -use crate::ast::{Ty, TyKind, AssocTyConstraint, AssocTyConstraintKind, GenericBounds}; -use crate::ast::{Visibility, VisibilityKind, WhereClause, CrateSugar}; -use crate::ast::{UseTree, UseTreeKind}; -use crate::ast::{BinOpKind, UnOp}; -use crate::ast::{RangeEnd, RangeSyntax}; -use crate::{ast, attr}; -use crate::ext::base::DummyResult; -use crate::ext::hygiene::SyntaxContext; -use crate::source_map::{self, SourceMap, Spanned, respan}; -use crate::parse::{SeqSep, classify, literal, token}; +mod expr; +mod pat; +mod item; +pub use item::AliasKind; +mod module; +pub use module::{ModulePath, ModulePathSuccess}; +mod ty; +mod path; +pub use path::PathStyle; +mod stmt; +mod generics; + +use crate::ast::{ + self, DUMMY_NODE_ID, AttrStyle, Attribute, BindingMode, CrateSugar, Ident, + IsAsync, MacDelimiter, Mutability, Param, StrStyle, SelfKind, TyKind, Visibility, + VisibilityKind, Unsafety, +}; +use crate::parse::{ParseSess, PResult, Directory, DirectoryOwnership, SeqSep, literal, token}; +use crate::parse::diagnostics::{Error, dummy_arg}; use crate::parse::lexer::UnmatchedBrace; use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use crate::parse::token::{Token, TokenKind, DelimToken}; -use crate::parse::{new_sub_parser_from_file, ParseSess, Directory, DirectoryOwnership}; -use crate::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par}; use crate::print::pprust; use crate::ptr::P; -use crate::parse::PResult; -use crate::ThinVec; -use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint}; +use crate::source_map::{self, respan}; use crate::symbol::{kw, sym, Symbol}; -use crate::parse::diagnostics::{Error, dummy_arg}; +use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint}; +use crate::ThinVec; -use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError}; +use errors::{Applicability, DiagnosticId, FatalError}; use rustc_target::spec::abi::{self, Abi}; use syntax_pos::{Span, BytePos, DUMMY_SP, FileName}; use log::debug; use std::borrow::Cow; -use std::cmp; -use std::mem; -use std::path::{self, Path, PathBuf}; -use std::slice; - -#[derive(Debug)] -/// Whether the type alias or associated type is a concrete type or an opaque type -pub enum AliasKind { - /// Just a new name for the same type - Weak(P), - /// Only trait impls of the type will be usable, not the actual type itself - OpaqueTy(GenericBounds), -} +use std::{cmp, mem, slice}; +use std::path::PathBuf; bitflags::bitflags! { struct Restrictions: u8 { @@ -77,31 +43,6 @@ bitflags::bitflags! { } } -type ItemInfo = (Ident, ItemKind, Option>); - -/// Specifies how to parse a path. -#[derive(Copy, Clone, PartialEq)] -pub enum PathStyle { - /// In some contexts, notably in expressions, paths with generic arguments are ambiguous - /// with something else. For example, in expressions `segment < ....` can be interpreted - /// as a comparison and `segment ( ....` can be interpreted as a function call. - /// In all such contexts the non-path interpretation is preferred by default for practical - /// reasons, but the path interpretation can be forced by the disambiguator `::`, e.g. - /// `x` - comparisons, `x::` - unambiguously a path. - Expr, - /// In other contexts, notably in types, no ambiguity exists and paths can be written - /// without the disambiguator, e.g., `x` - unambiguously a path. - /// Paths with disambiguators are still accepted, `x::` - unambiguously a path too. - Type, - /// A path with generic arguments disallowed, e.g., `foo::bar::Baz`, used in imports, - /// visibilities or attributes. - /// Technically, this variant is unnecessary and e.g., `Expr` can be used instead - /// (paths in "mod" contexts have to be checked later for absence of generic arguments - /// anyway, due to macros), but it is used to avoid weird suggestions about expected - /// tokens when something goes wrong. - Mod, -} - #[derive(Clone, Copy, PartialEq, Debug)] crate enum SemiColonMode { Break, @@ -115,42 +56,19 @@ crate enum BlockMode { Ignore, } -/// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression -/// dropped into the token stream, which happens while parsing the result of -/// macro expansion). Placement of these is not as complex as I feared it would -/// be. The important thing is to make sure that lookahead doesn't balk at -/// `token::Interpolated` tokens. -macro_rules! maybe_whole_expr { - ($p:expr) => { - if let token::Interpolated(nt) = &$p.token.kind { - match &**nt { - token::NtExpr(e) | token::NtLiteral(e) => { - let e = e.clone(); - $p.bump(); - return Ok(e); - } - token::NtPath(path) => { - let path = path.clone(); - $p.bump(); - return Ok($p.mk_expr( - $p.token.span, ExprKind::Path(None, path), ThinVec::new() - )); - } - token::NtBlock(block) => { - let block = block.clone(); - $p.bump(); - return Ok($p.mk_expr( - $p.token.span, ExprKind::Block(block, None), ThinVec::new() - )); - } - // N.B: `NtIdent(ident)` is normalized to `Ident` in `fn bump`. - _ => {}, - }; - } - } +/// The parsing configuration used to parse a parameter list (see `parse_fn_params`). +struct ParamCfg { + /// Is `self` is allowed as the first parameter? + is_self_allowed: bool, + /// Is `...` allowed as the tail of the parameter list? + allow_c_variadic: bool, + /// `is_name_required` decides if, per-parameter, + /// the parameter must have a pattern or just a type. + is_name_required: fn(&token::Token) -> bool, } -/// As maybe_whole_expr, but for things other than expressions +/// Like `maybe_whole_expr`, but for things other than expressions. +#[macro_export] macro_rules! maybe_whole { ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { if let token::Interpolated(nt) = &$p.token.kind { @@ -164,6 +82,7 @@ macro_rules! maybe_whole { } /// If the next tokens are ill-formed `$ty::` recover them as `<$ty>::`. +#[macro_export] macro_rules! maybe_recover_from_interpolated_ty_qpath { ($self: expr, $allow_qpath_recovery: expr) => { if $allow_qpath_recovery && $self.look_ahead(1, |t| t == &token::ModSep) { @@ -208,11 +127,11 @@ pub struct Parser<'a> { /// with non-interpolated identifier and lifetime tokens they refer to. /// Perhaps the normalized / non-normalized setup can be simplified somehow. pub token: Token, - /// Span of the current non-normalized token. + /// The span of the current non-normalized token. meta_var_span: Option, - /// Span of the previous non-normalized token. + /// The span of the previous non-normalized token. pub prev_span: Span, - /// Kind of the previous normalized token (in simplified form). + /// The kind of the previous normalized token (in simplified form). prev_token_kind: PrevTokenKind, restrictions: Restrictions, /// Used to determine the path to externally loaded source files. @@ -224,7 +143,7 @@ pub struct Parser<'a> { /// into modules, and sub-parsers have new values for this name. pub root_module_name: Option, crate expected_tokens: Vec, - crate token_cursor: TokenCursor, + token_cursor: TokenCursor, desugar_doc_comments: bool, /// `true` we should configure out of line modules as we parse. pub cfg_mods: bool, @@ -235,7 +154,7 @@ pub struct Parser<'a> { /// See the comments in the `parse_path_segment` function for more details. crate unmatched_angle_bracket_count: u32, crate max_angle_bracket_count: u32, - /// List of all unclosed delimiters found by the lexer. If an entry is used for error recovery + /// A list of all unclosed delimiters found by the lexer. If an entry is used for error recovery /// it gets removed from here. Every entry left at the end gets emitted as an independent /// error. crate unclosed_delims: Vec, @@ -253,19 +172,19 @@ impl<'a> Drop for Parser<'a> { } #[derive(Clone)] -crate struct TokenCursor { - crate frame: TokenCursorFrame, - crate stack: Vec, +struct TokenCursor { + frame: TokenCursorFrame, + stack: Vec, } #[derive(Clone)] -crate struct TokenCursorFrame { - crate delim: token::DelimToken, - crate span: DelimSpan, - crate open_delim: bool, - crate tree_cursor: tokenstream::Cursor, - crate close_delim: bool, - crate last_token: LastToken, +struct TokenCursorFrame { + delim: token::DelimToken, + span: DelimSpan, + open_delim: bool, + tree_cursor: tokenstream::Cursor, + close_delim: bool, + last_token: LastToken, } /// This is used in `TokenCursorFrame` above to track tokens that are consumed @@ -415,52 +334,6 @@ impl TokenType { } } -/// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT`, -/// `IDENT<::AssocTy>`. -/// -/// Types can also be of the form `IDENT(u8, u8) -> u8`, however this assumes -/// that `IDENT` is not the ident of a fn trait. -fn can_continue_type_after_non_fn_ident(t: &Token) -> bool { - t == &token::ModSep || t == &token::Lt || - t == &token::BinOp(token::Shl) -} - -/// Information about the path to a module. -pub struct ModulePath { - name: String, - path_exists: bool, - pub result: Result, -} - -pub struct ModulePathSuccess { - pub path: PathBuf, - pub directory_ownership: DirectoryOwnership, - warn: bool, -} - -#[derive(Debug)] -enum LhsExpr { - NotYetParsed, - AttributesParsed(ThinVec), - AlreadyParsed(P), -} - -impl From>> for LhsExpr { - fn from(o: Option>) -> Self { - if let Some(attrs) = o { - LhsExpr::AttributesParsed(attrs) - } else { - LhsExpr::NotYetParsed - } - } -} - -impl From> for LhsExpr { - fn from(expr: P) -> Self { - LhsExpr::AlreadyParsed(expr) - } -} - #[derive(Copy, Clone, Debug)] crate enum TokenExpectType { Expect, @@ -513,10 +386,11 @@ impl<'a> Parser<'a> { if let Some(directory) = directory { parser.directory = directory; } else if !parser.token.span.is_dummy() { - if let FileName::Real(mut path) = - sess.source_map().span_to_unmapped_path(parser.token.span) { - path.pop(); - parser.directory.path = Cow::from(path); + if let Some(FileName::Real(path)) = + &sess.source_map().lookup_char_pos(parser.token.span.lo()).file.unmapped_path { + if let Some(directory_path) = path.parent() { + parser.directory.path = Cow::from(directory_path.to_path_buf()); + } } } @@ -602,20 +476,6 @@ impl<'a> Parser<'a> { } } - /// Returns the span of expr, if it was not interpolated or the span of the interpolated token. - fn interpolated_or_expr_span( - &self, - expr: PResult<'a, P>, - ) -> PResult<'a, (Span, P)> { - expr.map(|e| { - if self.prev_token_kind == PrevTokenKind::Interpolated { - (self.prev_span, e) - } else { - (e.span, e) - } - }) - } - pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> { self.parse_ident_common(true) } @@ -662,13 +522,15 @@ impl<'a> Parser<'a> { is_present } + /// If the next token is the given keyword, returns `true` without eating it. + /// An expectation is also added for diagnostics purposes. fn check_keyword(&mut self, kw: Symbol) -> bool { self.expected_tokens.push(TokenType::Keyword(kw)); self.token.is_keyword(kw) } - /// If the next token is the given keyword, eats it and returns - /// `true`. Otherwise, returns `false`. + /// If the next token is the given keyword, eats it and returns `true`. + /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes. pub fn eat_keyword(&mut self, kw: Symbol) -> bool { if self.check_keyword(kw) { self.bump(); @@ -698,40 +560,38 @@ impl<'a> Parser<'a> { } } - crate fn check_ident(&mut self) -> bool { - if self.token.is_ident() { + fn check_or_expected(&mut self, ok: bool, typ: TokenType) -> bool { + if ok { true } else { - self.expected_tokens.push(TokenType::Ident); + self.expected_tokens.push(typ); false } } + crate fn check_ident(&mut self) -> bool { + self.check_or_expected(self.token.is_ident(), TokenType::Ident) + } + fn check_path(&mut self) -> bool { - if self.token.is_path_start() { - true - } else { - self.expected_tokens.push(TokenType::Path); - false - } + self.check_or_expected(self.token.is_path_start(), TokenType::Path) } fn check_type(&mut self) -> bool { - if self.token.can_begin_type() { - true - } else { - self.expected_tokens.push(TokenType::Type); - false - } + self.check_or_expected(self.token.can_begin_type(), TokenType::Type) } fn check_const_arg(&mut self) -> bool { - if self.token.can_begin_const_arg() { - true - } else { - self.expected_tokens.push(TokenType::Const); - false - } + self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const) + } + + /// Checks to see if the next token is either `+` or `+=`. + /// Otherwise returns `false`. + fn check_plus(&mut self) -> bool { + self.check_or_expected( + self.token.is_like_plus(), + TokenType::Token(token::BinOp(token::Plus)), + ) } /// Expects and consumes a `+`. if `+=` is seen, replaces it with a `=` @@ -755,19 +615,6 @@ impl<'a> Parser<'a> { } } - - /// Checks to see if the next token is either `+` or `+=`. - /// Otherwise returns `false`. - fn check_plus(&mut self) -> bool { - if self.token.is_like_plus() { - true - } - else { - self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus))); - false - } - } - /// Expects and consumes an `&`. If `&&` is seen, replaces it with a single /// `&` and continues. If an `&` is not seen, signals an error. fn expect_and(&mut self) -> PResult<'a, ()> { @@ -951,14 +798,14 @@ impl<'a> Parser<'a> { break; } Err(mut e) => { - // Attempt to keep parsing if it was a similar separator + // Attempt to keep parsing if it was a similar separator. if let Some(ref tokens) = t.similar_tokens() { if tokens.contains(&self.token.kind) { self.bump(); } } e.emit(); - // Attempt to keep parsing if it was an omitted separator + // Attempt to keep parsing if it was an omitted separator. match f(self) { Ok(t) => { v.push(t); @@ -1023,7 +870,7 @@ impl<'a> Parser<'a> { self.parse_delim_comma_seq(token::Paren, f) } - /// Advance the parser by one token + /// Advance the parser by one token. pub fn bump(&mut self) { if self.prev_token_kind == PrevTokenKind::Eof { // Bumping after EOF is a bad sign, usually an infinite loop. @@ -1046,31 +893,31 @@ impl<'a> Parser<'a> { self.token = self.next_tok(); self.expected_tokens.clear(); - // check after each token + // Check after each token. self.process_potential_macro_variable(); } - /// Advance the parser using provided token as a next one. Use this when + /// Advances the parser using provided token as a next one. Use this when /// consuming a part of a token. For example a single `<` from `<<`. fn bump_with(&mut self, next: TokenKind, span: Span) { self.prev_span = self.token.span.with_hi(span.lo()); // It would be incorrect to record the kind of the current token, but // fortunately for tokens currently using `bump_with`, the - // prev_token_kind will be of no use anyway. + // `prev_token_kind` will be of no use anyway. self.prev_token_kind = PrevTokenKind::Other; self.token = Token::new(next, span); self.expected_tokens.clear(); } - pub fn look_ahead(&self, dist: usize, f: F) -> R where - F: FnOnce(&Token) -> R, - { + /// Look-ahead `dist` tokens of `self.token` and get access to that token there. + /// When `dist == 0` then the current token is looked at. + pub fn look_ahead(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R { if dist == 0 { - return f(&self.token); + return looker(&self.token); } let frame = &self.token_cursor.frame; - f(&match frame.tree_cursor.look_ahead(dist - 1) { + looker(&match frame.tree_cursor.look_ahead(dist - 1) { Some(tree) => match tree { TokenTree::Token(token) => token, TokenTree::Delimited(dspan, delim, _) => @@ -1085,56 +932,12 @@ impl<'a> Parser<'a> { self.look_ahead(dist, |t| kws.iter().any(|&kw| t.is_keyword(kw))) } - /// Is the current token one of the keywords that signals a bare function type? - fn token_is_bare_fn_keyword(&mut self) -> bool { - self.check_keyword(kw::Fn) || - self.check_keyword(kw::Unsafe) || - self.check_keyword(kw::Extern) - } - - /// Parses a `TyKind::BareFn` type. - fn parse_ty_bare_fn(&mut self, generic_params: Vec) -> PResult<'a, TyKind> { - /* - - [unsafe] [extern "ABI"] fn (S) -> T - ^~~~^ ^~~~^ ^~^ ^ - | | | | - | | | Return type - | | Argument types - | | - | ABI - Function Style - */ - - let unsafety = self.parse_unsafety(); - let abi = if self.eat_keyword(kw::Extern) { - self.parse_opt_abi()?.unwrap_or(Abi::C) - } else { - Abi::Rust - }; - - self.expect_keyword(kw::Fn)?; - let (inputs, c_variadic) = self.parse_fn_args(false, true)?; - let ret_ty = self.parse_ret_ty(false)?; - let decl = P(FnDecl { - inputs, - output: ret_ty, - c_variadic, - }); - Ok(TyKind::BareFn(P(BareFnTy { - abi, - unsafety, - generic_params, - decl, - }))) - } - /// Parses asyncness: `async` or nothing. fn parse_asyncness(&mut self) -> IsAsync { if self.eat_keyword(kw::Async) { IsAsync::Async { - closure_id: ast::DUMMY_NODE_ID, - return_impl_trait_id: ast::DUMMY_NODE_ID, + closure_id: DUMMY_NODE_ID, + return_impl_trait_id: DUMMY_NODE_ID, } } else { IsAsync::NotAsync @@ -1150,410 +953,262 @@ impl<'a> Parser<'a> { } } - /// Parses the items in a trait declaration. - pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem> { - maybe_whole!(self, NtTraitItem, |x| x); - let attrs = self.parse_outer_attributes()?; - let mut unclosed_delims = vec![]; - let (mut item, tokens) = self.collect_tokens(|this| { - let item = this.parse_trait_item_(at_end, attrs); - unclosed_delims.append(&mut this.unclosed_delims); - item - })?; - self.unclosed_delims.append(&mut unclosed_delims); - // See `parse_item` for why this clause is here. - if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { - item.tokens = Some(tokens); + /// Parses mutability (`mut` or nothing). + fn parse_mutability(&mut self) -> Mutability { + if self.eat_keyword(kw::Mut) { + Mutability::Mutable + } else { + Mutability::Immutable } - Ok(item) } - fn parse_trait_item_(&mut self, - at_end: &mut bool, - mut attrs: Vec) -> PResult<'a, TraitItem> { - let lo = self.token.span; - self.eat_bad_pub(); - let (name, node, generics) = if self.eat_keyword(kw::Type) { - self.parse_trait_item_assoc_ty()? - } else if self.is_const_item() { - self.expect_keyword(kw::Const)?; - let ident = self.parse_ident()?; - self.expect(&token::Colon)?; - let ty = self.parse_ty()?; - let default = if self.eat(&token::Eq) { - let expr = self.parse_expr()?; - self.expect(&token::Semi)?; - Some(expr) - } else { - self.expect(&token::Semi)?; - None - }; - (ident, TraitItemKind::Const(ty, default), ast::Generics::default()) - } else if let Some(mac) = self.parse_assoc_macro_invoc("trait", None, &mut false)? { - // trait item macro. - (Ident::invalid(), ast::TraitItemKind::Macro(mac), ast::Generics::default()) + /// Possibly parses mutability (`const` or `mut`). + fn parse_const_or_mut(&mut self) -> Option { + if self.eat_keyword(kw::Mut) { + Some(Mutability::Mutable) + } else if self.eat_keyword(kw::Const) { + Some(Mutability::Immutable) } else { - let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; - - let ident = self.parse_ident()?; - let mut generics = self.parse_generics()?; - - let decl = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| { - // This is somewhat dubious; We don't want to allow - // argument names to be left off if there is a - // definition... - - // We don't allow argument names to be left off in edition 2018. - let is_name_required = p.token.span.rust_2018(); - p.parse_arg_general(true, false, |_| is_name_required) - })?; - generics.where_clause = self.parse_where_clause()?; - - let sig = ast::MethodSig { - header: FnHeader { - unsafety, - constness, - abi, - asyncness, - }, - decl, - }; - - let body = match self.token.kind { - token::Semi => { - self.bump(); - *at_end = true; - debug!("parse_trait_methods(): parsing required method"); - None - } - token::OpenDelim(token::Brace) => { - debug!("parse_trait_methods(): parsing provided method"); - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) - } - token::Interpolated(ref nt) => { - match **nt { - token::NtBlock(..) => { - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) - } - _ => { - return self.expected_semi_or_open_brace(); - } - } - } - _ => { - return self.expected_semi_or_open_brace(); - } - }; - (ident, ast::TraitItemKind::Method(sig, body), generics) - }; - - Ok(TraitItem { - id: ast::DUMMY_NODE_ID, - ident: name, - attrs, - generics, - node, - span: lo.to(self.prev_span), - tokens: None, - }) + None + } } - /// Parses an optional return type `[ -> TY ]` in a function declaration. - fn parse_ret_ty(&mut self, allow_plus: bool) -> PResult<'a, FunctionRetTy> { - if self.eat(&token::RArrow) { - Ok(FunctionRetTy::Ty(self.parse_ty_common(allow_plus, true, false)?)) + fn parse_field_name(&mut self) -> PResult<'a, Ident> { + if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = + self.token.kind { + self.expect_no_suffix(self.token.span, "a tuple index", suffix); + self.bump(); + Ok(Ident::new(symbol, self.prev_span)) } else { - Ok(FunctionRetTy::Default(self.token.span.shrink_to_lo())) + self.parse_ident_common(false) } } - /// Parses a type. - pub fn parse_ty(&mut self) -> PResult<'a, P> { - self.parse_ty_common(true, true, false) + fn expect_delimited_token_tree(&mut self) -> PResult<'a, (MacDelimiter, TokenStream)> { + let delim = match self.token.kind { + token::OpenDelim(delim) => delim, + _ => { + let msg = "expected open delimiter"; + let mut err = self.fatal(msg); + err.span_label(self.token.span, msg); + return Err(err) + } + }; + let tts = match self.parse_token_tree() { + TokenTree::Delimited(_, _, tts) => tts, + _ => unreachable!(), + }; + let delim = match delim { + token::Paren => MacDelimiter::Parenthesis, + token::Bracket => MacDelimiter::Bracket, + token::Brace => MacDelimiter::Brace, + token::NoDelim => self.bug("unexpected no delimiter"), + }; + Ok((delim, tts.into())) } - /// Parses a type in restricted contexts where `+` is not permitted. - /// - /// Example 1: `&'a TYPE` - /// `+` is prohibited to maintain operator priority (P(+) < P(&)). - /// Example 2: `value1 as TYPE + value2` - /// `+` is prohibited to avoid interactions with expression grammar. - fn parse_ty_no_plus(&mut self) -> PResult<'a, P> { - self.parse_ty_common(false, true, false) + fn parse_or_use_outer_attributes( + &mut self, + already_parsed_attrs: Option>, + ) -> PResult<'a, ThinVec> { + if let Some(attrs) = already_parsed_attrs { + Ok(attrs) + } else { + self.parse_outer_attributes().map(|a| a.into()) + } } - fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool, - allow_c_variadic: bool) -> PResult<'a, P> { - maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); - maybe_whole!(self, NtTy, |x| x); - - let lo = self.token.span; - let mut impl_dyn_multi = false; - let node = if self.eat(&token::OpenDelim(token::Paren)) { - // `(TYPE)` is a parenthesized type. - // `(TYPE,)` is a tuple with a single field of type TYPE. - let mut ts = vec![]; - let mut last_comma = false; - while self.token != token::CloseDelim(token::Paren) { - ts.push(self.parse_ty()?); - if self.eat(&token::Comma) { - last_comma = true; - } else { - last_comma = false; - break; - } - } - let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus; - self.expect(&token::CloseDelim(token::Paren))?; - - if ts.len() == 1 && !last_comma { - let ty = ts.into_iter().nth(0).unwrap().into_inner(); - let maybe_bounds = allow_plus && self.token.is_like_plus(); - match ty.node { - // `(TY_BOUND_NOPAREN) + BOUND + ...`. - TyKind::Path(None, ref path) if maybe_bounds => { - self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)? - } - TyKind::TraitObject(ref bounds, TraitObjectSyntax::None) - if maybe_bounds && bounds.len() == 1 && !trailing_plus => { - let path = match bounds[0] { - GenericBound::Trait(ref pt, ..) => pt.trait_ref.path.clone(), - GenericBound::Outlives(..) => self.bug("unexpected lifetime bound"), - }; - self.parse_remaining_bounds(Vec::new(), path, lo, true)? - } - // `(TYPE)` - _ => TyKind::Paren(P(ty)) - } - } else { - TyKind::Tup(ts) - } - } else if self.eat(&token::Not) { - // Never type `!` - TyKind::Never - } else if self.eat(&token::BinOp(token::Star)) { - // Raw pointer - TyKind::Ptr(self.parse_ptr()?) - } else if self.eat(&token::OpenDelim(token::Bracket)) { - // Array or slice - let t = self.parse_ty()?; - // Parse optional `; EXPR` in `[TYPE; EXPR]` - let t = match self.maybe_parse_fixed_length_of_vec()? { - None => TyKind::Slice(t), - Some(length) => TyKind::Array(t, AnonConst { - id: ast::DUMMY_NODE_ID, - value: length, - }), - }; - self.expect(&token::CloseDelim(token::Bracket))?; - t - } else if self.check(&token::BinOp(token::And)) || self.check(&token::AndAnd) { - // Reference - self.expect_and()?; - self.parse_borrowed_pointee()? - } else if self.eat_keyword_noexpect(kw::Typeof) { - // `typeof(EXPR)` - // In order to not be ambiguous, the type must be surrounded by parens. - self.expect(&token::OpenDelim(token::Paren))?; - let e = AnonConst { - id: ast::DUMMY_NODE_ID, - value: self.parse_expr()?, - }; - self.expect(&token::CloseDelim(token::Paren))?; - TyKind::Typeof(e) - } else if self.eat_keyword(kw::Underscore) { - // A type to be inferred `_` - TyKind::Infer - } else if self.token_is_bare_fn_keyword() { - // Function pointer type - self.parse_ty_bare_fn(Vec::new())? - } else if self.check_keyword(kw::For) { - // Function pointer type or bound list (trait object type) starting with a poly-trait. - // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` - // `for<'lt> Trait1<'lt> + Trait2 + 'a` - let lo = self.token.span; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - if self.token_is_bare_fn_keyword() { - self.parse_ty_bare_fn(lifetime_defs)? - } else { - let path = self.parse_path(PathStyle::Type)?; - let parse_plus = allow_plus && self.check_plus(); - self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? - } - } else if self.eat_keyword(kw::Impl) { - // Always parse bounds greedily for better error recovery. - let bounds = self.parse_generic_bounds(None)?; - impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; - TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds) - } else if self.check_keyword(kw::Dyn) && - (self.token.span.rust_2018() || - self.look_ahead(1, |t| t.can_begin_bound() && - !can_continue_type_after_non_fn_ident(t))) { - self.bump(); // `dyn` - // Always parse bounds greedily for better error recovery. - let bounds = self.parse_generic_bounds(None)?; - impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; - TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn) - } else if self.check(&token::Question) || - self.check_lifetime() && self.look_ahead(1, |t| t.is_like_plus()) { - // Bound list (trait object type) - TyKind::TraitObject(self.parse_generic_bounds_common(allow_plus, None)?, - TraitObjectSyntax::None) - } else if self.eat_lt() { - // Qualified path - let (qself, path) = self.parse_qpath(PathStyle::Type)?; - TyKind::Path(Some(qself), path) - } else if self.token.is_path_start() { - // Simple path - let path = self.parse_path(PathStyle::Type)?; - if self.eat(&token::Not) { - // Macro invocation in type position - let (delim, tts) = self.expect_delimited_token_tree()?; - let node = Mac_ { - path, - tts, - delim, - prior_type_ascription: self.last_type_ascription, + crate fn process_potential_macro_variable(&mut self) { + self.token = match self.token.kind { + token::Dollar if self.token.span.from_expansion() && + self.look_ahead(1, |t| t.is_ident()) => { + self.bump(); + let name = match self.token.kind { + token::Ident(name, _) => name, + _ => unreachable!() }; - TyKind::Mac(respan(lo.to(self.prev_span), node)) - } else { - // Just a type path or bound list (trait object type) starting with a trait. - // `Type` - // `Trait1 + Trait2 + 'a` - if allow_plus && self.check_plus() { - self.parse_remaining_bounds(Vec::new(), path, lo, true)? - } else { - TyKind::Path(None, path) - } + let span = self.prev_span.to(self.token.span); + self.diagnostic() + .struct_span_fatal(span, &format!("unknown macro variable `{}`", name)) + .span_label(span, "unknown macro variable") + .emit(); + self.bump(); + return } - } else if self.check(&token::DotDotDot) { - if allow_c_variadic { - self.eat(&token::DotDotDot); - TyKind::CVarArgs - } else { - return Err(self.fatal( - "only foreign functions are allowed to be C-variadic" - )); + token::Interpolated(ref nt) => { + self.meta_var_span = Some(self.token.span); + // Interpolated identifier and lifetime tokens are replaced with usual identifier + // and lifetime tokens, so the former are never encountered during normal parsing. + match **nt { + token::NtIdent(ident, is_raw) => + Token::new(token::Ident(ident.name, is_raw), ident.span), + token::NtLifetime(ident) => + Token::new(token::Lifetime(ident.name), ident.span), + _ => return, + } } - } else { - let msg = format!("expected type, found {}", self.this_token_descr()); - let mut err = self.fatal(&msg); - err.span_label(self.token.span, "expected type"); - self.maybe_annotate_with_ascription(&mut err, true); - return Err(err); + _ => return, }; - - let span = lo.to(self.prev_span); - let ty = P(Ty { node, span, id: ast::DUMMY_NODE_ID }); - - // Try to recover from use of `+` with incorrect priority. - self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty); - self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?; - self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery) } - fn parse_remaining_bounds(&mut self, generic_params: Vec, path: ast::Path, - lo: Span, parse_plus: bool) -> PResult<'a, TyKind> { - let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span)); - let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)]; - if parse_plus { - self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded - bounds.append(&mut self.parse_generic_bounds(Some(self.prev_span))?); + /// Parses a single token tree from the input. + crate fn parse_token_tree(&mut self) -> TokenTree { + match self.token.kind { + token::OpenDelim(..) => { + let frame = mem::replace(&mut self.token_cursor.frame, + self.token_cursor.stack.pop().unwrap()); + self.token.span = frame.span.entire(); + self.bump(); + TokenTree::Delimited( + frame.span, + frame.delim, + frame.tree_cursor.stream.into(), + ) + }, + token::CloseDelim(_) | token::Eof => unreachable!(), + _ => { + let token = self.token.take(); + self.bump(); + TokenTree::Token(token) + } } - Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) - } - - fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { - let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; - let mutbl = self.parse_mutability(); - let ty = self.parse_ty_no_plus()?; - return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl })); } - fn parse_ptr(&mut self) -> PResult<'a, MutTy> { - let mutbl = if self.eat_keyword(kw::Mut) { - Mutability::Mutable - } else if self.eat_keyword(kw::Const) { - Mutability::Immutable - } else { - let span = self.prev_span; - let msg = "expected mut or const in raw pointer type"; - self.struct_span_err(span, msg) - .span_label(span, msg) - .help("use `*mut T` or `*const T` as appropriate") - .emit(); - Mutability::Immutable - }; - let t = self.parse_ty_no_plus()?; - Ok(MutTy { ty: t, mutbl }) + /// Parses a stream of tokens into a list of `TokenTree`s, up to EOF. + pub fn parse_all_token_trees(&mut self) -> PResult<'a, Vec> { + let mut tts = Vec::new(); + while self.token != token::Eof { + tts.push(self.parse_token_tree()); + } + Ok(tts) } - fn is_named_argument(&self) -> bool { - let offset = match self.token.kind { - token::Interpolated(ref nt) => match **nt { - token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), - _ => 0, + pub fn parse_tokens(&mut self) -> TokenStream { + let mut result = Vec::new(); + loop { + match self.token.kind { + token::Eof | token::CloseDelim(..) => break, + _ => result.push(self.parse_token_tree().into()), } - token::BinOp(token::And) | token::AndAnd => 1, - _ if self.token.is_keyword(kw::Mut) => 1, - _ => 0, - }; + } + TokenStream::new(result) + } - self.look_ahead(offset, |t| t.is_ident()) && - self.look_ahead(offset + 1, |t| t == &token::Colon) + /// Evaluates the closure with restrictions in place. + /// + /// Afters the closure is evaluated, restrictions are reset. + fn with_res(&mut self, res: Restrictions, f: impl FnOnce(&mut Self) -> T) -> T { + let old = self.restrictions; + self.restrictions = res; + let res = f(self); + self.restrictions = old; + res } - /// Skips unexpected attributes and doc comments in this position and emits an appropriate - /// error. - /// This version of parse arg doesn't necessarily require identifier names. - fn parse_arg_general( - &mut self, - is_trait_item: bool, - allow_c_variadic: bool, - is_name_required: F, - ) -> PResult<'a, Arg> - where - F: Fn(&token::Token) -> bool - { + /// Parses the parameter list of a function, including the `(` and `)` delimiters. + fn parse_fn_params(&mut self, mut cfg: ParamCfg) -> PResult<'a, Vec> { + let sp = self.token.span; + let is_trait_item = cfg.is_self_allowed; + let mut c_variadic = false; + // Parse the arguments, starting out with `self` being possibly allowed... + let (params, _) = self.parse_paren_comma_seq(|p| { + let param = p.parse_param_general(&cfg, is_trait_item); + // ...now that we've parsed the first argument, `self` is no longer allowed. + cfg.is_self_allowed = false; + + match param { + Ok(param) => Ok( + if let TyKind::CVarArgs = param.ty.kind { + c_variadic = true; + if p.token != token::CloseDelim(token::Paren) { + p.span_err( + p.token.span, + "`...` must be the last argument of a C-variadic function", + ); + // FIXME(eddyb) this should probably still push `CVarArgs`. + // Maybe AST validation/HIR lowering should emit the above error? + None + } else { + Some(param) + } + } else { + Some(param) + } + ), + Err(mut e) => { + e.emit(); + let lo = p.prev_span; + // Skip every token until next possible arg or end. + p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]); + // Create a placeholder argument for proper arg count (issue #34264). + let span = lo.to(p.prev_span); + Ok(Some(dummy_arg(Ident::new(kw::Invalid, span)))) + } + } + })?; + + let mut params: Vec<_> = params.into_iter().filter_map(|x| x).collect(); + + // Replace duplicated recovered params with `_` pattern to avoid unecessary errors. + self.deduplicate_recovered_params_names(&mut params); + + if c_variadic && params.len() <= 1 { + self.span_err( + sp, + "C-variadic function must be declared with at least one named argument", + ); + } + + Ok(params) + } + + /// Skips unexpected attributes and doc comments in this position and emits an appropriate + /// error. + /// This version of parse param doesn't necessarily require identifier names. + fn parse_param_general(&mut self, cfg: &ParamCfg, is_trait_item: bool) -> PResult<'a, Param> { let lo = self.token.span; - let attrs = self.parse_arg_attributes()?; - if let Some(mut arg) = self.parse_self_arg()? { - arg.attrs = attrs.into(); - return self.recover_bad_self_arg(arg, is_trait_item); + let attrs = self.parse_outer_attributes()?; + + // Possibly parse `self`. Recover if we parsed it and it wasn't allowed here. + if let Some(mut param) = self.parse_self_param()? { + param.attrs = attrs.into(); + return if cfg.is_self_allowed { + Ok(param) + } else { + self.recover_bad_self_param(param, is_trait_item) + }; } - let is_name_required = is_name_required(&self.token); - let (pat, ty) = if is_name_required || self.is_named_argument() { - debug!("parse_arg_general parse_pat (is_name_required:{})", is_name_required); + let is_name_required = match self.token.kind { + token::DotDotDot => false, + _ => (cfg.is_name_required)(&self.token), + }; + let (pat, ty) = if is_name_required || self.is_named_param() { + debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); - let pat = self.parse_pat(Some("argument name"))?; + let pat = self.parse_fn_param_pat()?; if let Err(mut err) = self.expect(&token::Colon) { - if let Some(ident) = self.argument_without_type( + return if let Some(ident) = self.parameter_without_type( &mut err, pat, is_name_required, + cfg.is_self_allowed, is_trait_item, ) { err.emit(); - return Ok(dummy_arg(ident)); + Ok(dummy_arg(ident)) } else { - return Err(err); - } + Err(err) + }; } - self.eat_incorrect_doc_comment_for_arg_type(); - (pat, self.parse_ty_common(true, true, allow_c_variadic)?) + self.eat_incorrect_doc_comment_for_param_type(); + (pat, self.parse_ty_common(true, true, cfg.allow_c_variadic)?) } else { - debug!("parse_arg_general ident_to_pat"); + debug!("parse_param_general ident_to_pat"); let parser_snapshot_before_ty = self.clone(); - self.eat_incorrect_doc_comment_for_arg_type(); - let mut ty = self.parse_ty_common(true, true, allow_c_variadic); + self.eat_incorrect_doc_comment_for_param_type(); + let mut ty = self.parse_ty_common(true, true, cfg.allow_c_variadic); if ty.is_ok() && self.token != token::Comma && self.token != token::CloseDelim(token::Paren) { // This wasn't actually a type, but a pattern looking like a type, @@ -1563,21 +1218,14 @@ impl<'a> Parser<'a> { match ty { Ok(ty) => { let ident = Ident::new(kw::Invalid, self.prev_span); - let pat = P(Pat { - id: ast::DUMMY_NODE_ID, - node: PatKind::Ident( - BindingMode::ByValue(Mutability::Immutable), ident, None), - span: ty.span, - }); + let bm = BindingMode::ByValue(Mutability::Immutable); + let pat = self.mk_pat_ident(ty.span, bm, ident); (pat, ty) } + // If this is a C-variadic argument and we hit an error, return the error. + Err(err) if self.token == token::DotDotDot => return Err(err), + // Recover from attempting to parse the argument as a type without pattern. Err(mut err) => { - // If this is a C-variadic argument and we hit an error, return the - // error. - if self.token == token::DotDotDot { - return Err(err); - } - // Recover from attempting to parse the argument as a type without pattern. err.cancel(); mem::replace(self, parser_snapshot_before_ty); self.recover_arg_parse()? @@ -1587,5344 +1235,245 @@ impl<'a> Parser<'a> { let span = lo.to(self.token.span); - Ok(Arg { attrs: attrs.into(), id: ast::DUMMY_NODE_ID, pat, span, ty }) - } - - /// Parses an argument in a lambda header (e.g., `|arg, arg|`). - fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> { - let lo = self.token.span; - let attrs = self.parse_arg_attributes()?; - let pat = self.parse_pat(Some("argument name"))?; - let t = if self.eat(&token::Colon) { - self.parse_ty()? - } else { - P(Ty { - id: ast::DUMMY_NODE_ID, - node: TyKind::Infer, - span: self.prev_span, - }) - }; - let span = lo.to(self.token.span); - Ok(Arg { + Ok(Param { attrs: attrs.into(), - ty: t, + id: ast::DUMMY_NODE_ID, + is_placeholder: false, pat, span, - id: ast::DUMMY_NODE_ID + ty, }) } - fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<'a, Option>> { - if self.eat(&token::Semi) { - Ok(Some(self.parse_expr()?)) - } else { - Ok(None) - } - } - - /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). - crate fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P> { - maybe_whole_expr!(self); - - let minus_lo = self.token.span; - let minus_present = self.eat(&token::BinOp(token::Minus)); - let lo = self.token.span; - let literal = self.parse_lit()?; - let hi = self.prev_span; - let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), ThinVec::new()); - - if minus_present { - let minus_hi = self.prev_span; - let unary = self.mk_unary(UnOp::Neg, expr); - Ok(self.mk_expr(minus_lo.to(minus_hi), unary, ThinVec::new())) - } else { - Ok(expr) - } - } - - fn parse_path_segment_ident(&mut self) -> PResult<'a, ast::Ident> { - match self.token.kind { - token::Ident(name, _) if name.is_path_segment_keyword() => { - let span = self.token.span; - self.bump(); - Ok(Ident::new(name, span)) - } - _ => self.parse_ident(), - } - } - - fn parse_ident_or_underscore(&mut self) -> PResult<'a, ast::Ident> { - match self.token.kind { - token::Ident(name, false) if name == kw::Underscore => { - let span = self.token.span; - self.bump(); - Ok(Ident::new(name, span)) - } - _ => self.parse_ident(), - } - } - - /// Parses a qualified path. - /// Assumes that the leading `<` has been parsed already. - /// - /// `qualified_path = ::path` - /// - /// # Examples - /// `::default` - /// `::a` - /// `::F::a` (without disambiguator) - /// `::F::a::` (with disambiguator) - fn parse_qpath(&mut self, style: PathStyle) -> PResult<'a, (QSelf, ast::Path)> { - let lo = self.prev_span; - let ty = self.parse_ty()?; - - // `path` will contain the prefix of the path up to the `>`, - // if any (e.g., `U` in the `::*` examples - // above). `path_span` has the span of that path, or an empty - // span in the case of something like `::Bar`. - let (mut path, path_span); - if self.eat_keyword(kw::As) { - let path_lo = self.token.span; - path = self.parse_path(PathStyle::Type)?; - path_span = path_lo.to(self.prev_span); - } else { - path_span = self.token.span.to(self.token.span); - path = ast::Path { segments: Vec::new(), span: path_span }; - } - - // See doc comment for `unmatched_angle_bracket_count`. - self.expect(&token::Gt)?; - if self.unmatched_angle_bracket_count > 0 { - self.unmatched_angle_bracket_count -= 1; - debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count); - } - - self.expect(&token::ModSep)?; - - let qself = QSelf { ty, path_span, position: path.segments.len() }; - self.parse_path_segments(&mut path.segments, style)?; - - Ok((qself, ast::Path { segments: path.segments, span: lo.to(self.prev_span) })) - } - - /// Parses simple paths. + /// Returns the parsed optional self parameter and whether a self shortcut was used. /// - /// `path = [::] segment+` - /// `segment = ident | ident[::] | ident[::](args) [-> type]` - /// - /// # Examples - /// `a::b::C` (without disambiguator) - /// `a::b::C::` (with disambiguator) - /// `Fn(Args)` (without disambiguator) - /// `Fn::(Args)` (with disambiguator) - pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, ast::Path> { - maybe_whole!(self, NtPath, |path| { - if style == PathStyle::Mod && - path.segments.iter().any(|segment| segment.args.is_some()) { - self.diagnostic().span_err(path.span, "unexpected generic arguments in path"); - } - path - }); - - let lo = self.meta_var_span.unwrap_or(self.token.span); - let mut segments = Vec::new(); - let mod_sep_ctxt = self.token.span.ctxt(); - if self.eat(&token::ModSep) { - segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt))); - } - self.parse_path_segments(&mut segments, style)?; - - Ok(ast::Path { segments, span: lo.to(self.prev_span) }) - } - - /// Like `parse_path`, but also supports parsing `Word` meta items into paths for - /// backwards-compatibility. This is used when parsing derive macro paths in `#[derive]` - /// attributes. - pub fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, ast::Path> { - let meta_ident = match self.token.kind { - token::Interpolated(ref nt) => match **nt { - token::NtMeta(ref meta) => match meta.node { - ast::MetaItemKind::Word => Some(meta.path.clone()), - _ => None, - }, - _ => None, - }, - _ => None, - }; - if let Some(path) = meta_ident { - self.bump(); - return Ok(path); - } - self.parse_path(style) - } - - crate fn parse_path_segments(&mut self, - segments: &mut Vec, - style: PathStyle) - -> PResult<'a, ()> { - loop { - let segment = self.parse_path_segment(style)?; - if style == PathStyle::Expr { - // In order to check for trailing angle brackets, we must have finished - // recursing (`parse_path_segment` can indirectly call this function), - // that is, the next token must be the highlighted part of the below example: - // - // `Foo::>::Qux` - // ^ here - // - // As opposed to the below highlight (if we had only finished the first - // recursion): - // - // `Foo::>::Qux` - // ^ here - // - // `PathStyle::Expr` is only provided at the root invocation and never in - // `parse_path_segment` to recurse and therefore can be checked to maintain - // this invariant. - self.check_trailing_angle_brackets(&segment, token::ModSep); - } - segments.push(segment); - - if self.is_import_coupler() || !self.eat(&token::ModSep) { - return Ok(()); - } - } - } - - fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> { - let ident = self.parse_path_segment_ident()?; - - let is_args_start = |token: &Token| match token.kind { - token::Lt | token::BinOp(token::Shl) | token::OpenDelim(token::Paren) - | token::LArrow => true, - _ => false, - }; - let check_args_start = |this: &mut Self| { - this.expected_tokens.extend_from_slice( - &[TokenType::Token(token::Lt), TokenType::Token(token::OpenDelim(token::Paren))] - ); - is_args_start(&this.token) - }; - - Ok(if style == PathStyle::Type && check_args_start(self) || - style != PathStyle::Mod && self.check(&token::ModSep) - && self.look_ahead(1, |t| is_args_start(t)) { - // We use `style == PathStyle::Expr` to check if this is in a recursion or not. If - // it isn't, then we reset the unmatched angle bracket count as we're about to start - // parsing a new path. - if style == PathStyle::Expr { - self.unmatched_angle_bracket_count = 0; - self.max_angle_bracket_count = 0; - } - - // Generic arguments are found - `<`, `(`, `::<` or `::(`. - self.eat(&token::ModSep); - let lo = self.token.span; - let args = if self.eat_lt() { - // `<'a, T, A = U>` - let (args, constraints) = - self.parse_generic_args_with_leaning_angle_bracket_recovery(style, lo)?; - self.expect_gt()?; - let span = lo.to(self.prev_span); - AngleBracketedArgs { args, constraints, span }.into() + /// See `parse_self_param_with_attrs` to collect attributes. + fn parse_self_param(&mut self) -> PResult<'a, Option> { + // Extract an identifier *after* having confirmed that the token is one. + let expect_self_ident = |this: &mut Self| { + match this.token.kind { + // Preserve hygienic context. + token::Ident(name, _) => { + let span = this.token.span; + this.bump(); + Ident::new(name, span) + } + _ => unreachable!(), + } + }; + // Is `self` `n` tokens ahead? + let is_isolated_self = |this: &Self, n| { + this.is_keyword_ahead(n, &[kw::SelfLower]) + && this.look_ahead(n + 1, |t| t != &token::ModSep) + }; + // Is `mut self` `n` tokens ahead? + let is_isolated_mut_self = |this: &Self, n| { + this.is_keyword_ahead(n, &[kw::Mut]) + && is_isolated_self(this, n + 1) + }; + // Parse `self` or `self: TYPE`. We already know the current token is `self`. + let parse_self_possibly_typed = |this: &mut Self, m| { + let eself_ident = expect_self_ident(this); + let eself_hi = this.prev_span; + let eself = if this.eat(&token::Colon) { + SelfKind::Explicit(this.parse_ty()?, m) } else { - // `(T, U) -> R` - let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?; - let span = lo.to(self.prev_span); - let output = if self.eat(&token::RArrow) { - Some(self.parse_ty_common(false, false, false)?) - } else { - None - }; - ParenthesizedArgs { inputs, output, span }.into() + SelfKind::Value(m) }; - - PathSegment { ident, args, id: ast::DUMMY_NODE_ID } - } else { - // Generic arguments are not found. - PathSegment::from_ident(ident) - }) - } - - crate fn check_lifetime(&mut self) -> bool { - self.expected_tokens.push(TokenType::Lifetime); - self.token.is_lifetime() - } - - /// Parses a single lifetime `'a` or panics. - crate fn expect_lifetime(&mut self) -> Lifetime { - if let Some(ident) = self.token.lifetime() { - let span = self.token.span; - self.bump(); - Lifetime { ident: Ident::new(ident.name, span), id: ast::DUMMY_NODE_ID } - } else { - self.span_bug(self.token.span, "not a lifetime") - } - } - - fn eat_label(&mut self) -> Option

(&self, sp: Span, predicate: P) -> Span where P: for <'r> FnMut(&'r char) -> bool { @@ -693,7 +719,7 @@ impl SourceMap { self.span_until_char(sp, '{') } - /// Returns a new span representing just the start-point of this span + /// Returns a new span representing just the start point of this span. pub fn start_point(&self, sp: Span) -> Span { let pos = sp.lo().0; let width = self.find_width_of_character_at_span(sp, false); @@ -702,7 +728,7 @@ impl SourceMap { sp.with_hi(end_point) } - /// Returns a new span representing just the end-point of this span + /// Returns a new span representing just the end point of this span. pub fn end_point(&self, sp: Span) -> Span { let pos = sp.hi().0; @@ -713,7 +739,7 @@ impl SourceMap { sp.with_lo(end_point) } - /// Returns a new span representing the next character after the end-point of this span + /// Returns a new span representing the next character after the end-point of this span. pub fn next_point(&self, sp: Span) -> Span { let start_of_next_point = sp.hi().0; @@ -816,7 +842,7 @@ impl SourceMap { None } - /// For a global BytePos compute the local offset within the containing SourceFile + /// For a global `BytePos`, computes the local offset within the containing `SourceFile`. pub fn lookup_byte_offset(&self, bpos: BytePos) -> SourceFileAndBytePos { let idx = self.lookup_source_file_idx(bpos); let sf = (*self.files.borrow().source_files)[idx].clone(); @@ -824,22 +850,22 @@ impl SourceMap { SourceFileAndBytePos {sf, pos: offset} } - /// Converts an absolute BytePos to a CharPos relative to the source_file. + /// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`. pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos { let idx = self.lookup_source_file_idx(bpos); let map = &(*self.files.borrow().source_files)[idx]; - // The number of extra bytes due to multibyte chars in the SourceFile + // The number of extra bytes due to multibyte chars in the `SourceFile`. let mut total_extra_bytes = 0; for mbc in map.multibyte_chars.iter() { debug!("{}-byte char at {:?}", mbc.bytes, mbc.pos); if mbc.pos < bpos { - // every character is at least one byte, so we only + // Every character is at least one byte, so we only // count the actual extra bytes. total_extra_bytes += mbc.bytes as u32 - 1; // We should never see a byte position in the middle of a - // character + // character. assert!(bpos.to_u32() >= mbc.pos.to_u32() + mbc.bytes as u32); } else { break; @@ -850,13 +876,13 @@ impl SourceMap { CharPos(bpos.to_usize() - map.start_pos.to_usize() - total_extra_bytes as usize) } - // Return the index of the source_file (in self.files) which contains pos. + // Returns the index of the `SourceFile` (in `self.files`) that contains `pos`. pub fn lookup_source_file_idx(&self, pos: BytePos) -> usize { let files = self.files.borrow(); let files = &files.source_files; let count = files.len(); - // Binary search for the source_file. + // Binary search for the `SourceFile`. let mut a = 0; let mut b = count; while b - a > 1 { @@ -887,8 +913,8 @@ impl SourceMap { }).ok() } - /// Take the span of a type parameter in a function signature and try to generate a span for the - /// function name (with generics) and a new snippet for this span with the pointed type + /// Takes the span of a type parameter in a function signature and try to generate a span for + /// the function name (with generics) and a new snippet for this span with the pointed type /// parameter as a new local type parameter. /// /// For instance: @@ -904,18 +930,18 @@ impl SourceMap { /// /// Attention: The method used is very fragile since it essentially duplicates the work of the /// parser. If you need to use this function or something similar, please consider updating the - /// source_map functions and this function to something more robust. + /// `SourceMap` functions and this function to something more robust. pub fn generate_local_type_param_snippet(&self, span: Span) -> Option<(Span, String)> { // Try to extend the span to the previous "fn" keyword to retrieve the function - // signature + // signature. let sugg_span = self.span_extend_to_prev_str(span, "fn", false); if sugg_span != span { if let Ok(snippet) = self.span_to_snippet(sugg_span) { - // Consume the function name + // Consume the function name. let mut offset = snippet.find(|c: char| !c.is_alphanumeric() && c != '_') .expect("no label after fn"); - // Consume the generics part of the function signature + // Consume the generics part of the function signature. let mut bracket_counter = 0; let mut last_char = None; for c in snippet[offset..].chars() { @@ -929,11 +955,11 @@ impl SourceMap { last_char = Some(c); } - // Adjust the suggestion span to encompass the function name with its generics + // Adjust the suggestion span to encompass the function name with its generics. let sugg_span = sugg_span.with_hi(BytePos(sugg_span.lo().0 + offset as u32)); // Prepare the new suggested snippet to append the type parameter that triggered - // the error in the generics of the function signature + // the error in the generics of the function signature. let mut new_snippet = if last_char == Some('>') { format!("{}, ", &snippet[..(offset - '>'.len_utf8())]) } else { diff --git a/src/libsyntax/source_map/tests.rs b/src/libsyntax/source_map/tests.rs index 427e86b56e12b..15254336bbfa5 100644 --- a/src/libsyntax/source_map/tests.rs +++ b/src/libsyntax/source_map/tests.rs @@ -4,18 +4,24 @@ use rustc_data_structures::sync::Lrc; fn init_source_map() -> SourceMap { let sm = SourceMap::new(FilePathMapping::empty()); - sm.new_source_file(PathBuf::from("blork.rs").into(), - "first line.\nsecond line".to_string()); - sm.new_source_file(PathBuf::from("empty.rs").into(), - String::new()); - sm.new_source_file(PathBuf::from("blork2.rs").into(), - "first line.\nsecond line".to_string()); + sm.new_source_file( + PathBuf::from("blork.rs").into(), + "first line.\nsecond line".to_string(), + ); + sm.new_source_file( + PathBuf::from("empty.rs").into(), + String::new(), + ); + sm.new_source_file( + PathBuf::from("blork2.rs").into(), + "first line.\nsecond line".to_string(), + ); sm } +/// Tests `lookup_byte_offset`. #[test] fn t3() { - // Test lookup_byte_offset let sm = init_source_map(); let srcfbp1 = sm.lookup_byte_offset(BytePos(23)); @@ -31,9 +37,9 @@ fn t3() { assert_eq!(srcfbp2.pos, BytePos(0)); } +/// Tests `bytepos_to_file_charpos`. #[test] fn t4() { - // Test bytepos_to_file_charpos let sm = init_source_map(); let cp1 = sm.bytepos_to_file_charpos(BytePos(22)); @@ -43,9 +49,9 @@ fn t4() { assert_eq!(cp2, CharPos(0)); } +/// Tests zero-length `SourceFile`s. #[test] fn t5() { - // Test zero-length source_files. let sm = init_source_map(); let loc1 = sm.lookup_char_pos(BytePos(22)); @@ -61,7 +67,7 @@ fn t5() { fn init_source_map_mbc() -> SourceMap { let sm = SourceMap::new(FilePathMapping::empty()); - // € is a three byte utf8 char. + // "€" is a three-byte UTF8 char. sm.new_source_file(PathBuf::from("blork.rs").into(), "fir€st €€€€ line.\nsecond line".to_string()); sm.new_source_file(PathBuf::from("blork2.rs").into(), @@ -69,9 +75,9 @@ fn init_source_map_mbc() -> SourceMap { sm } +/// Tests `bytepos_to_file_charpos` in the presence of multi-byte chars. #[test] fn t6() { - // Test bytepos_to_file_charpos in the presence of multi-byte chars let sm = init_source_map_mbc(); let cp1 = sm.bytepos_to_file_charpos(BytePos(3)); @@ -87,11 +93,11 @@ fn t6() { assert_eq!(cp4, CharPos(15)); } +/// Test `span_to_lines` for a span ending at the end of a `SourceFile`. #[test] fn t7() { - // Test span_to_lines for a span ending at the end of source_file let sm = init_source_map(); - let span = Span::new(BytePos(12), BytePos(23), NO_EXPANSION); + let span = Span::with_root_ctxt(BytePos(12), BytePos(23)); let file_lines = sm.span_to_lines(span).unwrap(); assert_eq!(file_lines.file.name, PathBuf::from("blork.rs").into()); @@ -107,10 +113,10 @@ fn span_from_selection(input: &str, selection: &str) -> Span { assert_eq!(input.len(), selection.len()); let left_index = selection.find('~').unwrap() as u32; let right_index = selection.rfind('~').map(|x|x as u32).unwrap_or(left_index); - Span::new(BytePos(left_index), BytePos(right_index + 1), NO_EXPANSION) + Span::with_root_ctxt(BytePos(left_index), BytePos(right_index + 1)) } -/// Tests span_to_snippet and span_to_lines for a span converting 3 +/// Tests `span_to_snippet` and `span_to_lines` for a span converting 3 /// lines in the middle of a file. #[test] fn span_to_snippet_and_lines_spanning_multiple_lines() { @@ -120,10 +126,10 @@ fn span_to_snippet_and_lines_spanning_multiple_lines() { sm.new_source_file(Path::new("blork.rs").to_owned().into(), inputtext.to_string()); let span = span_from_selection(inputtext, selection); - // check that we are extracting the text we thought we were extracting + // Check that we are extracting the text we thought we were extracting. assert_eq!(&sm.span_to_snippet(span).unwrap(), "BB\nCCC\nDDDDD"); - // check that span_to_lines gives us the complete result with the lines/cols we expected + // Check that span_to_lines gives us the complete result with the lines/cols we expected. let lines = sm.span_to_lines(span).unwrap(); let expected = vec![ LineInfo { line_index: 1, start_col: CharPos(4), end_col: CharPos(6) }, @@ -133,27 +139,27 @@ fn span_to_snippet_and_lines_spanning_multiple_lines() { assert_eq!(lines.lines, expected); } +/// Test span_to_snippet for a span ending at the end of a `SourceFile`. #[test] fn t8() { - // Test span_to_snippet for a span ending at the end of source_file let sm = init_source_map(); - let span = Span::new(BytePos(12), BytePos(23), NO_EXPANSION); + let span = Span::with_root_ctxt(BytePos(12), BytePos(23)); let snippet = sm.span_to_snippet(span); assert_eq!(snippet, Ok("second line".to_string())); } +/// Test `span_to_str` for a span ending at the end of a `SourceFile`. #[test] fn t9() { - // Test span_to_str for a span ending at the end of source_file let sm = init_source_map(); - let span = Span::new(BytePos(12), BytePos(23), NO_EXPANSION); + let span = Span::with_root_ctxt(BytePos(12), BytePos(23)); let sstr = sm.span_to_string(span); assert_eq!(sstr, "blork.rs:2:1: 2:12"); } -/// Tests failing to merge two spans on different lines +/// Tests failing to merge two spans on different lines. #[test] fn span_merging_fail() { let sm = SourceMap::new(FilePathMapping::empty()); @@ -167,44 +173,46 @@ fn span_merging_fail() { assert!(sm.merge_spans(span1, span2).is_none()); } -/// Returns the span corresponding to the `n`th occurrence of -/// `substring` in `source_text`. +/// Returns the span corresponding to the `n`th occurrence of `substring` in `source_text`. trait SourceMapExtension { - fn span_substr(&self, - file: &Lrc, - source_text: &str, - substring: &str, - n: usize) - -> Span; + fn span_substr( + &self, + file: &Lrc, + source_text: &str, + substring: &str, + n: usize, + ) -> Span; } impl SourceMapExtension for SourceMap { - fn span_substr(&self, - file: &Lrc, - source_text: &str, - substring: &str, - n: usize) - -> Span - { - println!("span_substr(file={:?}/{:?}, substring={:?}, n={})", - file.name, file.start_pos, substring, n); + fn span_substr( + &self, + file: &Lrc, + source_text: &str, + substring: &str, + n: usize, + ) -> Span { + println!( + "span_substr(file={:?}/{:?}, substring={:?}, n={})", + file.name, file.start_pos, substring, n + ); let mut i = 0; let mut hi = 0; loop { let offset = source_text[hi..].find(substring).unwrap_or_else(|| { - panic!("source_text `{}` does not have {} occurrences of `{}`, only {}", - source_text, n, substring, i); + panic!( + "source_text `{}` does not have {} occurrences of `{}`, only {}", + source_text, n, substring, i + ); }); let lo = hi + offset; hi = lo + substring.len(); if i == n { - let span = Span::new( + let span = Span::with_root_ctxt( BytePos(lo as u32 + file.start_pos.0), BytePos(hi as u32 + file.start_pos.0), - NO_EXPANSION, ); - assert_eq!(&self.span_to_snippet(span).unwrap()[..], - substring); + assert_eq!(&self.span_to_snippet(span).unwrap()[..], substring); return span; } i += 1; diff --git a/src/libsyntax/tests.rs b/src/libsyntax/tests.rs index cff034fdeb1e3..f510ac9273d09 100644 --- a/src/libsyntax/tests.rs +++ b/src/libsyntax/tests.rs @@ -9,7 +9,7 @@ use crate::with_default_globals; use errors::emitter::EmitterWriter; use errors::Handler; use rustc_data_structures::sync::Lrc; -use syntax_pos::{BytePos, NO_EXPANSION, Span, MultiSpan}; +use syntax_pos::{BytePos, Span, MultiSpan}; use std::io; use std::io::prelude::*; @@ -18,7 +18,7 @@ use std::path::{Path, PathBuf}; use std::str; use std::sync::{Arc, Mutex}; -/// Map string to parser (via tts) +/// Map string to parser (via tts). fn string_to_parser(ps: &ParseSess, source_str: String) -> Parser<'_> { new_parser_from_source_str(ps, PathBuf::from("bogofile").into(), source_str) } @@ -32,7 +32,7 @@ crate fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) x } -/// Map a string to tts, using a made-up filename: +/// Maps a string to tts, using a made-up filename. crate fn string_to_stream(source_str: String) -> TokenStream { let ps = ParseSess::new(FilePathMapping::empty()); source_file_to_stream( @@ -42,7 +42,7 @@ crate fn string_to_stream(source_str: String) -> TokenStream { ), None).0 } -/// Parse a string, return a crate. +/// Parses a string, returns a crate. crate fn string_to_crate(source_str : String) -> ast::Crate { let ps = ParseSess::new(FilePathMapping::empty()); with_error_checking_parse(source_str, &ps, |p| { @@ -63,8 +63,8 @@ crate fn matches_codepattern(a : &str, b : &str) -> bool { (None, None) => return true, (None, _) => return false, (Some(&a), None) => { - if is_pattern_whitespace(a) { - break // trailing whitespace check is out of loop for borrowck + if rustc_lexer::is_whitespace(a) { + break // Trailing whitespace check is out of loop for borrowck. } else { return false } @@ -72,12 +72,12 @@ crate fn matches_codepattern(a : &str, b : &str) -> bool { (Some(&a), Some(&b)) => (a, b) }; - if is_pattern_whitespace(a) && is_pattern_whitespace(b) { - // skip whitespace for a and b + if rustc_lexer::is_whitespace(a) && rustc_lexer::is_whitespace(b) { + // Skip whitespace for `a` and `b`. scan_for_non_ws_or_end(&mut a_iter); scan_for_non_ws_or_end(&mut b_iter); - } else if is_pattern_whitespace(a) { - // skip whitespace for a + } else if rustc_lexer::is_whitespace(a) { + // Skip whitespace for `a`. scan_for_non_ws_or_end(&mut a_iter); } else if a == b { a_iter.next(); @@ -87,22 +87,18 @@ crate fn matches_codepattern(a : &str, b : &str) -> bool { } } - // check if a has *only* trailing whitespace - a_iter.all(is_pattern_whitespace) + // Check if a has *only* trailing whitespace. + a_iter.all(rustc_lexer::is_whitespace) } -/// Advances the given peekable `Iterator` until it reaches a non-whitespace character +/// Advances the given peekable `Iterator` until it reaches a non-whitespace character. fn scan_for_non_ws_or_end>(iter: &mut Peekable) { - while iter.peek().copied().map(|c| is_pattern_whitespace(c)) == Some(true) { + while iter.peek().copied().map(|c| rustc_lexer::is_whitespace(c)) == Some(true) { iter.next(); } } -fn is_pattern_whitespace(c: char) -> bool { - rustc_lexer::character_properties::is_whitespace(c) -} - -/// Identify a position in the text by the Nth occurrence of a string. +/// Identifies a position in the text by the n'th occurrence of a string. struct Position { string: &'static str, count: usize, @@ -144,11 +140,15 @@ fn test_harness(file_text: &str, span_labels: Vec, expected_output: & println!("text: {:?}", source_map.span_to_snippet(span)); } - let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }), - Some(source_map.clone()), - false, - false, - false); + let emitter = EmitterWriter::new( + Box::new(Shared { data: output.clone() }), + Some(source_map.clone()), + false, + false, + false, + None, + false, + ); let handler = Handler::with_emitter(true, None, Box::new(emitter)); handler.span_err(msp, "foo"); @@ -169,7 +169,7 @@ fn make_span(file_text: &str, start: &Position, end: &Position) -> Span { let start = make_pos(file_text, start); let end = make_pos(file_text, end) + end.string.len(); // just after matching thing ends assert!(start <= end); - Span::new(BytePos(start as u32), BytePos(end as u32), NO_EXPANSION) + Span::with_root_ctxt(BytePos(start as u32), BytePos(end as u32)) } fn make_pos(file_text: &str, pos: &Position) -> usize { diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 6ff8898fe2162..bef12ed4fadaf 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -6,27 +6,23 @@ //! //! ## Ownership //! -//! `TokenStreams` are persistent data structures constructed as ropes with reference +//! `TokenStream`s are persistent data structures constructed as ropes with reference //! counted-children. In general, this means that calling an operation on a `TokenStream` //! (such as `slice`) produces an entirely new `TokenStream` from the borrowed reference to //! the original. This essentially coerces `TokenStream`s into 'views' of their subparts, //! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking //! ownership of the original. -use crate::ext::base; -use crate::ext::tt::{macro_parser, quoted}; -use crate::parse::Directory; use crate::parse::token::{self, DelimToken, Token, TokenKind}; use crate::print::pprust; -use syntax_pos::{BytePos, ExpnId, Span, DUMMY_SP}; +use syntax_pos::{BytePos, Span, DUMMY_SP}; #[cfg(target_arch = "x86_64")] use rustc_data_structures::static_assert_size; use rustc_data_structures::sync::Lrc; use rustc_serialize::{Decoder, Decodable, Encoder, Encodable}; use smallvec::{SmallVec, smallvec}; -use std::borrow::Cow; use std::{fmt, iter, mem}; #[cfg(test)] @@ -63,17 +59,6 @@ where {} impl TokenTree { - /// Use this token tree as a matcher to parse given tts. - pub fn parse(cx: &base::ExtCtxt<'_>, mtch: &[quoted::TokenTree], tts: TokenStream) - -> macro_parser::NamedParseResult { - // `None` is because we're not interpolating - let directory = Directory { - path: Cow::from(cx.current_expansion.module.directory.as_path()), - ownership: cx.current_expansion.directory_ownership, - }; - macro_parser::parse(cx.parse_sess(), tts, mtch, Some(directory), true) - } - /// Checks if this TokenTree is equal to the other, regardless of span information. pub fn eq_unspanned(&self, other: &TokenTree) -> bool { match (self, other) { @@ -147,9 +132,8 @@ impl TokenTree { } } -/// # Token Streams -/// /// A `TokenStream` is an abstract sequence of tokens, organized into `TokenTree`s. +/// /// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s /// instead of a representation of the abstract syntax tree. /// Today's `TokenTree`s can still contain AST via `token::Interpolated` for back-compat. @@ -265,20 +249,47 @@ impl TokenStream { 0 => TokenStream::empty(), 1 => streams.pop().unwrap(), _ => { - // rust-lang/rust#57735: pre-allocate vector to avoid - // quadratic blow-up due to on-the-fly reallocations. - let tree_count = streams.iter() - .map(|ts| match &ts.0 { None => 0, Some(s) => s.len() }) + // We are going to extend the first stream in `streams` with + // the elements from the subsequent streams. This requires + // using `make_mut()` on the first stream, and in practice this + // doesn't cause cloning 99.9% of the time. + // + // One very common use case is when `streams` has two elements, + // where the first stream has any number of elements within + // (often 1, but sometimes many more) and the second stream has + // a single element within. + + // Determine how much the first stream will be extended. + // Needed to avoid quadratic blow up from on-the-fly + // reallocations (#57735). + let num_appends = streams.iter() + .skip(1) + .map(|ts| ts.len()) .sum(); - let mut vec = Vec::with_capacity(tree_count); - for stream in streams { - match stream.0 { - None => {}, - Some(stream2) => vec.extend(stream2.iter().cloned()), + // Get the first stream. If it's `None`, create an empty + // stream. + let mut iter = streams.drain(); + let mut first_stream_lrc = match iter.next().unwrap().0 { + Some(first_stream_lrc) => first_stream_lrc, + None => Lrc::new(vec![]), + }; + + // Append the elements to the first stream, after reserving + // space for them. + let first_vec_mut = Lrc::make_mut(&mut first_stream_lrc); + first_vec_mut.reserve(num_appends); + for stream in iter { + if let Some(stream) = stream.0 { + first_vec_mut.extend(stream.iter().cloned()); } } - TokenStream::new(vec) + + // Create the final `TokenStream`. + match first_vec_mut.len() { + 0 => TokenStream(None), + _ => TokenStream(Some(first_stream_lrc)), + } } } } @@ -304,7 +315,7 @@ impl TokenStream { Cursor::new(self) } - /// Compares two TokenStreams, checking equality without regarding span information. + /// Compares two `TokenStream`s, checking equality without regarding span information. pub fn eq_unspanned(&self, other: &TokenStream) -> bool { let mut t1 = self.trees(); let mut t2 = other.trees(); @@ -379,25 +390,6 @@ impl TokenStream { .collect()) })) } - - fn first_tree_and_joint(&self) -> Option { - self.0.as_ref().map(|stream| { - stream.first().unwrap().clone() - }) - } - - fn last_tree_if_joint(&self) -> Option { - match self.0 { - None => None, - Some(ref stream) => { - if let (tree, Joint) = stream.last().unwrap() { - Some(tree.clone()) - } else { - None - } - } - } - } } // 99.5%+ of the time we have 1 or 2 elements in this vector. @@ -410,18 +402,49 @@ impl TokenStreamBuilder { } pub fn push>(&mut self, stream: T) { - let stream = stream.into(); - let last_tree_if_joint = self.0.last().and_then(TokenStream::last_tree_if_joint); - if let Some(TokenTree::Token(last_token)) = last_tree_if_joint { - if let Some((TokenTree::Token(token), is_joint)) = stream.first_tree_and_joint() { - if let Some(glued_tok) = last_token.glue(token) { - let last_stream = self.0.pop().unwrap(); - self.push_all_but_last_tree(&last_stream); - let glued_tt = TokenTree::Token(glued_tok); - let glued_tokenstream = TokenStream::new(vec![(glued_tt, is_joint)]); - self.0.push(glued_tokenstream); - self.push_all_but_first_tree(&stream); - return + let mut stream = stream.into(); + + // If `self` is not empty and the last tree within the last stream is a + // token tree marked with `Joint`... + if let Some(TokenStream(Some(ref mut last_stream_lrc))) = self.0.last_mut() { + if let Some((TokenTree::Token(last_token), Joint)) = last_stream_lrc.last() { + + // ...and `stream` is not empty and the first tree within it is + // a token tree... + if let TokenStream(Some(ref mut stream_lrc)) = stream { + if let Some((TokenTree::Token(token), is_joint)) = stream_lrc.first() { + + // ...and the two tokens can be glued together... + if let Some(glued_tok) = last_token.glue(&token) { + + // ...then do so, by overwriting the last token + // tree in `self` and removing the first token tree + // from `stream`. This requires using `make_mut()` + // on the last stream in `self` and on `stream`, + // and in practice this doesn't cause cloning 99.9% + // of the time. + + // Overwrite the last token tree with the merged + // token. + let last_vec_mut = Lrc::make_mut(last_stream_lrc); + *last_vec_mut.last_mut().unwrap() = + (TokenTree::Token(glued_tok), *is_joint); + + // Remove the first token tree from `stream`. (This + // is almost always the only tree in `stream`.) + let stream_vec_mut = Lrc::make_mut(stream_lrc); + stream_vec_mut.remove(0); + + // Don't push `stream` if it's empty -- that could + // block subsequent token gluing, by getting + // between two token trees that should be glued + // together. + if !stream.is_empty() { + self.0.push(stream); + } + return; + } + } } } } @@ -431,26 +454,6 @@ impl TokenStreamBuilder { pub fn build(self) -> TokenStream { TokenStream::from_streams(self.0) } - - fn push_all_but_last_tree(&mut self, stream: &TokenStream) { - if let Some(ref streams) = stream.0 { - let len = streams.len(); - match len { - 1 => {} - _ => self.0.push(TokenStream(Some(Lrc::new(streams[0 .. len - 1].to_vec())))), - } - } - } - - fn push_all_but_first_tree(&mut self, stream: &TokenStream) { - if let Some(ref streams) = stream.0 { - let len = streams.len(); - match len { - 1 => {} - _ => self.0.push(TokenStream(Some(Lrc::new(streams[1 .. len].to_vec())))), - } - } - } } #[derive(Clone)] @@ -506,7 +509,7 @@ impl Cursor { impl fmt::Display for TokenStream { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&pprust::tokens_to_string(self.clone())) + f.write_str(&pprust::tts_to_string(self.clone())) } } @@ -547,11 +550,4 @@ impl DelimSpan { pub fn entire(self) -> Span { self.open.with_hi(self.close.hi()) } - - pub fn apply_mark(self, expn_id: ExpnId) -> Self { - DelimSpan { - open: self.open.apply_mark(expn_id), - close: self.close.apply_mark(expn_id), - } - } } diff --git a/src/libsyntax/tokenstream/tests.rs b/src/libsyntax/tokenstream/tests.rs index 72e22a49876e8..5017e5f5424c1 100644 --- a/src/libsyntax/tokenstream/tests.rs +++ b/src/libsyntax/tokenstream/tests.rs @@ -3,14 +3,14 @@ use super::*; use crate::ast::Name; use crate::with_default_globals; use crate::tests::string_to_stream; -use syntax_pos::{Span, BytePos, NO_EXPANSION}; +use syntax_pos::{Span, BytePos}; fn string_to_ts(string: &str) -> TokenStream { string_to_stream(string.to_owned()) } fn sp(a: u32, b: u32) -> Span { - Span::new(BytePos(a), BytePos(b), NO_EXPANSION) + Span::with_root_ctxt(BytePos(a), BytePos(b)) } #[test] diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs index f17eb3b39432e..a64fec7096132 100644 --- a/src/libsyntax/util/node_count.rs +++ b/src/libsyntax/util/node_count.rs @@ -93,8 +93,7 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_poly_trait_ref(self, t, m) } - fn visit_variant_data(&mut self, s: &VariantData, _: Ident, - _: &Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, s: &VariantData) { self.count += 1; walk_struct_def(self, s) } @@ -107,9 +106,9 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_enum_def(self, enum_definition, generics, item_id) } - fn visit_variant(&mut self, v: &Variant, g: &Generics, item_id: NodeId) { + fn visit_variant(&mut self, v: &Variant) { self.count += 1; - walk_variant(self, v, g, item_id) + walk_variant(self, v) } fn visit_lifetime(&mut self, lifetime: &Lifetime) { self.count += 1; diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs index d71358f45c470..982755e868054 100644 --- a/src/libsyntax/util/parser.rs +++ b/src/libsyntax/util/parser.rs @@ -69,7 +69,7 @@ pub enum Fixity { impl AssocOp { /// Creates a new AssocOP from a token - pub fn from_token(t: &Token) -> Option { + crate fn from_token(t: &Token) -> Option { use AssocOp::*; match t.kind { token::BinOpEq(k) => Some(AssignOp(k)), @@ -97,6 +97,8 @@ impl AssocOp { // DotDotDot is no longer supported, but we need some way to display the error token::DotDotDot => Some(DotDotEq), token::Colon => Some(Colon), + // `<-` should probably be `< -` + token::LArrow => Some(Less), _ if t.is_keyword(kw::As) => Some(As), _ => None } @@ -373,7 +375,7 @@ crate fn needs_par_as_let_scrutinee(order: i8) -> bool { /// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and /// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not. pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool { - match value.node { + match value.kind { ast::ExprKind::Struct(..) => true, ast::ExprKind::Assign(ref lhs, ref rhs) | diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 596c5b46b986f..a36783e2b642d 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -21,13 +21,13 @@ use syntax_pos::Span; #[derive(Copy, Clone)] pub enum FnKind<'a> { - /// fn foo() or extern "Abi" fn foo() + /// E.g., `fn foo()` or `extern "Abi" fn foo()`. ItemFn(Ident, &'a FnHeader, &'a Visibility, &'a Block), - /// fn foo(&self) + /// E.g., `fn foo(&self)`. Method(Ident, &'a MethodSig, Option<&'a Visibility>, &'a Block), - /// |x, y| body + /// E.g., `|x, y| body`. Closure(&'a Expr), } @@ -41,7 +41,7 @@ impl<'a> FnKind<'a> { } } -/// Each method of the Visitor trait is a hook to be potentially +/// Each method of the `Visitor` trait is a hook to be potentially /// overridden. Each method's default implementation recursively visits /// the substructure of the input via the corresponding `walk` method; /// e.g., the `visit_mod` method by default calls `visit::walk_mod`. @@ -66,7 +66,7 @@ pub trait Visitor<'ast>: Sized { fn visit_local(&mut self, l: &'ast Local) { walk_local(self, l) } fn visit_block(&mut self, b: &'ast Block) { walk_block(self, b) } fn visit_stmt(&mut self, s: &'ast Stmt) { walk_stmt(self, s) } - fn visit_arg(&mut self, arg: &'ast Arg) { walk_arg(self, arg) } + fn visit_param(&mut self, param: &'ast Param) { walk_param(self, param) } fn visit_arm(&mut self, a: &'ast Arm) { walk_arm(self, a) } fn visit_pat(&mut self, p: &'ast Pat) { walk_pat(self, p) } fn visit_anon_const(&mut self, c: &'ast AnonConst) { walk_anon_const(self, c) } @@ -92,8 +92,7 @@ pub trait Visitor<'ast>: Sized { fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) { walk_poly_trait_ref(self, t, m) } - fn visit_variant_data(&mut self, s: &'ast VariantData, _: Ident, - _: &'ast Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, s: &'ast VariantData) { walk_struct_def(self, s) } fn visit_struct_field(&mut self, s: &'ast StructField) { walk_struct_field(self, s) } @@ -101,8 +100,8 @@ pub trait Visitor<'ast>: Sized { generics: &'ast Generics, item_id: NodeId, _: Span) { walk_enum_def(self, enum_definition, generics, item_id) } - fn visit_variant(&mut self, v: &'ast Variant, g: &'ast Generics, item_id: NodeId) { - walk_variant(self, v, g, item_id) + fn visit_variant(&mut self, v: &'ast Variant) { + walk_variant(self, v) } fn visit_label(&mut self, label: &'ast Label) { walk_label(self, label) @@ -163,6 +162,12 @@ pub trait Visitor<'ast>: Sized { fn visit_fn_header(&mut self, _header: &'ast FnHeader) { // Nothing to do } + fn visit_field(&mut self, f: &'ast Field) { + walk_field(self, f) + } + fn visit_field_pattern(&mut self, fp: &'ast FieldPat) { + walk_field_pattern(self, fp) + } } #[macro_export] @@ -225,7 +230,7 @@ pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitR pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { visitor.visit_vis(&item.vis); visitor.visit_ident(item.ident); - match item.node { + match item.kind { ItemKind::ExternCrate(orig_name) => { if let Some(orig_name) = orig_name { visitor.visit_name(item.span, orig_name); @@ -280,8 +285,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ItemKind::Struct(ref struct_definition, ref generics) | ItemKind::Union(ref struct_definition, ref generics) => { visitor.visit_generics(generics); - visitor.visit_variant_data(struct_definition, item.ident, - generics, item.id, item.span); + visitor.visit_variant_data(struct_definition); } ItemKind::Trait(.., ref generics, ref bounds, ref methods) => { visitor.visit_generics(generics); @@ -298,28 +302,38 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { walk_list!(visitor, visit_attribute, &item.attrs); } -pub fn walk_enum_def<'a, V: Visitor<'a>>(visitor: &mut V, - enum_definition: &'a EnumDef, - generics: &'a Generics, - item_id: NodeId) { - walk_list!(visitor, visit_variant, &enum_definition.variants, generics, item_id); +pub fn walk_enum_def<'a, V: Visitor<'a>>( + visitor: &mut V, + enum_definition: &'a EnumDef, + _: &'a Generics, + _: NodeId, +) { + walk_list!(visitor, visit_variant, &enum_definition.variants); } -pub fn walk_variant<'a, V>(visitor: &mut V, - variant: &'a Variant, - generics: &'a Generics, - item_id: NodeId) +pub fn walk_variant<'a, V: Visitor<'a>>(visitor: &mut V, variant: &'a Variant) where V: Visitor<'a>, { - visitor.visit_ident(variant.node.ident); - visitor.visit_variant_data(&variant.node.data, variant.node.ident, - generics, item_id, variant.span); - walk_list!(visitor, visit_anon_const, &variant.node.disr_expr); - walk_list!(visitor, visit_attribute, &variant.node.attrs); + visitor.visit_ident(variant.ident); + visitor.visit_variant_data(&variant.data); + walk_list!(visitor, visit_anon_const, &variant.disr_expr); + walk_list!(visitor, visit_attribute, &variant.attrs); +} + +pub fn walk_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a Field) { + visitor.visit_expr(&f.expr); + visitor.visit_ident(f.ident); + walk_list!(visitor, visit_attribute, f.attrs.iter()); +} + +pub fn walk_field_pattern<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a FieldPat) { + visitor.visit_ident(fp.ident); + visitor.visit_pat(&fp.pat); + walk_list!(visitor, visit_attribute, fp.attrs.iter()); } pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { - match typ.node { + match typ.kind { TyKind::Slice(ref ty) | TyKind::Paren(ref ty) => { visitor.visit_ty(ty) } @@ -330,7 +344,6 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { walk_list!(visitor, visit_lifetime, opt_lifetime); visitor.visit_ty(&mutable_type.ty) } - TyKind::Never | TyKind::CVarArgs => {} TyKind::Tup(ref tuple_element_types) => { walk_list!(visitor, visit_ty, tuple_element_types); } @@ -359,6 +372,8 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { TyKind::Mac(ref mac) => { visitor.visit_mac(mac) } + TyKind::Never | + TyKind::CVarArgs => {} } } @@ -374,7 +389,7 @@ pub fn walk_use_tree<'a, V: Visitor<'a>>( visitor.visit_path(&use_tree.prefix, id); match use_tree.kind { UseTreeKind::Simple(rename, ..) => { - // the extra IDs are handled during HIR lowering + // The extra IDs are handled during HIR lowering. if let Some(rename) = rename { visitor.visit_ident(rename); } @@ -428,7 +443,7 @@ pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(visitor: &mut V, } pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { - match pattern.node { + match pattern.kind { PatKind::TupleStruct(ref path, ref elems) => { visitor.visit_path(path, pattern.id); walk_list!(visitor, visit_pat, elems); @@ -441,14 +456,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { } PatKind::Struct(ref path, ref fields, _) => { visitor.visit_path(path, pattern.id); - for field in fields { - walk_list!(visitor, visit_attribute, field.node.attrs.iter()); - visitor.visit_ident(field.node.ident); - visitor.visit_pat(&field.node.pat) - } - } - PatKind::Tuple(ref elems) => { - walk_list!(visitor, visit_pat, elems); + walk_list!(visitor, visit_field_pattern, fields); } PatKind::Box(ref subpattern) | PatKind::Ref(ref subpattern, _) | @@ -465,7 +473,9 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { visitor.visit_expr(upper_bound); } PatKind::Wild | PatKind::Rest => {}, - PatKind::Slice(ref elems) => { + PatKind::Tuple(ref elems) + | PatKind::Slice(ref elems) + | PatKind::Or(ref elems) => { walk_list!(visitor, visit_pat, elems); } PatKind::Mac(ref mac) => visitor.visit_mac(mac), @@ -476,7 +486,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, foreign_item: &'a visitor.visit_vis(&foreign_item.vis); visitor.visit_ident(foreign_item.ident); - match foreign_item.node { + match foreign_item.kind { ForeignItemKind::Fn(ref function_declaration, ref generics) => { walk_fn_decl(visitor, function_declaration); visitor.visit_generics(generics) @@ -548,8 +558,8 @@ pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FunctionR } pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &'a FnDecl) { - for arg in &function_declaration.inputs { - visitor.visit_arg(arg); + for param in &function_declaration.inputs { + visitor.visit_param(param); } visitor.visit_fn_ret_ty(&function_declaration.output); } @@ -579,7 +589,7 @@ pub fn walk_trait_item<'a, V: Visitor<'a>>(visitor: &mut V, trait_item: &'a Trai visitor.visit_ident(trait_item.ident); walk_list!(visitor, visit_attribute, &trait_item.attrs); visitor.visit_generics(&trait_item.generics); - match trait_item.node { + match trait_item.kind { TraitItemKind::Const(ref ty, ref default) => { visitor.visit_ty(ty); walk_list!(visitor, visit_expr, default); @@ -607,7 +617,7 @@ pub fn walk_impl_item<'a, V: Visitor<'a>>(visitor: &mut V, impl_item: &'a ImplIt visitor.visit_ident(impl_item.ident); walk_list!(visitor, visit_attribute, &impl_item.attrs); visitor.visit_generics(&impl_item.generics); - match impl_item.node { + match impl_item.kind { ImplItemKind::Const(ref ty, ref expr) => { visitor.visit_ty(ty); visitor.visit_expr(expr); @@ -646,7 +656,7 @@ pub fn walk_block<'a, V: Visitor<'a>>(visitor: &mut V, block: &'a Block) { } pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) { - match statement.node { + match statement.kind { StmtKind::Local(ref local) => visitor.visit_local(local), StmtKind::Item(ref item) => visitor.visit_item(item), StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => { @@ -663,7 +673,7 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) { } pub fn walk_mac<'a, V: Visitor<'a>>(visitor: &mut V, mac: &'a Mac) { - visitor.visit_path(&mac.node.path, DUMMY_NODE_ID); + visitor.visit_path(&mac.path, DUMMY_NODE_ID); } pub fn walk_anon_const<'a, V: Visitor<'a>>(visitor: &mut V, constant: &'a AnonConst) { @@ -671,10 +681,9 @@ pub fn walk_anon_const<'a, V: Visitor<'a>>(visitor: &mut V, constant: &'a AnonCo } pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { - for attr in expression.attrs.iter() { - visitor.visit_attribute(attr); - } - match expression.node { + walk_list!(visitor, visit_attribute, expression.attrs.iter()); + + match expression.kind { ExprKind::Box(ref subexpression) => { visitor.visit_expr(subexpression) } @@ -687,11 +696,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { } ExprKind::Struct(ref path, ref fields, ref optional_base) => { visitor.visit_path(path, expression.id); - for field in fields { - walk_list!(visitor, visit_attribute, field.attrs.iter()); - visitor.visit_ident(field.ident); - visitor.visit_expr(&field.expr) - } + walk_list!(visitor, visit_field, fields); walk_list!(visitor, visit_expr, optional_base); } ExprKind::Tup(ref subexpressions) => { @@ -716,8 +721,8 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr(subexpression); visitor.visit_ty(typ) } - ExprKind::Let(ref pats, ref scrutinee) => { - walk_list!(visitor, visit_pat, pats); + ExprKind::Let(ref pat, ref scrutinee) => { + visitor.visit_pat(pat); visitor.visit_expr(scrutinee); } ExprKind::If(ref head_expression, ref if_block, ref optional_else) => { @@ -821,17 +826,15 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr_post(expression) } -pub fn walk_arg<'a, V: Visitor<'a>>(visitor: &mut V, arg: &'a Arg) { - walk_list!(visitor, visit_attribute, arg.attrs.iter()); - visitor.visit_pat(&arg.pat); - visitor.visit_ty(&arg.ty); +pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) { + walk_list!(visitor, visit_attribute, param.attrs.iter()); + visitor.visit_pat(¶m.pat); + visitor.visit_ty(¶m.ty); } pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) { - walk_list!(visitor, visit_pat, &arm.pats); - if let Some(ref e) = &arm.guard { - visitor.visit_expr(e); - } + visitor.visit_pat(&arm.pat); + walk_list!(visitor, visit_expr, &arm.guard); visitor.visit_expr(&arm.body); walk_list!(visitor, visit_attribute, &arm.attrs); } diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index c1c2732605c46..becbf6d60a070 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -8,13 +8,12 @@ use errors::DiagnosticBuilder; use syntax::ast; use syntax::ext::base::{self, *}; -use syntax::parse; use syntax::parse::token::{self, Token}; use syntax::ptr::P; use syntax::symbol::{kw, sym, Symbol}; use syntax::ast::AsmDialect; use syntax_pos::Span; -use syntax::tokenstream; +use syntax::tokenstream::{self, TokenStream}; use syntax::{span_err, struct_span_err}; enum State { @@ -43,14 +42,14 @@ const OPTIONS: &[Symbol] = &[sym::volatile, sym::alignstack, sym::intel]; pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, - tts: &[tokenstream::TokenTree]) + tts: TokenStream) -> Box { let mut inline_asm = match parse_inline_asm(cx, sp, tts) { Ok(Some(inline_asm)) => inline_asm, - Ok(None) => return DummyResult::expr(sp), + Ok(None) => return DummyResult::any(sp), Err(mut err) => { err.emit(); - return DummyResult::expr(sp); + return DummyResult::any(sp); } }; @@ -62,8 +61,8 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt<'_>, MacEager::expr(P(ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprKind::InlineAsm(P(inline_asm)), - span: sp, + kind: ast::ExprKind::InlineAsm(P(inline_asm)), + span: cx.with_def_site_ctxt(sp), attrs: ThinVec::new(), })) } @@ -71,20 +70,20 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt<'_>, fn parse_inline_asm<'a>( cx: &mut ExtCtxt<'a>, sp: Span, - tts: &[tokenstream::TokenTree], + tts: TokenStream, ) -> Result, DiagnosticBuilder<'a>> { // Split the tts before the first colon, to avoid `asm!("x": y)` being // parsed as `asm!(z)` with `z = "x": y` which is type ascription. - let first_colon = tts.iter() + let first_colon = tts.trees() .position(|tt| { - match *tt { + match tt { tokenstream::TokenTree::Token(Token { kind: token::Colon, .. }) | tokenstream::TokenTree::Token(Token { kind: token::ModSep, .. }) => true, _ => false, } }) .unwrap_or(tts.len()); - let mut p = cx.new_parser_from_tts(&tts[first_colon..]); + let mut p = cx.new_parser_from_tts(tts.trees().skip(first_colon).collect()); let mut asm = kw::Invalid; let mut asm_str_style = None; let mut outputs = Vec::new(); @@ -110,7 +109,8 @@ fn parse_inline_asm<'a>( )); } // Nested parser, stop before the first colon (see above). - let mut p2 = cx.new_parser_from_tts(&tts[..first_colon]); + let mut p2 = + cx.new_parser_from_tts(tts.trees().take(first_colon).collect()); if p2.token == token::Eof { let mut err = @@ -129,12 +129,8 @@ fn parse_inline_asm<'a>( // This is most likely malformed. if p2.token != token::Eof { let mut extra_tts = p2.parse_all_token_trees()?; - extra_tts.extend(tts[first_colon..].iter().cloned()); - p = parse::stream_to_parser( - cx.parse_sess, - extra_tts.into_iter().collect(), - Some("inline assembly"), - ); + extra_tts.extend(tts.trees().skip(first_colon)); + p = cx.new_parser_from_tts(extra_tts.into_iter().collect()); } asm = s; @@ -277,6 +273,5 @@ fn parse_inline_asm<'a>( volatile, alignstack, dialect, - ctxt: cx.backtrace(), })) } diff --git a/src/libsyntax_ext/assert.rs b/src/libsyntax_ext/assert.rs index d7571f43eddd0..cbfe14fa439be 100644 --- a/src/libsyntax_ext/assert.rs +++ b/src/libsyntax_ext/assert.rs @@ -1,7 +1,6 @@ use errors::{Applicability, DiagnosticBuilder}; use syntax::ast::{self, *}; -use syntax::source_map::Spanned; use syntax::ext::base::*; use syntax::parse::token::{self, TokenKind}; use syntax::parse::parser::Parser; @@ -14,18 +13,20 @@ use syntax_pos::{Span, DUMMY_SP}; pub fn expand_assert<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, - tts: &[TokenTree], + tts: TokenStream, ) -> Box { let Assert { cond_expr, custom_message } = match parse_assert(cx, sp, tts) { Ok(assert) => assert, Err(mut err) => { err.emit(); - return DummyResult::expr(sp); + return DummyResult::any(sp); } }; - let sp = sp.apply_mark(cx.current_expansion.id); - let panic_call = Mac_ { + // `core::panic` and `std::panic` are different macros, so we use call-site + // context to pick up whichever is currently in scope. + let sp = cx.with_call_site_ctxt(sp); + let panic_call = Mac { path: Path::from_ident(Ident::new(sym::panic, sp)), tts: custom_message.unwrap_or_else(|| { TokenStream::from(TokenTree::token( @@ -37,6 +38,7 @@ pub fn expand_assert<'cx>( )) }).into(), delim: MacDelimiter::Parenthesis, + span: sp, prior_type_ascription: None, }; let if_expr = cx.expr_if( @@ -44,10 +46,7 @@ pub fn expand_assert<'cx>( cx.expr(sp, ExprKind::Unary(UnOp::Not, cond_expr)), cx.expr( sp, - ExprKind::Mac(Spanned { - span: sp, - node: panic_call, - }), + ExprKind::Mac(panic_call), ), None, ); @@ -62,9 +61,9 @@ struct Assert { fn parse_assert<'a>( cx: &mut ExtCtxt<'a>, sp: Span, - tts: &[TokenTree] + stream: TokenStream ) -> Result> { - let mut parser = cx.new_parser_from_tts(tts); + let mut parser = cx.new_parser_from_tts(stream); if parser.token == token::Eof { let mut err = cx.struct_span_err(sp, "macro requires a boolean expression as an argument"); diff --git a/src/libsyntax_ext/cfg.rs b/src/libsyntax_ext/cfg.rs index 84830e6ddda1a..3c33baf95a597 100644 --- a/src/libsyntax_ext/cfg.rs +++ b/src/libsyntax_ext/cfg.rs @@ -7,16 +7,16 @@ use errors::DiagnosticBuilder; use syntax::ast; use syntax::ext::base::{self, *}; use syntax::attr; -use syntax::tokenstream; +use syntax::tokenstream::TokenStream; use syntax::parse::token; use syntax_pos::Span; pub fn expand_cfg( cx: &mut ExtCtxt<'_>, sp: Span, - tts: &[tokenstream::TokenTree], + tts: TokenStream, ) -> Box { - let sp = sp.apply_mark(cx.current_expansion.id); + let sp = cx.with_def_site_ctxt(sp); match parse_cfg(cx, sp, tts) { Ok(cfg) => { @@ -25,7 +25,7 @@ pub fn expand_cfg( } Err(mut err) => { err.emit(); - DummyResult::expr(sp) + DummyResult::any(sp) } } } @@ -33,7 +33,7 @@ pub fn expand_cfg( fn parse_cfg<'a>( cx: &mut ExtCtxt<'a>, sp: Span, - tts: &[tokenstream::TokenTree], + tts: TokenStream, ) -> Result> { let mut p = cx.new_parser_from_tts(tts); diff --git a/src/libsyntax_ext/cmdline_attrs.rs b/src/libsyntax_ext/cmdline_attrs.rs new file mode 100644 index 0000000000000..203c4a834899b --- /dev/null +++ b/src/libsyntax_ext/cmdline_attrs.rs @@ -0,0 +1,30 @@ +//! Attributes injected into the crate root from command line using `-Z crate-attr`. + +use syntax::ast::{self, AttrItem, AttrStyle}; +use syntax::attr::mk_attr; +use syntax::panictry; +use syntax::parse::{self, token, ParseSess}; +use syntax_pos::FileName; + +pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate { + for raw_attr in attrs { + let mut parser = parse::new_parser_from_source_str( + parse_sess, + FileName::cli_crate_attr_source_code(&raw_attr), + raw_attr.clone(), + ); + + let start_span = parser.token.span; + let AttrItem { path, tokens } = panictry!(parser.parse_attr_item()); + let end_span = parser.token.span; + if parser.token != token::Eof { + parse_sess.span_diagnostic + .span_err(start_span.to(end_span), "invalid crate attribute"); + continue; + } + + krate.attrs.push(mk_attr(AttrStyle::Inner, path, tokens, start_span.to(end_span))); + } + + krate +} diff --git a/src/libsyntax_ext/compile_error.rs b/src/libsyntax_ext/compile_error.rs index 59d3f2c9c7813..24f3a66d4ae19 100644 --- a/src/libsyntax_ext/compile_error.rs +++ b/src/libsyntax_ext/compile_error.rs @@ -2,11 +2,11 @@ use syntax::ext::base::{self, *}; use syntax_pos::Span; -use syntax::tokenstream; +use syntax::tokenstream::TokenStream; pub fn expand_compile_error<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, - tts: &[tokenstream::TokenTree]) + tts: TokenStream) -> Box { let var = match get_single_str_from_tts(cx, sp, tts, "compile_error!") { None => return DummyResult::any(sp), diff --git a/src/libsyntax_ext/concat.rs b/src/libsyntax_ext/concat.rs index f1d079eb05379..790fdad5b3f58 100644 --- a/src/libsyntax_ext/concat.rs +++ b/src/libsyntax_ext/concat.rs @@ -1,25 +1,25 @@ use syntax::ast; -use syntax::ext::base; +use syntax::ext::base::{self, DummyResult}; use syntax::symbol::Symbol; -use syntax::tokenstream; +use syntax::tokenstream::TokenStream; use std::string::String; -pub fn expand_syntax_ext( +pub fn expand_concat( cx: &mut base::ExtCtxt<'_>, sp: syntax_pos::Span, - tts: &[tokenstream::TokenTree], + tts: TokenStream, ) -> Box { let es = match base::get_exprs_from_tts(cx, sp, tts) { Some(e) => e, - None => return base::DummyResult::expr(sp), + None => return DummyResult::any(sp), }; let mut accumulator = String::new(); let mut missing_literal = vec![]; let mut has_errors = false; for e in es { - match e.node { - ast::ExprKind::Lit(ref lit) => match lit.node { + match e.kind { + ast::ExprKind::Lit(ref lit) => match lit.kind { ast::LitKind::Str(ref s, _) | ast::LitKind::Float(ref s, _) | ast::LitKind::FloatUnsuffixed(ref s) => { @@ -55,10 +55,10 @@ pub fn expand_syntax_ext( let mut err = cx.struct_span_err(missing_literal, "expected a literal"); err.note("only literals (like `\"foo\"`, `42` and `3.14`) can be passed to `concat!()`"); err.emit(); - return base::DummyResult::expr(sp); + return DummyResult::any(sp); } else if has_errors { - return base::DummyResult::expr(sp); + return DummyResult::any(sp); } - let sp = sp.apply_mark(cx.current_expansion.id); + let sp = cx.with_def_site_ctxt(sp); base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator))) } diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index 8184fc442676d..f6747658c070e 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -6,21 +6,21 @@ use syntax::parse::token::{self, Token}; use syntax::ptr::P; use syntax_pos::Span; use syntax_pos::symbol::Symbol; -use syntax::tokenstream::TokenTree; +use syntax::tokenstream::{TokenTree, TokenStream}; -pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: &[TokenTree]) - -> Box { +pub fn expand_concat_idents<'cx>(cx: &'cx mut ExtCtxt<'_>, + sp: Span, + tts: TokenStream) + -> Box { if tts.is_empty() { cx.span_err(sp, "concat_idents! takes 1 or more arguments."); return DummyResult::any(sp); } let mut res_str = String::new(); - for (i, e) in tts.iter().enumerate() { + for (i, e) in tts.into_trees().enumerate() { if i & 1 == 1 { - match *e { + match e { TokenTree::Token(Token { kind: token::Comma, .. }) => {} _ => { cx.span_err(sp, "concat_idents! expecting comma."); @@ -28,7 +28,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt<'_>, } } } else { - match *e { + match e { TokenTree::Token(Token { kind: token::Ident(name, _), .. }) => res_str.push_str(&name.as_str()), _ => { @@ -39,7 +39,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt<'_>, } } - let ident = ast::Ident::new(Symbol::intern(&res_str), sp.apply_mark(cx.current_expansion.id)); + let ident = ast::Ident::new(Symbol::intern(&res_str), cx.with_call_site_ctxt(sp)); struct ConcatIdentsResult { ident: ast::Ident } @@ -47,7 +47,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt<'_>, fn make_expr(self: Box) -> Option> { Some(P(ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprKind::Path(None, ast::Path::from_ident(self.ident)), + kind: ast::ExprKind::Path(None, ast::Path::from_ident(self.ident)), span: self.ident.span, attrs: ThinVec::new(), })) @@ -56,7 +56,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt<'_>, fn make_ty(self: Box) -> Option> { Some(P(ast::Ty { id: ast::DUMMY_NODE_ID, - node: ast::TyKind::Path(None, ast::Path::from_ident(self.ident)), + kind: ast::TyKind::Path(None, ast::Path::from_ident(self.ident)), span: self.ident.span, })) } diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index 3b1edf90d6bf2..9ef2c033b0784 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -32,10 +32,10 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt<'_>, let is_shallow; match *item { Annotatable::Item(ref annitem) => { - match annitem.node { + match annitem.kind { ItemKind::Struct(_, Generics { ref params, .. }) | ItemKind::Enum(_, Generics { ref params, .. }) => { - let container_id = cx.current_expansion.id.parent(); + let container_id = cx.current_expansion.id.expn_data().parent; if cx.resolver.has_derives(container_id, SpecialDerives::COPY) && !params.iter().any(|param| match param.kind { ast::GenericParamKind::Type { .. } => true, @@ -112,10 +112,10 @@ fn cs_clone_shallow(name: &str, ty: P, span: Span, helper_name: &str) { // Generate statement `let _: helper_name;`, // set the expn ID so we can use the unstable struct. - let span = span.with_ctxt(cx.backtrace()); + let span = cx.with_def_site_ctxt(span); let assert_path = cx.path_all(span, true, cx.std_path(&[sym::clone, Symbol::intern(helper_name)]), - vec![GenericArg::Type(ty)], vec![]); + vec![GenericArg::Type(ty)]); stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path))); } fn process_variant(cx: &mut ExtCtxt<'_>, stmts: &mut Vec, variant: &VariantData) { @@ -129,7 +129,7 @@ fn cs_clone_shallow(name: &str, if is_union { // let _: AssertParamIsCopy; let self_ty = - cx.ty_path(cx.path_ident(trait_span, ast::Ident::with_empty_ctxt(kw::SelfUpper))); + cx.ty_path(cx.path_ident(trait_span, ast::Ident::with_dummy_span(kw::SelfUpper))); assert_ty_bounds(cx, &mut stmts, self_ty, trait_span, "AssertParamIsCopy"); } else { match *substr.fields { @@ -138,7 +138,7 @@ fn cs_clone_shallow(name: &str, } StaticEnum(enum_def, ..) => { for variant in &enum_def.variants { - process_variant(cx, &mut stmts, &variant.node.data); + process_variant(cx, &mut stmts, &variant.data); } } _ => cx.span_bug(trait_span, &format!("unexpected substructure in \ @@ -170,9 +170,9 @@ fn cs_clone(name: &str, vdata = vdata_; } EnumMatching(.., variant, ref af) => { - ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.node.ident]); + ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.ident]); all_fields = af; - vdata = &variant.node.data; + vdata = &variant.data; } EnumNonMatchingCollapsed(..) => { cx.span_bug(trait_span, diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index 1909729f4a941..c92339dd2fbd5 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -2,7 +2,7 @@ use crate::deriving::path_std; use crate::deriving::generic::*; use crate::deriving::generic::ty::*; -use syntax::ast::{self, Expr, MetaItem, GenericArg}; +use syntax::ast::{self, Ident, Expr, MetaItem, GenericArg}; use syntax::ext::base::{Annotatable, ExtCtxt, SpecialDerives}; use syntax::ptr::P; use syntax::symbol::{sym, Symbol}; @@ -13,11 +13,11 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt<'_>, mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable)) { - cx.resolver.add_derives(cx.current_expansion.id.parent(), SpecialDerives::EQ); + cx.resolver.add_derives(cx.current_expansion.id.expn_data().parent, SpecialDerives::EQ); let inline = cx.meta_word(span, sym::inline); - let hidden = cx.meta_list_item_word(span, sym::hidden); - let doc = cx.meta_list(span, sym::doc, vec![hidden]); + let hidden = syntax::attr::mk_nested_word_item(Ident::new(sym::hidden, span)); + let doc = syntax::attr::mk_list_item(Ident::new(sym::doc, span), vec![hidden]); let attrs = vec![cx.attribute(inline), cx.attribute(doc)]; let trait_def = TraitDef { span, @@ -53,10 +53,10 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt<'_>, ty: P, span: Span, helper_name: &str) { // Generate statement `let _: helper_name;`, // set the expn ID so we can use the unstable struct. - let span = span.with_ctxt(cx.backtrace()); + let span = cx.with_def_site_ctxt(span); let assert_path = cx.path_all(span, true, cx.std_path(&[sym::cmp, Symbol::intern(helper_name)]), - vec![GenericArg::Type(ty)], vec![]); + vec![GenericArg::Type(ty)]); stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path))); } fn process_variant(cx: &mut ExtCtxt<'_>, @@ -75,7 +75,7 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt<'_>, } StaticEnum(enum_def, ..) => { for variant in &enum_def.variants { - process_variant(cx, &mut stmts, &variant.node.data); + process_variant(cx, &mut stmts, &variant.data); } } _ => cx.span_bug(trait_span, "unexpected substructure in `derive(Eq)`") diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs index 885cfee35658a..1f4f5aa37099f 100644 --- a/src/libsyntax_ext/deriving/cmp/ord.rs +++ b/src/libsyntax_ext/deriving/cmp/ord.rs @@ -43,17 +43,18 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt<'_>, } -pub fn ordering_collapsed(cx: &mut ExtCtxt<'_>, - span: Span, - self_arg_tags: &[ast::Ident]) - -> P { +pub fn ordering_collapsed( + cx: &mut ExtCtxt<'_>, + span: Span, + self_arg_tags: &[ast::Ident], +) -> P { let lft = cx.expr_ident(span, self_arg_tags[0]); let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1])); - cx.expr_method_call(span, lft, cx.ident_of("cmp"), vec![rgt]) + cx.expr_method_call(span, lft, ast::Ident::new(sym::cmp, span), vec![rgt]) } pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P { - let test_id = cx.ident_of("cmp").gensym(); + let test_id = ast::Ident::new(sym::cmp, span); let equals_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); let cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]); @@ -75,34 +76,32 @@ pub fn cs_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 { - // ::std::cmp::Ordering::Equal => old, - // cmp => cmp - // } + // match new { + // ::std::cmp::Ordering::Equal => old, + // cmp => cmp + // } - let new = { - let other_f = match other_fs { - [o_f] => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`"), - }; + let new = { + let other_f = match other_fs { + [o_f] => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`"), + }; - 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, cmp_path.clone(), args) - }; + cx.expr_call_global(span, cmp_path.clone(), args) + }; - let eq_arm = cx.arm(span, - vec![cx.pat_path(span, equals_path.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, cx.pat_path(span, equals_path.clone()), old); + let neq_arm = cx.arm(span, + 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]) + }, cx.expr_path(equals_path.clone()), Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { if self_args.len() != 2 { diff --git a/src/libsyntax_ext/deriving/cmp/partial_eq.rs b/src/libsyntax_ext/deriving/cmp/partial_eq.rs index 7d7c4ae22a8a6..91e1e80e4fbfa 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_eq.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_eq.rs @@ -13,7 +13,7 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt<'_>, mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable)) { - cx.resolver.add_derives(cx.current_expansion.id.parent(), SpecialDerives::PARTIAL_EQ); + cx.resolver.add_derives(cx.current_expansion.id.expn_data().parent, SpecialDerives::PARTIAL_EQ); // structures are equal if all fields are equal, and non equal, if // any fields are not equal or if the enum variants are different diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index 0ec30f5924fbe..13d63aaf2a80c 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -94,11 +94,12 @@ pub enum OrderingOp { GeOp, } -pub fn some_ordering_collapsed(cx: &mut ExtCtxt<'_>, - span: Span, - op: OrderingOp, - self_arg_tags: &[ast::Ident]) - -> P { +pub fn some_ordering_collapsed( + cx: &mut ExtCtxt<'_>, + span: Span, + op: OrderingOp, + self_arg_tags: &[ast::Ident], +) -> P { let lft = cx.expr_ident(span, self_arg_tags[0]); let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1])); let op_str = match op { @@ -108,11 +109,11 @@ pub fn some_ordering_collapsed(cx: &mut ExtCtxt<'_>, GtOp => "gt", GeOp => "ge", }; - cx.expr_method_call(span, lft, cx.ident_of(op_str), vec![rgt]) + cx.expr_method_call(span, lft, cx.ident_of(op_str, span), vec![rgt]) } pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P { - let test_id = cx.ident_of("cmp").gensym(); + let test_id = ast::Ident::new(sym::cmp, span); let ordering = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); let ordering_expr = cx.expr_path(ordering.clone()); let equals_expr = cx.expr_some(span, ordering_expr); @@ -159,10 +160,10 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_ }; let eq_arm = cx.arm(span, - vec![cx.pat_some(span, cx.pat_path(span, ordering.clone()))], + 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.pat_ident(span, test_id), cx.expr_ident(span, test_id)); cx.expr_match(span, new, vec![eq_arm, neq_arm]) diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index 0f709630bf41e..003c2423576eb 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -53,16 +53,16 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> // based on the "shape". let (ident, vdata, fields) = match substr.fields { Struct(vdata, fields) => (substr.type_ident, *vdata, fields), - EnumMatching(_, _, v, fields) => (v.node.ident, &v.node.data, fields), + EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields), EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`"), }; // We want to make sure we have the ctxt set so that we can use unstable methods - let span = span.with_ctxt(cx.backtrace()); + let span = cx.with_def_site_ctxt(span); let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked)); - let builder = Ident::from_str("debug_trait_builder").gensym(); + let builder = cx.ident_of("debug_trait_builder", span); let builder_expr = cx.expr_ident(span, builder.clone()); let fmt = substr.nonself_args[0].clone(); @@ -72,8 +72,8 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => { // tuple struct/"normal" variant let expr = - cx.expr_method_call(span, fmt, Ident::from_str("debug_tuple"), vec![name]); - stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr)); + cx.expr_method_call(span, fmt, cx.ident_of("debug_tuple", span), vec![name]); + stmts.push(cx.stmt_let(span, true, builder, expr)); for field in fields { // Use double indirection to make sure this works for unsized types @@ -82,7 +82,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> let expr = cx.expr_method_call(span, builder_expr.clone(), - Ident::with_empty_ctxt(sym::field), + Ident::new(sym::field, span), vec![field]); // Use `let _ = expr;` to avoid triggering the @@ -93,7 +93,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> ast::VariantData::Struct(..) => { // normal struct/struct variant let expr = - cx.expr_method_call(span, fmt, Ident::from_str("debug_struct"), vec![name]); + cx.expr_method_call(span, fmt, cx.ident_of("debug_struct", span), vec![name]); stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr)); for field in fields { @@ -106,14 +106,14 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> let field = cx.expr_addr_of(field.span, field); let expr = cx.expr_method_call(span, builder_expr.clone(), - Ident::with_empty_ctxt(sym::field), + Ident::new(sym::field, span), vec![name, field]); stmts.push(stmt_let_undescore(cx, span, expr)); } } } - let expr = cx.expr_method_call(span, builder_expr, Ident::from_str("finish"), vec![]); + let expr = cx.expr_method_call(span, builder_expr, cx.ident_of("finish", span), vec![]); stmts.push(cx.stmt_expr(expr)); let block = cx.block(span, stmts); @@ -131,7 +131,7 @@ fn stmt_let_undescore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P) -> ast }); ast::Stmt { id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Local(local), + kind: ast::StmtKind::Local(local), span: sp, } } diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index 293c5a1e7e71b..cde72abbdef6a 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -1,6 +1,6 @@ -//! The compiler code necessary for `#[derive(Decodable)]`. See encodable.rs for more. +//! The compiler code necessary for `#[derive(RustcDecodable)]`. See encodable.rs for more. -use crate::deriving::{self, pathvec_std}; +use crate::deriving::pathvec_std; use crate::deriving::generic::*; use crate::deriving::generic::ty::*; @@ -17,7 +17,7 @@ pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt<'_>, item: &Annotatable, push: &mut dyn FnMut(Annotatable)) { let krate = "rustc_serialize"; - let typaram = &*deriving::hygienic_type_parameter(item, "__D"); + let typaram = "__D"; let trait_def = TraitDef { span, @@ -66,10 +66,14 @@ fn decodable_substructure(cx: &mut ExtCtxt<'_>, krate: &str) -> P { let decoder = substr.nonself_args[0].clone(); - let recurse = vec![cx.ident_of(krate), cx.ident_of("Decodable"), cx.ident_of("decode")]; + let recurse = vec![ + cx.ident_of(krate, trait_span), + cx.ident_of("Decodable", trait_span), + cx.ident_of("decode", trait_span), + ]; let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse)); // throw an underscore in front to suppress unused variable warnings - let blkarg = cx.ident_of("_d"); + let blkarg = cx.ident_of("_d", trait_span); let blkdecoder = cx.expr_ident(trait_span, blkarg); return match *substr.fields { @@ -78,7 +82,7 @@ fn decodable_substructure(cx: &mut ExtCtxt<'_>, Unnamed(ref fields, _) => fields.len(), Named(ref fields) => fields.len(), }; - let read_struct_field = cx.ident_of("read_struct_field"); + let read_struct_field = cx.ident_of("read_struct_field", trait_span); let path = cx.path_ident(trait_span, substr.type_ident); let result = @@ -94,17 +98,17 @@ fn decodable_substructure(cx: &mut ExtCtxt<'_>, let result = cx.expr_ok(trait_span, result); cx.expr_method_call(trait_span, decoder, - cx.ident_of("read_struct"), + cx.ident_of("read_struct", trait_span), vec![cx.expr_str(trait_span, substr.type_ident.name), cx.expr_usize(trait_span, nfields), cx.lambda1(trait_span, result, blkarg)]) } StaticEnum(_, ref fields) => { - let variant = cx.ident_of("i"); + let variant = cx.ident_of("i", trait_span); let mut arms = Vec::with_capacity(fields.len() + 1); let mut variants = Vec::with_capacity(fields.len()); - let rvariant_arg = cx.ident_of("read_enum_variant_arg"); + let rvariant_arg = cx.ident_of("read_enum_variant_arg", trait_span); for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() { variants.push(cx.expr_str(v_span, ident.name)); @@ -119,9 +123,7 @@ fn decodable_substructure(cx: &mut ExtCtxt<'_>, vec![idx, exprdecode.clone()])) }); - arms.push(cx.arm(v_span, - vec![cx.pat_lit(v_span, cx.expr_usize(v_span, i))], - decoded)); + arms.push(cx.arm(v_span, cx.pat_lit(v_span, cx.expr_usize(v_span, i)), decoded)); } arms.push(cx.arm_unreachable(trait_span)); @@ -134,11 +136,11 @@ fn decodable_substructure(cx: &mut ExtCtxt<'_>, let variant_vec = cx.expr_addr_of(trait_span, variant_vec); let result = cx.expr_method_call(trait_span, blkdecoder, - cx.ident_of("read_enum_variant"), + cx.ident_of("read_enum_variant", trait_span), vec![variant_vec, lambda]); cx.expr_method_call(trait_span, decoder, - cx.ident_of("read_enum"), + cx.ident_of("read_enum", trait_span), vec![cx.expr_str(trait_span, substr.type_ident.name), cx.lambda1(trait_span, result, blkarg)]) } diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index 6d0d3b96a56d6..655d3bb7c4ab8 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -1,11 +1,12 @@ -//! The compiler code necessary to implement the `#[derive(Encodable)]` -//! (and `Decodable`, in `decodable.rs`) extension. The idea here is that -//! type-defining items may be tagged with `#[derive(Encodable, Decodable)]`. +//! The compiler code necessary to implement the `#[derive(RustcEncodable)]` +//! (and `RustcDecodable`, in `decodable.rs`) extension. The idea here is that +//! type-defining items may be tagged with +//! `#[derive(RustcEncodable, RustcDecodable)]`. //! //! For example, a type like: //! //! ``` -//! #[derive(Encodable, Decodable)] +//! #[derive(RustcEncodable, RustcDecodable)] //! struct Node { id: usize } //! ``` //! @@ -40,15 +41,17 @@ //! references other non-built-in types. A type definition like: //! //! ``` -//! # #[derive(Encodable, Decodable)] struct Span; -//! #[derive(Encodable, Decodable)] +//! # #[derive(RustcEncodable, RustcDecodable)] +//! # struct Span; +//! #[derive(RustcEncodable, RustcDecodable)] //! struct Spanned { node: T, span: Span } //! ``` //! //! would yield functions like: //! //! ``` -//! # #[derive(Encodable, Decodable)] struct Span; +//! # #[derive(RustcEncodable, RustcDecodable)] +//! # struct Span; //! # struct Spanned { node: T, span: Span } //! impl< //! S: Encoder, @@ -82,7 +85,7 @@ //! } //! ``` -use crate::deriving::{self, pathvec_std}; +use crate::deriving::pathvec_std; use crate::deriving::generic::*; use crate::deriving::generic::ty::*; @@ -98,7 +101,7 @@ pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt<'_>, item: &Annotatable, push: &mut dyn FnMut(Annotatable)) { let krate = "rustc_serialize"; - let typaram = &*deriving::hygienic_type_parameter(item, "__S"); + let typaram = "__S"; let trait_def = TraitDef { span, @@ -150,16 +153,16 @@ fn encodable_substructure(cx: &mut ExtCtxt<'_>, -> P { let encoder = substr.nonself_args[0].clone(); // throw an underscore in front to suppress unused variable warnings - let blkarg = cx.ident_of("_e"); + let blkarg = cx.ident_of("_e", trait_span); let blkencoder = cx.expr_ident(trait_span, blkarg); let fn_path = cx.expr_path(cx.path_global(trait_span, - vec![cx.ident_of(krate), - cx.ident_of("Encodable"), - cx.ident_of("encode")])); + vec![cx.ident_of(krate, trait_span), + cx.ident_of("Encodable", trait_span), + cx.ident_of("encode", trait_span)])); return match *substr.fields { Struct(_, ref fields) => { - let emit_struct_field = cx.ident_of("emit_struct_field"); + let emit_struct_field = cx.ident_of("emit_struct_field", trait_span); let mut stmts = Vec::new(); for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() { let name = match name { @@ -198,7 +201,7 @@ fn encodable_substructure(cx: &mut ExtCtxt<'_>, cx.expr_method_call(trait_span, encoder, - cx.ident_of("emit_struct"), + cx.ident_of("emit_struct", trait_span), vec![cx.expr_str(trait_span, substr.type_ident.name), cx.expr_usize(trait_span, fields.len()), blk]) @@ -211,7 +214,7 @@ fn encodable_substructure(cx: &mut ExtCtxt<'_>, // actually exist. let me = cx.stmt_let(trait_span, false, blkarg, encoder); let encoder = cx.expr_ident(trait_span, blkarg); - let emit_variant_arg = cx.ident_of("emit_enum_variant_arg"); + let emit_variant_arg = cx.ident_of("emit_enum_variant_arg", trait_span); let mut stmts = Vec::new(); if !fields.is_empty() { let last = fields.len() - 1; @@ -238,10 +241,10 @@ fn encodable_substructure(cx: &mut ExtCtxt<'_>, } let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg); - let name = cx.expr_str(trait_span, variant.node.ident.name); + let name = cx.expr_str(trait_span, variant.ident.name); let call = cx.expr_method_call(trait_span, blkencoder, - cx.ident_of("emit_enum_variant"), + cx.ident_of("emit_enum_variant", trait_span), vec![name, cx.expr_usize(trait_span, idx), cx.expr_usize(trait_span, fields.len()), @@ -249,7 +252,7 @@ fn encodable_substructure(cx: &mut ExtCtxt<'_>, let blk = cx.lambda1(trait_span, call, blkarg); let ret = cx.expr_method_call(trait_span, encoder, - cx.ident_of("emit_enum"), + cx.ident_of("emit_enum", trait_span), vec![cx.expr_str(trait_span ,substr.type_ident.name), blk]); cx.expr_block(cx.block(trait_span, vec![me, cx.stmt_expr(ret)])) diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 7e6d9126c8740..abdcb6c8e3d37 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -187,12 +187,12 @@ use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind}; use syntax::ast::{VariantData, GenericParamKind, GenericArg}; use syntax::attr; use syntax::ext::base::{Annotatable, ExtCtxt, SpecialDerives}; -use syntax::source_map::{self, respan}; +use syntax::source_map::respan; use syntax::util::map_in_place::MapInPlace; use syntax::ptr::P; use syntax::symbol::{Symbol, kw, sym}; use syntax::parse::ParseSess; -use syntax_pos::{DUMMY_SP, Span}; +use syntax_pos::{Span}; use ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty}; @@ -237,7 +237,7 @@ pub struct MethodDef<'a> { /// Whether there is a self argument (outer Option) i.e., whether /// this is a static function, and whether it is a pointer (inner /// Option) - pub explicit_self: Option>>, + pub explicit_self: Option>, /// Arguments other than the self argument pub args: Vec<(Ty<'a>, &'a str)>, @@ -355,7 +355,7 @@ fn find_type_parameters( impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> { fn visit_ty(&mut self, ty: &'a ast::Ty) { - if let ast::TyKind::Path(_, ref path) = ty.node { + if let ast::TyKind::Path(_, ref path) = ty.kind { if let Some(segment) = path.segments.first() { if self.ty_param_names.contains(&segment.ident.name) { self.types.push(P(ty.clone())); @@ -409,7 +409,7 @@ impl<'a> TraitDef<'a> { } false }); - let has_no_type_params = match item.node { + let has_no_type_params = match item.kind { ast::ItemKind::Struct(_, ref generics) | ast::ItemKind::Enum(_, ref generics) | ast::ItemKind::Union(_, ref generics) => { @@ -425,13 +425,13 @@ impl<'a> TraitDef<'a> { return; } }; - let container_id = cx.current_expansion.id.parent(); + let container_id = cx.current_expansion.id.expn_data().parent; let is_always_copy = cx.resolver.has_derives(container_id, SpecialDerives::COPY) && has_no_type_params; let use_temporaries = is_packed && is_always_copy; - let newitem = match item.node { + let newitem = match item.kind { ast::ItemKind::Struct(ref struct_def, ref generics) => { self.expand_struct_def(cx, &struct_def, item.ident, generics, from_scratch, use_temporaries) @@ -530,7 +530,7 @@ impl<'a> TraitDef<'a> { defaultness: ast::Defaultness::Final, attrs: Vec::new(), generics: Generics::default(), - node: ast::ImplItemKind::TyAlias( + kind: ast::ImplItemKind::TyAlias( type_def.to_ty(cx, self.span, type_ident, generics)), tokens: None, } @@ -612,7 +612,7 @@ impl<'a> TraitDef<'a> { for ty in tys { // if we have already handled this type, skip it - if let ast::TyKind::Path(_, ref p) = ty.node { + if let ast::TyKind::Path(_, ref p) = ty.kind { if p.segments.len() == 1 && ty_param_names.contains(&p.segments[0].ident.name) { continue; @@ -664,7 +664,7 @@ impl<'a> TraitDef<'a> { }).collect(); // Create the type of `self`. - let path = cx.path_all(self.span, false, vec![type_ident], self_params, vec![]); + let path = cx.path_all(self.span, false, vec![type_ident], self_params); let self_type = cx.ty_path(path); let attr = cx.attribute(cx.meta_word(self.span, sym::automatically_derived)); @@ -672,8 +672,11 @@ impl<'a> TraitDef<'a> { attr::mark_used(&attr); let opt_trait_ref = Some(trait_ref); let unused_qual = { - let word = cx.meta_list_item_word(self.span, Symbol::intern("unused_qualifications")); - cx.attribute(cx.meta_list(self.span, sym::allow, vec![word])) + let word = syntax::attr::mk_nested_word_item( + Ident::new(Symbol::intern("unused_qualifications"), self.span)); + let list = syntax::attr::mk_list_item( + Ident::new(sym::allow, self.span), vec![word]); + cx.attribute(list) }; let mut a = vec![attr, unused_qual]; @@ -758,7 +761,7 @@ impl<'a> TraitDef<'a> { let mut field_tys = Vec::new(); for variant in &enum_def.variants { - field_tys.extend(variant.node + field_tys.extend(variant .data .fields() .iter() @@ -843,7 +846,7 @@ impl<'a> MethodDef<'a> { -> P { let substructure = Substructure { type_ident, - method_ident: cx.ident_of(self.name), + method_ident: cx.ident_of(self.name, trait_.span), self_args, nonself_args, fields, @@ -890,7 +893,7 @@ impl<'a> MethodDef<'a> { for (ty, name) in self.args.iter() { let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics); - let ident = cx.ident_of(name).gensym(); + let ident = cx.ident_of(name, trait_.span); arg_tys.push((ident, ast_ty)); let arg_expr = cx.expr_ident(trait_.span, ident); @@ -928,17 +931,17 @@ impl<'a> MethodDef<'a> { let args = { let self_args = explicit_self.map(|explicit_self| { - let ident = Ident::with_empty_ctxt(kw::SelfLower).with_span_pos(trait_.span); - ast::Arg::from_self(ThinVec::default(), explicit_self, ident) + let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(trait_.span); + ast::Param::from_self(ThinVec::default(), explicit_self, ident) }); let nonself_args = arg_types.into_iter() - .map(|(name, ty)| cx.arg(trait_.span, name, ty)); + .map(|(name, ty)| cx.param(trait_.span, name, ty)); self_args.into_iter().chain(nonself_args).collect() }; let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident); - let method_ident = cx.ident_of(self.name); + let method_ident = cx.ident_of(self.name, trait_.span); let fn_decl = cx.fn_decl(args, ast::FunctionRetTy::Ty(ret_type)); let body_block = cx.block_expr(body); @@ -957,7 +960,7 @@ impl<'a> MethodDef<'a> { vis: respan(trait_.span.shrink_to_lo(), ast::VisibilityKind::Inherited), defaultness: ast::Defaultness::Final, ident: method_ident, - node: ast::ImplItemKind::Method(ast::MethodSig { + kind: ast::ImplItemKind::Method(ast::MethodSig { header: ast::FnHeader { unsafety, abi, ..ast::FnHeader::default() @@ -1019,7 +1022,7 @@ impl<'a> MethodDef<'a> { // [fields of next Self arg], [etc]> let mut patterns = Vec::new(); for i in 0..self_args.len() { - let struct_path = cx.path(DUMMY_SP, vec![type_ident]); + let struct_path = cx.path(trait_.span, vec![type_ident]); let (pat, ident_expr) = trait_.create_struct_pattern(cx, struct_path, struct_def, @@ -1071,7 +1074,7 @@ impl<'a> MethodDef<'a> { for (arg_expr, pat) in self_args.iter().zip(patterns) { body = cx.expr_match(trait_.span, arg_expr.clone(), - vec![cx.arm(trait_.span, vec![pat.clone()], body)]) + vec![cx.arm(trait_.span, pat.clone(), body)]) } body @@ -1201,7 +1204,7 @@ impl<'a> MethodDef<'a> { ).collect::>(); let self_arg_idents = self_arg_names.iter() - .map(|name| cx.ident_of(&name[..])) + .map(|name| cx.ident_of(name, sp)) .collect::>(); // The `vi_idents` will be bound, solely in the catch-all, to @@ -1210,7 +1213,7 @@ impl<'a> MethodDef<'a> { let vi_idents = self_arg_names.iter() .map(|name| { let vi_suffix = format!("{}_vi", &name[..]); - cx.ident_of(&vi_suffix[..]).gensym() + cx.ident_of(&vi_suffix[..], trait_.span) }) .collect::>(); @@ -1220,7 +1223,7 @@ impl<'a> MethodDef<'a> { let catch_all_substructure = EnumNonMatchingCollapsed(self_arg_idents, &variants[..], &vi_idents[..]); - let first_fieldless = variants.iter().find(|v| v.node.data.fields().is_empty()); + let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty()); // These arms are of the form: // (Variant1, Variant1, ...) => Body1 @@ -1229,7 +1232,7 @@ impl<'a> MethodDef<'a> { // where each tuple has length = self_args.len() let mut match_arms: Vec = variants.iter() .enumerate() - .filter(|&(_, v)| !(self.unify_fieldless_variants && v.node.data.fields().is_empty())) + .filter(|&(_, v)| !(self.unify_fieldless_variants && v.data.fields().is_empty())) .map(|(index, variant)| { let mk_self_pat = |cx: &mut ExtCtxt<'_>, self_arg_name: &str| { let (p, idents) = trait_.create_enum_variant_pattern(cx, @@ -1311,7 +1314,7 @@ impl<'a> MethodDef<'a> { nonself_args, &substructure); - cx.arm(sp, vec![single_pat], arm_expr) + cx.arm(sp, single_pat, arm_expr) }) .collect(); @@ -1337,7 +1340,7 @@ impl<'a> MethodDef<'a> { _ => None, }; if let Some(arm) = default { - match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], arm)); + match_arms.push(cx.arm(sp, cx.pat_wild(sp), arm)); } // We will usually need the catch-all after matching the @@ -1387,7 +1390,10 @@ impl<'a> MethodDef<'a> { let variant_value = deriving::call_intrinsic(cx, sp, "discriminant_value", vec![self_addr]); - let target_ty = cx.ty_ident(sp, cx.ident_of(target_type_name)); + let target_ty = cx.ty_ident( + sp, + cx.ident_of(target_type_name, sp), + ); let variant_disr = cx.expr_cast(sp, variant_value, target_ty); let let_stmt = cx.stmt_let(sp, false, ident, variant_disr); index_let_stmts.push(let_stmt); @@ -1513,8 +1519,8 @@ impl<'a> MethodDef<'a> { .iter() .map(|v| { let sp = v.span.with_ctxt(trait_.span.ctxt()); - let summary = trait_.summarise_struct(cx, &v.node.data); - (v.node.ident, sp, summary) + let summary = trait_.summarise_struct(cx, &v.data); + (v.ident, sp, summary) }) .collect(); self.call_substructure_method(cx, @@ -1588,7 +1594,7 @@ impl<'a> TraitDef<'a> { let mut ident_exprs = Vec::new(); for (i, struct_field) in struct_def.fields().iter().enumerate() { let sp = struct_field.span.with_ctxt(self.span.ctxt()); - let ident = cx.ident_of(&format!("{}_{}", prefix, i)).gensym(); + let ident = cx.ident_of(&format!("{}_{}", prefix, i), self.span); paths.push(ident.with_span_pos(sp)); let val = cx.expr_path(cx.path_ident(sp, ident)); let val = if use_temporaries { @@ -1610,14 +1616,14 @@ impl<'a> TraitDef<'a> { if ident.is_none() { cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); } - source_map::Spanned { + ast::FieldPat { + ident: ident.unwrap(), + is_shorthand: false, + attrs: ThinVec::new(), + id: ast::DUMMY_NODE_ID, span: pat.span.with_ctxt(self.span.ctxt()), - node: ast::FieldPat { - ident: ident.unwrap(), - pat, - is_shorthand: false, - attrs: ThinVec::new(), - }, + pat, + is_placeholder: false } }) .collect(); @@ -1643,9 +1649,9 @@ impl<'a> TraitDef<'a> { mutbl: ast::Mutability) -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { let sp = variant.span.with_ctxt(self.span.ctxt()); - let variant_path = cx.path(sp, vec![enum_ident, variant.node.ident]); + let variant_path = cx.path(sp, vec![enum_ident, variant.ident]); let use_temporaries = false; // enums can't be repr(packed) - self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl, + self.create_struct_pattern(cx, variant_path, &variant.data, prefix, mutbl, use_temporaries) } } @@ -1774,9 +1780,9 @@ pub fn cs_fold1(use_foldl: bool, /// (for an enum, no variant has any fields) pub fn is_type_without_fields(item: &Annotatable) -> bool { if let Annotatable::Item(ref item) = *item { - match item.node { + match item.kind { ast::ItemKind::Enum(ref enum_def, _) => { - enum_def.variants.iter().all(|v| v.node.data.fields().is_empty()) + enum_def.variants.iter().all(|v| v.data.fields().is_empty()) } ast::ItemKind::Struct(ref variant_data, _) => variant_data.fields().is_empty(), _ => false, diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs index 399829eaefd14..6ae02a5cab199 100644 --- a/src/libsyntax_ext/deriving/generic/ty.rs +++ b/src/libsyntax_ext/deriving/generic/ty.rs @@ -13,9 +13,9 @@ use syntax_pos::symbol::kw; /// The types of pointers #[derive(Clone)] -pub enum PtrTy<'a> { +pub enum PtrTy { /// &'lifetime mut - Borrowed(Option<&'a str>, ast::Mutability), + Borrowed(Option, ast::Mutability), /// *mut #[allow(dead_code)] Raw(ast::Mutability), @@ -26,7 +26,7 @@ pub enum PtrTy<'a> { #[derive(Clone)] pub struct Path<'a> { path: Vec<&'a str>, - lifetime: Option<&'a str>, + lifetime: Option, params: Vec>>, kind: PathKind, } @@ -46,7 +46,7 @@ impl<'a> Path<'a> { Path::new_(vec![path], None, Vec::new(), PathKind::Local) } pub fn new_<'r>(path: Vec<&'r str>, - lifetime: Option<&'r str>, + lifetime: Option, params: Vec>>, kind: PathKind) -> Path<'r> { @@ -72,7 +72,7 @@ impl<'a> Path<'a> { self_ty: Ident, self_generics: &Generics) -> ast::Path { - let mut idents = self.path.iter().map(|s| cx.ident_of(*s)).collect(); + let mut idents = self.path.iter().map(|s| cx.ident_of(*s, span)).collect(); let lt = mk_lifetimes(cx, span, &self.lifetime); let tys: Vec> = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect(); @@ -82,12 +82,12 @@ impl<'a> Path<'a> { .collect(); match self.kind { - PathKind::Global => cx.path_all(span, true, idents, params, Vec::new()), - PathKind::Local => cx.path_all(span, false, idents, params, Vec::new()), + PathKind::Global => cx.path_all(span, true, idents, params), + PathKind::Local => cx.path_all(span, false, idents, params), PathKind::Std => { - let def_site = DUMMY_SP.apply_mark(cx.current_expansion.id); + let def_site = cx.with_def_site_ctxt(DUMMY_SP); idents.insert(0, Ident::new(kw::DollarCrate, def_site)); - cx.path_all(span, false, idents, params, Vec::new()) + cx.path_all(span, false, idents, params) } } @@ -99,7 +99,7 @@ impl<'a> Path<'a> { pub enum Ty<'a> { Self_, /// &/Box/ Ty - Ptr(Box>, PtrTy<'a>), + Ptr(Box>, PtrTy), /// mod::mod::Type<[lifetime], [Params...]>, including a plain type /// parameter, and things like `i32` Literal(Path<'a>), @@ -107,14 +107,14 @@ pub enum Ty<'a> { Tuple(Vec>), } -pub fn borrowed_ptrty<'r>() -> PtrTy<'r> { +pub fn borrowed_ptrty() -> PtrTy { Borrowed(None, ast::Mutability::Immutable) } pub fn borrowed(ty: Box>) -> Ty<'_> { Ptr(ty, borrowed_ptrty()) } -pub fn borrowed_explicit_self<'r>() -> Option>> { +pub fn borrowed_explicit_self() -> Option> { Some(Some(borrowed_ptrty())) } @@ -126,13 +126,11 @@ pub fn nil_ty<'r>() -> Ty<'r> { Tuple(Vec::new()) } -fn mk_lifetime(cx: &ExtCtxt<'_>, span: Span, lt: &Option<&str>) -> Option { - lt.map(|s| - cx.lifetime(span, Ident::from_str(s)) - ) +fn mk_lifetime(cx: &ExtCtxt<'_>, span: Span, lt: &Option) -> Option { + lt.map(|ident| cx.lifetime(span, ident)) } -fn mk_lifetimes(cx: &ExtCtxt<'_>, span: Span, lt: &Option<&str>) -> Vec { +fn mk_lifetimes(cx: &ExtCtxt<'_>, span: Span, lt: &Option) -> Vec { mk_lifetime(cx, span, lt).into_iter().collect() } @@ -185,7 +183,7 @@ impl<'a> Ty<'a> { } }).collect(); - cx.path_all(span, false, vec![self_ty], params, vec![]) + cx.path_all(span, false, vec![self_ty], params) } Literal(ref p) => p.to_path(cx, span, self_ty, generics), Ptr(..) => cx.span_bug(span, "pointer in a path in generic `derive`"), @@ -209,7 +207,7 @@ fn mk_ty_param(cx: &ExtCtxt<'_>, cx.trait_bound(path) }) .collect(); - cx.typaram(span, cx.ident_of(name), attrs.to_owned(), bounds, None) + cx.typaram(span, cx.ident_of(name, span), attrs.to_owned(), bounds, None) } fn mk_generics(params: Vec, span: Span) -> Generics { @@ -265,7 +263,7 @@ impl<'a> LifetimeBounds<'a> { pub fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span, - self_ptr: &Option>) + self_ptr: &Option) -> (P, ast::ExplicitSelf) { // this constructs a fresh `self` path let self_path = cx.expr_self(span); @@ -276,7 +274,7 @@ pub fn get_explicit_self(cx: &ExtCtxt<'_>, respan(span, match *ptr { Borrowed(ref lt, mutbl) => { - let lt = lt.map(|s| cx.lifetime(span, Ident::from_str(s))); + let lt = lt.map(|s| cx.lifetime(span, s)); SelfKind::Region(lt, mutbl) } Raw(_) => { diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs index 9787722e81dd0..2fc594abd705e 100644 --- a/src/libsyntax_ext/deriving/hash.rs +++ b/src/libsyntax_ext/deriving/hash.rs @@ -16,7 +16,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt<'_>, let path = Path::new_(pathvec_std!(cx, hash::Hash), None, vec![], PathKind::Std); - let typaram = &*deriving::hygienic_type_parameter(item, "__H"); + let typaram = "__H"; let arg = Path::new_local(typaram); let hash_trait_def = TraitDef { diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 8cd2853e5383d..60b6eba7a4b53 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -48,46 +48,22 @@ impl MultiItemModifier for BuiltinDerive { meta_item: &MetaItem, item: Annotatable) -> Vec { + // FIXME: Built-in derives often forget to give spans contexts, + // so we are doing it here in a centralized way. + let span = ecx.with_def_site_ctxt(span); let mut items = Vec::new(); (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a)); items } } -/// Construct a name for the inner type parameter that can't collide with any type parameters of -/// the item. This is achieved by starting with a base and then concatenating the names of all -/// other type parameters. -// FIXME(aburka): use real hygiene when that becomes possible -fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String { - let mut typaram = String::from(base); - if let Annotatable::Item(ref item) = *item { - match item.node { - ast::ItemKind::Struct(_, ast::Generics { ref params, .. }) | - ast::ItemKind::Enum(_, ast::Generics { ref params, .. }) => { - for param in params { - match param.kind { - ast::GenericParamKind::Type { .. } => { - typaram.push_str(¶m.ident.as_str()); - } - _ => {} - } - } - } - - _ => {} - } - } - - typaram -} - /// Constructs an expression that calls an intrinsic fn call_intrinsic(cx: &ExtCtxt<'_>, span: Span, intrinsic: &str, args: Vec>) -> P { - let span = span.with_ctxt(cx.backtrace()); + let span = cx.with_def_site_ctxt(span); let path = cx.std_path(&[sym::intrinsics, Symbol::intern(intrinsic)]); let call = cx.expr_call_global(span, path, args); diff --git a/src/libsyntax_ext/env.rs b/src/libsyntax_ext/env.rs index 39fc90decc92a..02757bf6b1689 100644 --- a/src/libsyntax_ext/env.rs +++ b/src/libsyntax_ext/env.rs @@ -7,32 +7,32 @@ use syntax::ast::{self, Ident, GenericArg}; use syntax::ext::base::{self, *}; use syntax::symbol::{kw, sym, Symbol}; use syntax_pos::Span; -use syntax::tokenstream; +use syntax::tokenstream::TokenStream; use std::env; pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, - tts: &[tokenstream::TokenTree]) + tts: TokenStream) -> Box { let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") { - None => return DummyResult::expr(sp), + None => return DummyResult::any(sp), Some(v) => v, }; - let sp = sp.apply_mark(cx.current_expansion.id); + let sp = cx.with_def_site_ctxt(sp); let e = match env::var(&*var.as_str()) { Err(..) => { - let lt = cx.lifetime(sp, Ident::with_empty_ctxt(kw::StaticLifetime)); + let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp)); cx.expr_path(cx.path_all(sp, true, cx.std_path(&[sym::option, sym::Option, sym::None]), vec![GenericArg::Type(cx.ty_rptr(sp, cx.ty_ident(sp, - Ident::with_empty_ctxt(sym::str)), + Ident::new(sym::str, sp)), Some(lt), ast::Mutability::Immutable))], - vec![])) + )) } Ok(s) => { cx.expr_call_global(sp, @@ -45,26 +45,26 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt<'_>, pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, - tts: &[tokenstream::TokenTree]) + tts: TokenStream) -> Box { let mut exprs = match get_exprs_from_tts(cx, sp, tts) { Some(ref exprs) if exprs.is_empty() => { cx.span_err(sp, "env! takes 1 or 2 arguments"); - return DummyResult::expr(sp); + return DummyResult::any(sp); } - None => return DummyResult::expr(sp), + None => return DummyResult::any(sp), Some(exprs) => exprs.into_iter(), }; let var = match expr_to_string(cx, exprs.next().unwrap(), "expected string literal") { - None => return DummyResult::expr(sp), + None => return DummyResult::any(sp), Some((v, _style)) => v, }; let msg = match exprs.next() { None => Symbol::intern(&format!("environment variable `{}` not defined", var)), Some(second) => { match expr_to_string(cx, second, "expected string literal") { - None => return DummyResult::expr(sp), + None => return DummyResult::any(sp), Some((s, _style)) => s, } } @@ -72,13 +72,13 @@ pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt<'_>, if exprs.next().is_some() { cx.span_err(sp, "env! takes 1 or 2 arguments"); - return DummyResult::expr(sp); + return DummyResult::any(sp); } let e = match env::var(&*var.as_str()) { Err(_) => { cx.span_err(sp, &msg.as_str()); - return DummyResult::expr(sp); + return DummyResult::any(sp); } Ok(s) => cx.expr_str(sp, Symbol::intern(&s)), }; diff --git a/src/libsyntax_ext/error_codes.rs b/src/libsyntax_ext/error_codes.rs index 5982a4df226c2..2bc990574f7a8 100644 --- a/src/libsyntax_ext/error_codes.rs +++ b/src/libsyntax_ext/error_codes.rs @@ -1,9 +1,8 @@ -use syntax::register_long_diagnostics; - // Error messages for EXXXX errors. -// Each message should start and end with a new line, and be wrapped to 80 characters. -// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable. -register_long_diagnostics! { +// Each message should start and end with a new line, and be wrapped to 80 +// characters. In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use +// `:set tw=0` to disable. +syntax::register_diagnostics! { E0660: r##" The argument to the `asm` macro is not well-formed. diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 2a299cc4f9241..8fc64021b51fc 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -5,14 +5,15 @@ use fmt_macros as parse; use errors::DiagnosticBuilder; use errors::Applicability; +use errors::pluralise; use syntax::ast; use syntax::ext::base::{self, *}; use syntax::parse::token; use syntax::ptr::P; use syntax::symbol::{Symbol, sym}; -use syntax::tokenstream; -use syntax_pos::{MultiSpan, Span, DUMMY_SP}; +use syntax::tokenstream::TokenStream; +use syntax_pos::{MultiSpan, Span}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use std::borrow::Cow; @@ -126,7 +127,7 @@ struct Context<'a, 'b> { fn parse_args<'a>( ecx: &mut ExtCtxt<'a>, sp: Span, - tts: &[tokenstream::TokenTree] + tts: TokenStream, ) -> Result<(P, Vec>, FxHashMap), DiagnosticBuilder<'a>> { let mut args = Vec::>::new(); let mut names = FxHashMap::::default(); @@ -138,15 +139,23 @@ fn parse_args<'a>( } let fmtstr = p.parse_expr()?; + let mut first = true; let mut named = false; while p.token != token::Eof { if !p.eat(&token::Comma) { - let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`"); - err.span_label(p.token.span, "expected `,`"); - p.maybe_annotate_with_ascription(&mut err, false); - return Err(err); + if first { + // After `format!(""` we always expect *only* a comma... + let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`"); + err.span_label(p.token.span, "expected `,`"); + p.maybe_annotate_with_ascription(&mut err, false); + return Err(err); + } else { + // ...after that delegate to `expect` to also include the other expected tokens. + return Err(p.expect(&token::Comma).err().unwrap()); + } } + first = false; if p.token == token::Eof { break; } // accept trailing commas @@ -286,12 +295,12 @@ impl<'a, 'b> Context<'a, 'b> { .filter(|fmt| fmt.precision_span.is_some()) .count(); if self.names.is_empty() && !numbered_position_args && count != self.args.len() { - e = self.ecx.mut_span_err( + e = self.ecx.struct_span_err( sp, &format!( "{} positional argument{} in format string, but {}", count, - if count > 1 { "s" } else { "" }, + pluralise!(count), self.describe_num_args(), ), ); @@ -327,7 +336,7 @@ impl<'a, 'b> Context<'a, 'b> { sp = MultiSpan::from_span(self.fmtsp); } - e = self.ecx.mut_span_err(sp, + e = self.ecx.struct_span_err(sp, &format!("invalid reference to positional {} ({})", arg_list, self.describe_num_args())); @@ -478,7 +487,7 @@ impl<'a, 'b> Context<'a, 'b> { let sp = self.macsp; let count = |c, arg| { let mut path = Context::rtpath(self.ecx, "Count"); - path.push(self.ecx.ident_of(c)); + path.push(self.ecx.ident_of(c, sp)); match arg { Some(arg) => self.ecx.expr_call_global(sp, path, vec![arg]), None => self.ecx.expr_path(self.ecx.path_global(sp, path)), @@ -526,7 +535,7 @@ impl<'a, 'b> Context<'a, 'b> { let pos = { let pos = |c, arg| { let mut path = Context::rtpath(self.ecx, "Position"); - path.push(self.ecx.ident_of(c)); + path.push(self.ecx.ident_of(c, sp)); match arg { Some(i) => { let arg = self.ecx.expr_usize(sp, i); @@ -595,7 +604,7 @@ impl<'a, 'b> Context<'a, 'b> { let fill = self.ecx.expr_lit(sp, ast::LitKind::Char(fill)); let align = |name| { let mut p = Context::rtpath(self.ecx, "Alignment"); - p.push(self.ecx.ident_of(name)); + p.push(self.ecx.ident_of(name, sp)); self.ecx.path_global(sp, p) }; let align = match arg.format.align { @@ -613,11 +622,11 @@ impl<'a, 'b> Context<'a, 'b> { sp, path, vec![ - self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill), - self.ecx.field_imm(sp, self.ecx.ident_of("align"), align), - self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags), - self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec), - self.ecx.field_imm(sp, self.ecx.ident_of("width"), width), + self.ecx.field_imm(sp, self.ecx.ident_of("fill", sp), fill), + self.ecx.field_imm(sp, self.ecx.ident_of("align", sp), align), + self.ecx.field_imm(sp, self.ecx.ident_of("flags", sp), flags), + self.ecx.field_imm(sp, self.ecx.ident_of("precision", sp), prec), + self.ecx.field_imm(sp, self.ecx.ident_of("width", sp), width), ], ); @@ -626,8 +635,8 @@ impl<'a, 'b> Context<'a, 'b> { sp, path, vec![ - self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos), - self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt), + self.ecx.field_imm(sp, self.ecx.ident_of("position", sp), pos), + self.ecx.field_imm(sp, self.ecx.ident_of("format", sp), fmt), ], )) } @@ -645,7 +654,7 @@ impl<'a, 'b> Context<'a, 'b> { let mut heads = Vec::with_capacity(self.args.len()); let names_pos: Vec<_> = (0..self.args.len()) - .map(|i| self.ecx.ident_of(&format!("arg{}", i)).gensym()) + .map(|i| self.ecx.ident_of(&format!("arg{}", i), self.macsp)) .collect(); // First, build up the static array which will become our precompiled @@ -666,8 +675,7 @@ impl<'a, 'b> Context<'a, 'b> { // passed to this function. for (i, e) in self.args.into_iter().enumerate() { let name = names_pos[i]; - let span = - DUMMY_SP.with_ctxt(e.span.ctxt().apply_mark(self.ecx.current_expansion.id)); + let span = self.ecx.with_def_site_ctxt(e.span); pats.push(self.ecx.pat_ident(span, name)); for ref arg_ty in self.arg_unique_types[i].iter() { locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, name)); @@ -687,7 +695,7 @@ impl<'a, 'b> Context<'a, 'b> { // Now create a vector containing all the arguments let args = locals.into_iter().chain(counts.into_iter()); - let args_array = self.ecx.expr_vec(self.fmtsp, args.collect()); + let args_array = self.ecx.expr_vec(self.macsp, args.collect()); // Constructs an AST equivalent to: // @@ -716,12 +724,12 @@ impl<'a, 'b> Context<'a, 'b> { // // But the nested match expression is proved to perform not as well // as series of let's; the first approach does. - let pat = self.ecx.pat_tuple(self.fmtsp, pats); - let arm = self.ecx.arm(self.fmtsp, vec![pat], args_array); - let head = self.ecx.expr(self.fmtsp, ast::ExprKind::Tup(heads)); - let result = self.ecx.expr_match(self.fmtsp, head, vec![arm]); + let pat = self.ecx.pat_tuple(self.macsp, pats); + let arm = self.ecx.arm(self.macsp, pat, args_array); + let head = self.ecx.expr(self.macsp, ast::ExprKind::Tup(heads)); + let result = self.ecx.expr_match(self.macsp, head, vec![arm]); - let args_slice = self.ecx.expr_addr_of(self.fmtsp, result); + let args_slice = self.ecx.expr_addr_of(self.macsp, result); // Now create the fmt::Arguments struct with all our locals we created. let (fn_name, fn_args) = if self.all_pieces_simple { @@ -745,7 +753,7 @@ impl<'a, 'b> Context<'a, 'b> { ty: &ArgumentType, arg: ast::Ident, ) -> P { - sp = sp.apply_mark(ecx.current_expansion.id); + sp = ecx.with_def_site_ctxt(sp); let arg = ecx.expr_ident(sp, arg); let trait_ = match *ty { Placeholder(ref tyname) => { @@ -795,17 +803,17 @@ impl<'a, 'b> Context<'a, 'b> { fn expand_format_args_impl<'cx>( ecx: &'cx mut ExtCtxt<'_>, mut sp: Span, - tts: &[tokenstream::TokenTree], + tts: TokenStream, nl: bool, ) -> Box { - sp = sp.apply_mark(ecx.current_expansion.id); + sp = ecx.with_def_site_ctxt(sp); match parse_args(ecx, sp, tts) { Ok((efmt, args, names)) => { MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names, nl)) } Err(mut err) => { err.emit(); - DummyResult::expr(sp) + DummyResult::any(sp) } } } @@ -813,7 +821,7 @@ fn expand_format_args_impl<'cx>( pub fn expand_format_args<'cx>( ecx: &'cx mut ExtCtxt<'_>, sp: Span, - tts: &[tokenstream::TokenTree], + tts: TokenStream, ) -> Box { expand_format_args_impl(ecx, sp, tts, false) } @@ -821,7 +829,7 @@ pub fn expand_format_args<'cx>( pub fn expand_format_args_nl<'cx>( ecx: &'cx mut ExtCtxt<'_>, sp: Span, - tts: &[tokenstream::TokenTree], + tts: TokenStream, ) -> Box { expand_format_args_impl(ecx, sp, tts, true) } @@ -842,13 +850,13 @@ pub fn expand_preparsed_format_args( let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect(); let mut macsp = ecx.call_site(); - macsp = macsp.apply_mark(ecx.current_expansion.id); + macsp = ecx.with_def_site_ctxt(macsp); let msg = "format argument must be a string literal"; let fmt_sp = efmt.span; - let fmt = match expr_to_spanned_string(ecx, efmt, msg) { + let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt, msg) { Ok(mut fmt) if append_newline => { - fmt.node.0 = Symbol::intern(&format!("{}\n", fmt.node.0)); + fmt.0 = Symbol::intern(&format!("{}\n", fmt.0)); fmt } Ok(fmt) => fmt, @@ -875,7 +883,7 @@ pub fn expand_preparsed_format_args( _ => (false, None), }; - let str_style = match fmt.node.1 { + let str_style = match fmt_style { ast::StrStyle::Cooked => None, ast::StrStyle::Raw(raw) => { Some(raw as usize) @@ -981,7 +989,7 @@ pub fn expand_preparsed_format_args( vec![] }; - let fmt_str = &*fmt.node.0.as_str(); // for the suggestions below + let fmt_str = &*fmt_str.as_str(); // for the suggestions below let mut parser = parse::Parser::new(fmt_str, str_style, skips, append_newline); let mut unverified_pieces = Vec::new(); @@ -995,7 +1003,7 @@ pub fn expand_preparsed_format_args( if !parser.errors.is_empty() { let err = parser.errors.remove(0); - let sp = fmt.span.from_inner(err.span); + let sp = fmt_span.from_inner(err.span); let mut e = ecx.struct_span_err(sp, &format!("invalid format string: {}", err.description)); e.span_label(sp, err.label + " in format string"); @@ -1003,7 +1011,7 @@ pub fn expand_preparsed_format_args( e.note(¬e); } if let Some((label, span)) = err.secondary_label { - let sp = fmt.span.from_inner(span); + let sp = fmt_span.from_inner(span); e.span_label(sp, label); } e.emit(); @@ -1011,7 +1019,7 @@ pub fn expand_preparsed_format_args( } let arg_spans = parser.arg_places.iter() - .map(|span| fmt.span.from_inner(*span)) + .map(|span| fmt_span.from_inner(*span)) .collect(); let named_pos: FxHashSet = names.values().cloned().collect(); @@ -1034,7 +1042,7 @@ pub fn expand_preparsed_format_args( str_pieces: Vec::with_capacity(unverified_pieces.len()), all_pieces_simple: true, macsp, - fmtsp: fmt.span, + fmtsp: fmt_span, invalid_refs: Vec::new(), arg_spans, arg_with_formatting: Vec::new(), diff --git a/src/libsyntax_ext/global_allocator.rs b/src/libsyntax_ext/global_allocator.rs index f788b51380433..cd2a9b61a76df 100644 --- a/src/libsyntax_ext/global_allocator.rs +++ b/src/libsyntax_ext/global_allocator.rs @@ -1,9 +1,8 @@ use syntax::ast::{ItemKind, Mutability, Stmt, Ty, TyKind, Unsafety}; -use syntax::ast::{self, Arg, Attribute, Expr, FnHeader, Generics, Ident}; +use syntax::ast::{self, Param, Attribute, Expr, FnHeader, Generics, Ident}; use syntax::attr::check_builtin_macro_attribute; use syntax::ext::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; use syntax::ext::base::{Annotatable, ExtCtxt}; -use syntax::ext::hygiene::SyntaxContext; use syntax::ptr::P; use syntax::symbol::{kw, sym, Symbol}; use syntax_pos::Span; @@ -21,7 +20,7 @@ pub fn expand( vec![item] }; let item = match item { - Annotatable::Item(item) => match item.node { + Annotatable::Item(item) => match item.kind { ItemKind::Static(..) => item, _ => return not_static(Annotatable::Item(item)), } @@ -29,7 +28,7 @@ pub fn expand( }; // Generate a bunch of new items using the AllocFnFactory - let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.id)); + let span = ecx.with_def_site_ctxt(item.span); let f = AllocFnFactory { span, kind: AllocatorKind::Global, @@ -44,7 +43,7 @@ pub fn expand( let const_ty = ecx.ty(span, TyKind::Tup(Vec::new())); let const_body = ecx.expr_block(ecx.block(span, stmts)); let const_item = - ecx.item_const(span, Ident::with_empty_ctxt(kw::Underscore), const_ty, const_body); + ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); // Return the original item and the new methods. vec![Annotatable::Item(item), Annotatable::Item(const_item)] @@ -62,7 +61,7 @@ impl AllocFnFactory<'_, '_> { let mut abi_args = Vec::new(); let mut i = 0; let ref mut mk = || { - let name = Ident::from_str(&format!("arg{}", i)); + let name = self.cx.ident_of(&format!("arg{}", i), self.span); i += 1; name }; @@ -84,7 +83,7 @@ impl AllocFnFactory<'_, '_> { ); let item = self.cx.item( self.span, - Ident::from_str(&self.kind.fn_name(method.name)), + self.cx.ident_of(&self.kind.fn_name(method.name), self.span), self.attrs(), kind, ); @@ -115,17 +114,17 @@ impl AllocFnFactory<'_, '_> { fn arg_ty( &self, ty: &AllocatorTy, - args: &mut Vec, + args: &mut Vec, ident: &mut dyn FnMut() -> Ident, ) -> P { match *ty { AllocatorTy::Layout => { - let usize = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::usize)); + let usize = self.cx.path_ident(self.span, Ident::new(sym::usize, self.span)); let ty_usize = self.cx.ty_path(usize); let size = ident(); let align = ident(); - args.push(self.cx.arg(self.span, size, ty_usize.clone())); - args.push(self.cx.arg(self.span, align, ty_usize)); + args.push(self.cx.param(self.span, size, ty_usize.clone())); + args.push(self.cx.param(self.span, align, ty_usize)); let layout_new = self.cx.std_path(&[ Symbol::intern("alloc"), @@ -141,14 +140,14 @@ impl AllocFnFactory<'_, '_> { AllocatorTy::Ptr => { let ident = ident(); - args.push(self.cx.arg(self.span, ident, self.ptr_u8())); + args.push(self.cx.param(self.span, ident, self.ptr_u8())); let arg = self.cx.expr_ident(self.span, ident); self.cx.expr_cast(self.span, arg, self.ptr_u8()) } AllocatorTy::Usize => { let ident = ident(); - args.push(self.cx.arg(self.span, ident, self.usize())); + args.push(self.cx.param(self.span, ident, self.usize())); self.cx.expr_ident(self.span, ident) } @@ -178,12 +177,12 @@ impl AllocFnFactory<'_, '_> { } fn usize(&self) -> P { - let usize = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::usize)); + let usize = self.cx.path_ident(self.span, Ident::new(sym::usize, self.span)); self.cx.ty_path(usize) } fn ptr_u8(&self) -> P { - let u8 = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::u8)); + let u8 = self.cx.path_ident(self.span, Ident::new(sym::u8, self.span)); let ty_u8 = self.cx.ty_path(u8); self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable) } diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs index 112192fac5d26..72fb5b47c2154 100644 --- a/src/libsyntax_ext/global_asm.rs +++ b/src/libsyntax_ext/global_asm.rs @@ -16,21 +16,21 @@ use syntax::ext::base::{self, *}; use syntax::parse::token; use syntax::ptr::P; use syntax_pos::Span; -use syntax::tokenstream; +use syntax::tokenstream::TokenStream; use smallvec::smallvec; pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, - tts: &[tokenstream::TokenTree]) -> Box { + tts: TokenStream) -> Box { match parse_global_asm(cx, sp, tts) { Ok(Some(global_asm)) => { MacEager::items(smallvec![P(ast::Item { ident: ast::Ident::invalid(), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, - node: ast::ItemKind::GlobalAsm(P(global_asm)), + kind: ast::ItemKind::GlobalAsm(P(global_asm)), vis: respan(sp.shrink_to_lo(), ast::VisibilityKind::Inherited), - span: sp, + span: cx.with_def_site_ctxt(sp), tokens: None, })]) } @@ -45,7 +45,7 @@ pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt<'_>, fn parse_global_asm<'a>( cx: &mut ExtCtxt<'a>, sp: Span, - tts: &[tokenstream::TokenTree] + tts: TokenStream ) -> Result, DiagnosticBuilder<'a>> { let mut p = cx.new_parser_from_tts(tts); @@ -61,8 +61,5 @@ fn parse_global_asm<'a>( None => return Ok(None), }; - Ok(Some(ast::GlobalAsm { - asm, - ctxt: cx.backtrace(), - })) + Ok(Some(ast::GlobalAsm { asm })) } diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 0f3f5c0cd0eed..64d46a84cba47 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -5,15 +5,18 @@ #![feature(crate_visibility_modifier)] #![feature(decl_macro)] -#![feature(mem_take)] #![feature(nll)] -#![feature(rustc_diagnostic_macros)] +#![feature(proc_macro_internals)] +#![feature(proc_macro_quote)] + +extern crate proc_macro; use crate::deriving::*; use syntax::ast::Ident; use syntax::edition::Edition; use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind, MacroExpanderFn}; +use syntax::ext::proc_macro::BangProcMacro; use syntax::symbol::sym; mod error_codes; @@ -35,6 +38,7 @@ mod source_util; mod test; mod trace_macros; +pub mod cmdline_attrs; pub mod plugin_macro_defs; pub mod proc_macro_harness; pub mod standard_library_imports; @@ -42,7 +46,7 @@ pub mod test_harness; pub fn register_builtin_macros(resolver: &mut dyn syntax::ext::base::Resolver, edition: Edition) { let mut register = |name, kind| resolver.register_builtin_macro( - Ident::with_empty_ctxt(name), SyntaxExtension { + Ident::with_dummy_span(name), SyntaxExtension { is_builtin: true, ..SyntaxExtension::default(kind, edition) }, ); @@ -57,14 +61,13 @@ pub fn register_builtin_macros(resolver: &mut dyn syntax::ext::base::Resolver, e } register_bang! { - __rust_unstable_column: source_util::expand_column, asm: asm::expand_asm, assert: assert::expand_assert, cfg: cfg::expand_cfg, column: source_util::expand_column, compile_error: compile_error::expand_compile_error, - concat_idents: concat_idents::expand_syntax_ext, - concat: concat::expand_syntax_ext, + concat_idents: concat_idents::expand_concat_idents, + concat: concat::expand_concat, env: env::expand_env, file: source_util::expand_file, format_args_nl: format::expand_format_args_nl, @@ -74,7 +77,7 @@ pub fn register_builtin_macros(resolver: &mut dyn syntax::ext::base::Resolver, e include_str: source_util::expand_include_str, include: source_util::expand_include, line: source_util::expand_line, - log_syntax: log_syntax::expand_syntax_ext, + log_syntax: log_syntax::expand_log_syntax, module_path: source_util::expand_mod, option_env: env::expand_option_env, stringify: source_util::expand_stringify, @@ -101,4 +104,7 @@ pub fn register_builtin_macros(resolver: &mut dyn syntax::ext::base::Resolver, e RustcDecodable: decodable::expand_deriving_rustc_decodable, RustcEncodable: encodable::expand_deriving_rustc_encodable, } + + let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote); + register(sym::quote, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client }))); } diff --git a/src/libsyntax_ext/log_syntax.rs b/src/libsyntax_ext/log_syntax.rs index cbdfd08b4977f..92130bfaf68e3 100644 --- a/src/libsyntax_ext/log_syntax.rs +++ b/src/libsyntax_ext/log_syntax.rs @@ -1,11 +1,11 @@ use syntax::ext::base; use syntax::print; -use syntax::tokenstream; +use syntax::tokenstream::TokenStream; use syntax_pos; -pub fn expand_syntax_ext<'cx>(_cx: &'cx mut base::ExtCtxt<'_>, +pub fn expand_log_syntax<'cx>(_cx: &'cx mut base::ExtCtxt<'_>, sp: syntax_pos::Span, - tts: &[tokenstream::TokenTree]) + tts: TokenStream) -> Box { println!("{}", print::pprust::tts_to_string(tts)); diff --git a/src/libsyntax_ext/plugin_macro_defs.rs b/src/libsyntax_ext/plugin_macro_defs.rs index a725f5e46ad1c..315babceae32c 100644 --- a/src/libsyntax_ext/plugin_macro_defs.rs +++ b/src/libsyntax_ext/plugin_macro_defs.rs @@ -11,7 +11,7 @@ use syntax::source_map::respan; use syntax::symbol::sym; use syntax::tokenstream::*; use syntax_pos::{Span, DUMMY_SP}; -use syntax_pos::hygiene::{ExpnId, ExpnInfo, ExpnKind, MacroKind}; +use syntax_pos::hygiene::{ExpnData, ExpnKind, AstPass}; use std::mem; @@ -28,7 +28,7 @@ fn plugin_macro_def(name: Name, span: Span) -> P { ident: Ident::new(name, span), attrs: vec![rustc_builtin_macro], id: DUMMY_NODE_ID, - node: ItemKind::MacroDef(MacroDef { tokens: TokenStream::new(trees), legacy: true }), + kind: ItemKind::MacroDef(MacroDef { tokens: TokenStream::new(trees), legacy: true }), vis: respan(span, VisibilityKind::Inherited), span: span, tokens: None, @@ -43,12 +43,12 @@ pub fn inject( ) { if !named_exts.is_empty() { let mut extra_items = Vec::new(); - let span = DUMMY_SP.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable( - ExpnKind::Macro(MacroKind::Attr, sym::plugin), DUMMY_SP, edition, + let span = DUMMY_SP.fresh_expansion(ExpnData::allow_unstable( + ExpnKind::AstPass(AstPass::PluginMacroDefs), DUMMY_SP, edition, [sym::rustc_attrs][..].into(), )); for (name, ext) in named_exts { - resolver.register_builtin_macro(Ident::with_empty_ctxt(name), ext); + resolver.register_builtin_macro(Ident::with_dummy_span(name), ext); extra_items.push(plugin_macro_def(name, span)); } // The `macro_rules` items must be inserted before any other items. diff --git a/src/libsyntax_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs index 7913a7442edc7..9b53bcb841c67 100644 --- a/src/libsyntax_ext/proc_macro_harness.rs +++ b/src/libsyntax_ext/proc_macro_harness.rs @@ -1,19 +1,17 @@ use std::mem; +use smallvec::smallvec; use syntax::ast::{self, Ident}; use syntax::attr; -use syntax::source_map::{ExpnInfo, ExpnKind, respan}; -use syntax::ext::base::{ExtCtxt, MacroKind}; -use syntax::ext::expand::ExpansionConfig; -use syntax::ext::hygiene::ExpnId; +use syntax::ext::base::ExtCtxt; +use syntax::ext::expand::{AstFragment, ExpansionConfig}; use syntax::ext::proc_macro::is_proc_macro_attr; -use syntax::mut_visit::MutVisitor; use syntax::parse::ParseSess; use syntax::ptr::P; use syntax::symbol::{kw, sym}; use syntax::visit::{self, Visitor}; - use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::hygiene::AstPass; struct ProcMacroDerive { trait_name: ast::Name, @@ -22,15 +20,24 @@ struct ProcMacroDerive { attrs: Vec, } +enum ProcMacroDefType { + Attr, + Bang +} + struct ProcMacroDef { function_name: Ident, span: Span, + def_type: ProcMacroDefType +} + +enum ProcMacro { + Derive(ProcMacroDerive), + Def(ProcMacroDef) } struct CollectProcMacros<'a> { - derives: Vec, - attr_macros: Vec, - bang_macros: Vec, + macros: Vec, in_root: bool, handler: &'a errors::Handler, is_proc_macro_crate: bool, @@ -48,22 +55,22 @@ pub fn inject(sess: &ParseSess, let ecfg = ExpansionConfig::default("proc_macro".to_string()); let mut cx = ExtCtxt::new(sess, ecfg, resolver); - let (derives, attr_macros, bang_macros) = { - let mut collect = CollectProcMacros { - derives: Vec::new(), - attr_macros: Vec::new(), - bang_macros: Vec::new(), - in_root: true, - handler, - is_proc_macro_crate, - is_test_crate, - }; - if has_proc_macro_decls || is_proc_macro_crate { - visit::walk_crate(&mut collect, &krate); - } - (collect.derives, collect.attr_macros, collect.bang_macros) + let mut collect = CollectProcMacros { + macros: Vec::new(), + in_root: true, + handler, + is_proc_macro_crate, + is_test_crate, }; + if has_proc_macro_decls || is_proc_macro_crate { + visit::walk_crate(&mut collect, &krate); + } + // NOTE: If you change the order of macros in this vec + // for any reason, you must also update 'raw_proc_macro' + // in src/librustc_metadata/decoder.rs + let macros = collect.macros; + if !is_proc_macro_crate { return krate } @@ -76,7 +83,7 @@ pub fn inject(sess: &ParseSess, return krate; } - krate.module.items.push(mk_decls(&mut cx, &derives, &attr_macros, &bang_macros)); + krate.module.items.push(mk_decls(&mut cx, ¯os)); krate } @@ -163,12 +170,12 @@ impl<'a> CollectProcMacros<'a> { }; if self.in_root && item.vis.node.is_pub() { - self.derives.push(ProcMacroDerive { + self.macros.push(ProcMacro::Derive(ProcMacroDerive { span: item.span, trait_name: trait_ident.name, function_name: item.ident, attrs: proc_attrs, - }); + })); } else { let msg = if !self.in_root { "functions tagged with `#[proc_macro_derive]` must \ @@ -182,10 +189,11 @@ impl<'a> CollectProcMacros<'a> { fn collect_attr_proc_macro(&mut self, item: &'a ast::Item) { if self.in_root && item.vis.node.is_pub() { - self.attr_macros.push(ProcMacroDef { + self.macros.push(ProcMacro::Def(ProcMacroDef { span: item.span, function_name: item.ident, - }); + def_type: ProcMacroDefType::Attr + })); } else { let msg = if !self.in_root { "functions tagged with `#[proc_macro_attribute]` must \ @@ -199,10 +207,11 @@ impl<'a> CollectProcMacros<'a> { fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) { if self.in_root && item.vis.node.is_pub() { - self.bang_macros.push(ProcMacroDef { + self.macros.push(ProcMacro::Def(ProcMacroDef { span: item.span, function_name: item.ident, - }); + def_type: ProcMacroDefType::Bang + })); } else { let msg = if !self.in_root { "functions tagged with `#[proc_macro]` must \ @@ -217,7 +226,7 @@ impl<'a> CollectProcMacros<'a> { impl<'a> Visitor<'a> for CollectProcMacros<'a> { fn visit_item(&mut self, item: &'a ast::Item) { - if let ast::ItemKind::MacroDef(..) = item.node { + if let ast::ItemKind::MacroDef(..) = item.kind { if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) { let msg = "cannot export macro_rules! macros from a `proc-macro` crate type currently"; @@ -229,7 +238,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { // we're just not interested in this item. // // If we find one, try to locate a `#[proc_macro_derive]` attribute on it. - let is_fn = match item.node { + let is_fn = match item.kind { ast::ItemKind::Fn(..) => true, _ => false, }; @@ -310,8 +319,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { // Creates a new module which looks like: // -// #[doc(hidden)] -// mod $gensym { +// const _: () = { // extern crate proc_macro; // // use proc_macro::bridge::client::ProcMacro; @@ -325,65 +333,67 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { // } fn mk_decls( cx: &mut ExtCtxt<'_>, - custom_derives: &[ProcMacroDerive], - custom_attrs: &[ProcMacroDef], - custom_macros: &[ProcMacroDef], + macros: &[ProcMacro], ) -> P { - let span = DUMMY_SP.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable( - ExpnKind::Macro(MacroKind::Attr, sym::proc_macro), DUMMY_SP, cx.parse_sess.edition, - [sym::rustc_attrs, sym::proc_macro_internals][..].into(), - )); - - let hidden = cx.meta_list_item_word(span, sym::hidden); - let doc = cx.meta_list(span, sym::doc, vec![hidden]); - let doc_hidden = cx.attribute(doc); - - let proc_macro = Ident::with_empty_ctxt(sym::proc_macro); + let expn_id = cx.resolver.expansion_for_ast_pass( + DUMMY_SP, + AstPass::ProcMacroHarness, + &[sym::rustc_attrs, sym::proc_macro_internals], + None, + ); + let span = DUMMY_SP.with_def_site_ctxt(expn_id); + + let proc_macro = Ident::new(sym::proc_macro, span); let krate = cx.item(span, proc_macro, Vec::new(), ast::ItemKind::ExternCrate(None)); - let bridge = Ident::from_str("bridge"); - let client = Ident::from_str("client"); - let proc_macro_ty = Ident::from_str("ProcMacro"); - let custom_derive = Ident::from_str("custom_derive"); - let attr = Ident::from_str("attr"); - let bang = Ident::from_str("bang"); - let crate_kw = Ident::with_empty_ctxt(kw::Crate); + let bridge = cx.ident_of("bridge", span); + let client = cx.ident_of("client", span); + let proc_macro_ty = cx.ident_of("ProcMacro", span); + let custom_derive = cx.ident_of("custom_derive", span); + let attr = cx.ident_of("attr", span); + let bang = cx.ident_of("bang", span); let decls = { let local_path = |sp: Span, name| { - cx.expr_path(cx.path(sp.with_ctxt(span.ctxt()), vec![crate_kw, name])) + cx.expr_path(cx.path(sp.with_ctxt(span.ctxt()), vec![name])) }; let proc_macro_ty_method_path = |method| cx.expr_path(cx.path(span, vec![ proc_macro, bridge, client, proc_macro_ty, method, ])); - custom_derives.iter().map(|cd| { - cx.expr_call(span, proc_macro_ty_method_path(custom_derive), vec![ - cx.expr_str(cd.span, cd.trait_name), - cx.expr_vec_slice( - span, - cd.attrs.iter().map(|&s| cx.expr_str(cd.span, s)).collect::>() - ), - local_path(cd.span, cd.function_name), - ]) - }).chain(custom_attrs.iter().map(|ca| { - cx.expr_call(span, proc_macro_ty_method_path(attr), vec![ - cx.expr_str(ca.span, ca.function_name.name), - local_path(ca.span, ca.function_name), - ]) - })).chain(custom_macros.iter().map(|cm| { - cx.expr_call(span, proc_macro_ty_method_path(bang), vec![ - cx.expr_str(cm.span, cm.function_name.name), - local_path(cm.span, cm.function_name), - ]) - })).collect() + macros.iter().map(|m| { + match m { + ProcMacro::Derive(cd) => { + cx.expr_call(span, proc_macro_ty_method_path(custom_derive), vec![ + cx.expr_str(cd.span, cd.trait_name), + cx.expr_vec_slice( + span, + cd.attrs.iter().map(|&s| cx.expr_str(cd.span, s)).collect::>() + ), + local_path(cd.span, cd.function_name), + ]) + }, + ProcMacro::Def(ca) => { + let ident = match ca.def_type { + ProcMacroDefType::Attr => attr, + ProcMacroDefType::Bang => bang + }; + + cx.expr_call(span, proc_macro_ty_method_path(ident), vec![ + cx.expr_str(ca.span, ca.function_name.name), + local_path(ca.span, ca.function_name), + ]) + + } + } + }).collect() }; let decls_static = cx.item_static( span, - Ident::from_str("_DECLS"), + cx.ident_of("_DECLS", span), cx.ty_rptr(span, cx.ty(span, ast::TyKind::Slice( cx.ty_path(cx.path(span, @@ -394,20 +404,22 @@ fn mk_decls( ).map(|mut i| { let attr = cx.meta_word(span, sym::rustc_proc_macro_decls); i.attrs.push(cx.attribute(attr)); - i.vis = respan(span, ast::VisibilityKind::Public); i }); - let module = cx.item_mod( - span, + let block = cx.expr_block(cx.block( span, - ast::Ident::from_str("decls").gensym(), - vec![doc_hidden], - vec![krate, decls_static], - ).map(|mut i| { - i.vis = respan(span, ast::VisibilityKind::Public); - i - }); + vec![cx.stmt_item(span, krate), cx.stmt_item(span, decls_static)], + )); - cx.monotonic_expander().flat_map_item(module).pop().unwrap() + let anon_constant = cx.item_const( + span, + ast::Ident::new(kw::Underscore, span), + cx.ty(span, ast::TyKind::Tup(Vec::new())), + block, + ); + + // Integrate the new item into existing module structures. + let items = AstFragment::Items(smallvec![anon_constant]); + cx.monotonic_expander().fully_expand_fragment(items).make_items().pop().unwrap() } diff --git a/src/libsyntax_ext/source_util.rs b/src/libsyntax_ext/source_util.rs index 2c8d53a231550..f74507dcc21f6 100644 --- a/src/libsyntax_ext/source_util.rs +++ b/src/libsyntax_ext/source_util.rs @@ -4,13 +4,12 @@ use syntax::parse::{self, token, DirectoryOwnership}; use syntax::print::pprust; use syntax::ptr::P; use syntax::symbol::Symbol; -use syntax::tokenstream; +use syntax::tokenstream::TokenStream; +use syntax::early_buffered_lints::BufferedEarlyLintId; use smallvec::SmallVec; use syntax_pos::{self, Pos, Span}; -use std::fs; -use std::io::ErrorKind; use rustc_data_structures::sync::Lrc; // These macros all relate to the file system; they either return @@ -18,7 +17,7 @@ use rustc_data_structures::sync::Lrc; // a given file into the current one. /// line!(): expands to the current line number -pub fn expand_line(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree]) +pub fn expand_line(cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream) -> Box { base::check_zero_tts(cx, sp, tts, "line!"); @@ -29,7 +28,7 @@ pub fn expand_line(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree } /* column!(): expands to the current column number */ -pub fn expand_column(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree]) +pub fn expand_column(cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream) -> Box { base::check_zero_tts(cx, sp, tts, "column!"); @@ -42,7 +41,7 @@ pub fn expand_column(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTr /// file!(): expands to the current filename */ /// The source_file (`loc.file`) contains a bunch more information we could spit /// out if we wanted. -pub fn expand_file(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree]) +pub fn expand_file(cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream) -> Box { base::check_zero_tts(cx, sp, tts, "file!"); @@ -51,13 +50,13 @@ pub fn expand_file(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree base::MacEager::expr(cx.expr_str(topmost, Symbol::intern(&loc.file.name.to_string()))) } -pub fn expand_stringify(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree]) +pub fn expand_stringify(cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream) -> Box { let s = pprust::tts_to_string(tts); base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&s))) } -pub fn expand_mod(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree]) +pub fn expand_mod(cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream) -> Box { base::check_zero_tts(cx, sp, tts, "module_path!"); let mod_path = &cx.current_expansion.module.mod_path; @@ -69,7 +68,7 @@ pub fn expand_mod(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree] /// include! : parse the given file as an expr /// This is generally a bad idea because it's going to behave /// unhygienically. -pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree]) +pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream) -> Box { let file = match get_single_str_from_tts(cx, sp, tts, "include!") { Some(f) => f, @@ -85,7 +84,16 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: &[tokenstrea } impl<'a> base::MacResult for ExpandResult<'a> { fn make_expr(mut self: Box>) -> Option> { - Some(panictry!(self.p.parse_expr())) + let r = panictry!(self.p.parse_expr()); + if self.p.token != token::Eof { + self.p.sess.buffer_lint( + BufferedEarlyLintId::IncompleteInclude, + self.p.token.span, + ast::CRATE_NODE_ID, + "include macro expected single expression in source", + ); + } + Some(r) } fn make_items(mut self: Box>) -> Option; 1]>> { @@ -107,58 +115,45 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: &[tokenstrea } // include_str! : read the given file, insert it as a literal string expr -pub fn expand_include_str(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree]) +pub fn expand_include_str(cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream) -> Box { let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") { Some(f) => f, - None => return DummyResult::expr(sp) + None => return DummyResult::any(sp) }; let file = cx.resolve_path(file, sp); - match fs::read_to_string(&file) { - Ok(src) => { - let interned_src = Symbol::intern(&src); - - // Add this input file to the code map to make it available as - // dependency information - cx.source_map().new_source_file(file.into(), src); - - base::MacEager::expr(cx.expr_str(sp, interned_src)) + match cx.source_map().load_binary_file(&file) { + Ok(bytes) => match std::str::from_utf8(&bytes) { + Ok(src) => { + let interned_src = Symbol::intern(&src); + base::MacEager::expr(cx.expr_str(sp, interned_src)) + } + Err(_) => { + cx.span_err(sp, &format!("{} wasn't a utf-8 file", file.display())); + DummyResult::any(sp) + } }, - Err(ref e) if e.kind() == ErrorKind::InvalidData => { - cx.span_err(sp, &format!("{} wasn't a utf-8 file", file.display())); - DummyResult::expr(sp) - } Err(e) => { cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e)); - DummyResult::expr(sp) + DummyResult::any(sp) } } } -pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree]) +pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream) -> Box { let file = match get_single_str_from_tts(cx, sp, tts, "include_bytes!") { Some(f) => f, - None => return DummyResult::expr(sp) + None => return DummyResult::any(sp) }; let file = cx.resolve_path(file, sp); - match fs::read(&file) { + match cx.source_map().load_binary_file(&file) { Ok(bytes) => { - // Add the contents to the source map if it contains UTF-8. - let (contents, bytes) = match String::from_utf8(bytes) { - Ok(s) => { - let bytes = s.as_bytes().to_owned(); - (s, bytes) - }, - Err(e) => (String::new(), e.into_bytes()), - }; - cx.source_map().new_source_file(file.into(), contents); - base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Lrc::new(bytes)))) }, Err(e) => { cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e)); - DummyResult::expr(sp) + DummyResult::any(sp) } } } diff --git a/src/libsyntax_ext/standard_library_imports.rs b/src/libsyntax_ext/standard_library_imports.rs index 68b13bdd171a9..c577b1e33cfeb 100644 --- a/src/libsyntax_ext/standard_library_imports.rs +++ b/src/libsyntax_ext/standard_library_imports.rs @@ -1,86 +1,86 @@ use syntax::{ast, attr}; use syntax::edition::Edition; -use syntax::ext::hygiene::{ExpnId, MacroKind}; +use syntax::ext::expand::ExpansionConfig; +use syntax::ext::hygiene::AstPass; +use syntax::ext::base::{ExtCtxt, Resolver}; +use syntax::parse::ParseSess; use syntax::ptr::P; -use syntax::source_map::{ExpnInfo, ExpnKind, dummy_spanned, respan}; use syntax::symbol::{Ident, Symbol, kw, sym}; use syntax_pos::DUMMY_SP; -use std::iter; - pub fn inject( - mut krate: ast::Crate, alt_std_name: Option<&str>, edition: Edition + mut krate: ast::Crate, + resolver: &mut dyn Resolver, + sess: &ParseSess, + alt_std_name: Option, ) -> (ast::Crate, Option) { - let rust_2018 = edition >= Edition::Edition2018; + let rust_2018 = sess.edition >= Edition::Edition2018; // the first name in this list is the crate name of the crate with the prelude - let names: &[&str] = if attr::contains_name(&krate.attrs, sym::no_core) { + let names: &[Symbol] = if attr::contains_name(&krate.attrs, sym::no_core) { return (krate, None); } else if attr::contains_name(&krate.attrs, sym::no_std) { if attr::contains_name(&krate.attrs, sym::compiler_builtins) { - &["core"] + &[sym::core] } else { - &["core", "compiler_builtins"] + &[sym::core, sym::compiler_builtins] } } else { - &["std"] + &[sym::std] }; + let expn_id = resolver.expansion_for_ast_pass( + DUMMY_SP, + AstPass::StdImports, + &[sym::prelude_import], + None, + ); + let span = DUMMY_SP.with_def_site_ctxt(expn_id); + let call_site = DUMMY_SP.with_call_site_ctxt(expn_id); + + let ecfg = ExpansionConfig::default("std_lib_injection".to_string()); + let cx = ExtCtxt::new(sess, ecfg, resolver); + + // .rev() to preserve ordering above in combination with insert(0, ...) - let alt_std_name = alt_std_name.map(Symbol::intern); - for orig_name_str in names.iter().rev() { - // HACK(eddyb) gensym the injected crates on the Rust 2018 edition, - // so they don't accidentally interfere with the new import paths. - let orig_name_sym = Symbol::intern(orig_name_str); - let orig_name_ident = Ident::with_empty_ctxt(orig_name_sym); - let (rename, orig_name) = if rust_2018 { - (orig_name_ident.gensym(), Some(orig_name_sym)) + for &name in names.iter().rev() { + let ident = if rust_2018 { + Ident::new(name, span) } else { - (orig_name_ident, None) + Ident::new(name, call_site) }; - krate.module.items.insert(0, P(ast::Item { - attrs: vec![attr::mk_attr_outer( - attr::mk_word_item(ast::Ident::with_empty_ctxt(sym::macro_use)) - )], - vis: dummy_spanned(ast::VisibilityKind::Inherited), - node: ast::ItemKind::ExternCrate(alt_std_name.or(orig_name)), - ident: rename, - id: ast::DUMMY_NODE_ID, - span: DUMMY_SP, - tokens: None, - })); + krate.module.items.insert(0, cx.item( + span, + ident, + vec![cx.attribute(cx.meta_word(span, sym::macro_use))], + ast::ItemKind::ExternCrate(alt_std_name), + )); } - // the crates have been injected, the assumption is that the first one is the one with - // the prelude. + // The crates have been injected, the assumption is that the first one is + // the one with the prelude. let name = names[0]; - let span = DUMMY_SP.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable( - ExpnKind::Macro(MacroKind::Attr, sym::std_inject), DUMMY_SP, edition, - [sym::prelude_import][..].into(), - )); + let import_path = if rust_2018 { + [name, sym::prelude, sym::v1].iter() + .map(|symbol| ast::Ident::new(*symbol, span)).collect() + } else { + [kw::PathRoot, name, sym::prelude, sym::v1].iter() + .map(|symbol| ast::Ident::new(*symbol, span)).collect() + }; - krate.module.items.insert(0, P(ast::Item { - attrs: vec![attr::mk_attr_outer( - attr::mk_word_item(ast::Ident::new(sym::prelude_import, span)))], - vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), - node: ast::ItemKind::Use(P(ast::UseTree { - prefix: ast::Path { - segments: iter::once(ast::Ident::with_empty_ctxt(kw::PathRoot)) - .chain( - [name, "prelude", "v1"].iter().cloned() - .map(ast::Ident::from_str) - ).map(ast::PathSegment::from_ident).collect(), - span, - }, + let use_item = cx.item( + span, + ast::Ident::invalid(), + vec![cx.attribute(cx.meta_word(span, sym::prelude_import))], + ast::ItemKind::Use(P(ast::UseTree { + prefix: cx.path(span, import_path), kind: ast::UseTreeKind::Glob, span, })), - id: ast::DUMMY_NODE_ID, - ident: ast::Ident::invalid(), - span, - tokens: None, - })); + ); + + krate.module.items.insert(0, use_item); - (krate, Some(Symbol::intern(name))) + (krate, Some(name)) } diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs index 993ef25752757..d4638c45473b1 100644 --- a/src/libsyntax_ext/test.rs +++ b/src/libsyntax_ext/test.rs @@ -4,7 +4,6 @@ use syntax::ast; use syntax::attr::{self, check_builtin_macro_attribute}; use syntax::ext::base::*; -use syntax::ext::hygiene::SyntaxContext; use syntax::print::pprust; use syntax::source_map::respan; use syntax::symbol::{Symbol, sym}; @@ -29,11 +28,11 @@ pub fn expand_test_case( if !ecx.ecfg.should_test { return vec![]; } - let sp = attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.id)); + let sp = ecx.with_def_site_ctxt(attr_sp); let mut item = anno_item.expect_item(); item = item.map(|mut item| { item.vis = respan(item.vis.span, ast::VisibilityKind::Public); - item.ident = item.ident.gensym(); + item.ident.span = item.ident.span.with_ctxt(sp.ctxt()); item.attrs.push( ecx.attribute(ecx.meta_word(sp, sym::rustc_test_marker)) ); @@ -79,7 +78,7 @@ pub fn expand_test_or_bench( "`#[test]` attribute is only allowed on non associated functions").raise(); }; - if let ast::ItemKind::Mac(_) = item.node { + if let ast::ItemKind::Mac(_) = item.kind { cx.parse_sess.span_diagnostic.span_warn(item.span, "`#[test]` attribute should not be used on macros. Use `#[cfg(test)]` instead."); return vec![Annotatable::Item(item)]; @@ -93,28 +92,31 @@ pub fn expand_test_or_bench( return vec![Annotatable::Item(item)]; } - let ctxt = SyntaxContext::empty().apply_mark(cx.current_expansion.id); - let (sp, attr_sp) = (item.span.with_ctxt(ctxt), attr_sp.with_ctxt(ctxt)); + let (sp, attr_sp) = (cx.with_def_site_ctxt(item.span), cx.with_def_site_ctxt(attr_sp)); - // Gensym "test" so we can extern crate without conflicting with any local names - let test_id = cx.ident_of("test").gensym(); + let test_id = ast::Ident::new(sym::test, attr_sp); // creates test::$name let test_path = |name| { - cx.path(sp, vec![test_id, cx.ident_of(name)]) + cx.path(sp, vec![test_id, cx.ident_of(name, sp)]) }; // creates test::ShouldPanic::$name let should_panic_path = |name| { - cx.path(sp, vec![test_id, cx.ident_of("ShouldPanic"), cx.ident_of(name)]) + cx.path(sp, vec![test_id, cx.ident_of("ShouldPanic", sp), cx.ident_of(name, sp)]) + }; + + // creates test::TestType::$name + let test_type_path = |name| { + cx.path(sp, vec![test_id, cx.ident_of("TestType", sp), cx.ident_of(name, sp)]) }; // creates $name: $expr - let field = |name, expr| cx.field_imm(sp, cx.ident_of(name), expr); + let field = |name, expr| cx.field_imm(sp, cx.ident_of(name, sp), expr); let test_fn = if is_bench { // A simple ident for a lambda - let b = cx.ident_of("b"); + let b = cx.ident_of("b", attr_sp); cx.expr_call(sp, cx.expr_path(test_path("StaticBenchFn")), vec![ // |b| self::test::assert_test_result( @@ -145,11 +147,11 @@ pub fn expand_test_or_bench( ]) }; - let mut test_const = cx.item(sp, ast::Ident::new(item.ident.name, sp).gensym(), + let mut test_const = cx.item(sp, ast::Ident::new(item.ident.name, sp), vec![ // #[cfg(test)] - cx.attribute(cx.meta_list(attr_sp, sym::cfg, vec![ - cx.meta_list_item_word(attr_sp, sym::test) + cx.attribute(attr::mk_list_item(ast::Ident::new(sym::cfg, attr_sp), vec![ + attr::mk_nested_word_item(ast::Ident::new(sym::test, attr_sp)) ])), // #[rustc_test_marker] cx.attribute(cx.meta_word(attr_sp, sym::rustc_test_marker)), @@ -184,6 +186,17 @@ pub fn expand_test_or_bench( cx.expr_path(should_panic_path("YesWithMessage")), vec![cx.expr_str(sp, sym)]), }), + // test_type: ... + field("test_type", match test_type(cx) { + // test::TestType::UnitTest + TestType::UnitTest => cx.expr_path(test_type_path("UnitTest")), + // test::TestType::IntegrationTest + TestType::IntegrationTest => cx.expr_path( + test_type_path("IntegrationTest") + ), + // test::TestPath::Unknown + TestType::Unknown => cx.expr_path(test_type_path("Unknown")), + }), // }, ])), // testfn: test::StaticTestFn(...) | test::StaticBenchFn(...) @@ -194,17 +207,17 @@ pub fn expand_test_or_bench( )); test_const = test_const.map(|mut tc| { tc.vis.node = ast::VisibilityKind::Public; tc}); - // extern crate test as test_gensym + // extern crate test let test_extern = cx.item(sp, test_id, vec![], - ast::ItemKind::ExternCrate(Some(sym::test)) + ast::ItemKind::ExternCrate(None) ); log::debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const)); vec![ - // Access to libtest under a gensymed name + // Access to libtest under a hygienic name Annotatable::Item(test_extern), // The generated test case Annotatable::Item(test_const), @@ -264,10 +277,38 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { } } +enum TestType { + UnitTest, + IntegrationTest, + Unknown, +} + +/// Attempts to determine the type of test. +/// Since doctests are created without macro expanding, only possible variants here +/// are `UnitTest`, `IntegrationTest` or `Unknown`. +fn test_type(cx: &ExtCtxt<'_>) -> TestType { + // Root path from context contains the topmost sources directory of the crate. + // I.e., for `project` with sources in `src` and tests in `tests` folders + // (no matter how many nested folders lie inside), + // there will be two different root paths: `/project/src` and `/project/tests`. + let crate_path = cx.root_path.as_path(); + + if crate_path.ends_with("src") { + // `/src` folder contains unit-tests. + TestType::UnitTest + } else if crate_path.ends_with("tests") { + // `/tests` folder contains integration tests. + TestType::IntegrationTest + } else { + // Crate layout doesn't match expected one, test type is unknown. + TestType::Unknown + } +} + fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic); let ref sd = cx.parse_sess.span_diagnostic; - if let ast::ItemKind::Fn(ref decl, ref header, ref generics, _) = i.node { + if let ast::ItemKind::Fn(ref decl, ref header, ref generics, _) = i.kind { if header.unsafety == ast::Unsafety::Unsafe { sd.span_err( i.span, @@ -288,7 +329,7 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { // type implements the `Termination` trait as `libtest` enforces that. let has_output = match decl.output { ast::FunctionRetTy::Default(..) => false, - ast::FunctionRetTy::Ty(ref t) if t.node.is_unit() => false, + ast::FunctionRetTy::Ty(ref t) if t.kind.is_unit() => false, _ => true }; @@ -318,7 +359,7 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { } fn has_bench_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { - let has_sig = if let ast::ItemKind::Fn(ref decl, _, _, _) = i.node { + let has_sig = if let ast::ItemKind::Fn(ref decl, _, _, _) = i.kind { // N.B., inadequate check, but we're running // well before resolve, can't get too deep. decl.inputs.len() == 1 diff --git a/src/libsyntax_ext/test_harness.rs b/src/libsyntax_ext/test_harness.rs index eec8a3f802343..f79ad1419e0b1 100644 --- a/src/libsyntax_ext/test_harness.rs +++ b/src/libsyntax_ext/test_harness.rs @@ -2,36 +2,35 @@ use log::debug; use smallvec::{smallvec, SmallVec}; +use rustc_target::spec::PanicStrategy; use syntax::ast::{self, Ident}; use syntax::attr; use syntax::entry::{self, EntryPointType}; use syntax::ext::base::{ExtCtxt, Resolver}; -use syntax::ext::expand::ExpansionConfig; -use syntax::ext::hygiene::{ExpnId, MacroKind}; +use syntax::ext::expand::{AstFragment, ExpansionConfig}; use syntax::feature_gate::Features; use syntax::mut_visit::{*, ExpectOne}; use syntax::parse::ParseSess; use syntax::ptr::P; -use syntax::source_map::{ExpnInfo, ExpnKind, dummy_spanned}; -use syntax::symbol::{kw, sym, Symbol}; +use syntax::source_map::respan; +use syntax::symbol::{sym, Symbol}; use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::hygiene::{AstPass, SyntaxContext, Transparency}; use std::{iter, mem}; struct Test { span: Span, - path: Vec, + ident: Ident, } struct TestCtxt<'a> { - span_diagnostic: &'a errors::Handler, - path: Vec, ext_cx: ExtCtxt<'a>, + panic_strategy: PanicStrategy, + def_site: Span, test_cases: Vec, reexport_test_harness_main: Option, test_runner: Option, - // top-level re-export submodule, filled out after folding is finished - toplevel_reexport: Option, } // Traverse the crate, collecting all the test functions, eliding any @@ -43,9 +42,12 @@ pub fn inject( krate: &mut ast::Crate, span_diagnostic: &errors::Handler, features: &Features, + panic_strategy: PanicStrategy, + platform_panic_strategy: PanicStrategy, + enable_panic_abort_tests: bool, ) { - // Check for #[reexport_test_harness_main = "some_name"] which - // creates a `use __test::main as some_name;`. This needs to be + // Check for #![reexport_test_harness_main = "some_name"] which gives the + // main test function the name `some_name` without hygiene. This needs to be // unconditional, so that the attribute is still marked as used in // non-test builds. let reexport_test_harness_main = @@ -56,17 +58,28 @@ pub fn inject( let test_runner = get_test_runner(span_diagnostic, &krate); if should_test { + let panic_strategy = match (panic_strategy, enable_panic_abort_tests) { + (PanicStrategy::Abort, true) => + PanicStrategy::Abort, + (PanicStrategy::Abort, false) if panic_strategy == platform_panic_strategy => { + // Silently allow compiling with panic=abort on these platforms, + // but with old behavior (abort if a test fails). + PanicStrategy::Unwind + } + (PanicStrategy::Abort, false) => { + span_diagnostic.err("building tests with panic=abort is not yet supported"); + PanicStrategy::Unwind + } + (PanicStrategy::Unwind, _) => PanicStrategy::Unwind, + }; generate_test_harness(sess, resolver, reexport_test_harness_main, - krate, span_diagnostic, features, test_runner) + krate, features, panic_strategy, test_runner) } } struct TestHarnessGenerator<'a> { cx: TestCtxt<'a>, - tests: Vec, - - // submodule name, gensym'd identifier for re-exports - tested_submods: Vec<(Ident, Ident)>, + tests: Vec, } impl<'a> MutVisitor for TestHarnessGenerator<'a> { @@ -74,57 +87,50 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { noop_visit_crate(c, self); // Create a main function to run our tests - let test_main = { - let unresolved = mk_main(&mut self.cx); - self.cx.ext_cx.monotonic_expander().flat_map_item(unresolved).pop().unwrap() - }; - - c.module.items.push(test_main); + c.module.items.push(mk_main(&mut self.cx)); } fn flat_map_item(&mut self, i: P) -> SmallVec<[P; 1]> { - let ident = i.ident; - if ident.name != kw::Invalid { - self.cx.path.push(ident); - } - debug!("current path: {}", path_name_i(&self.cx.path)); - let mut item = i.into_inner(); if is_test_case(&item) { debug!("this is a test item"); let test = Test { span: item.span, - path: self.cx.path.clone(), + ident: item.ident, }; - self.cx.test_cases.push(test); - self.tests.push(item.ident); + self.tests.push(test); } // We don't want to recurse into anything other than mods, since // mods or tests inside of functions will break things - if let ast::ItemKind::Mod(mut module) = item.node { + if let ast::ItemKind::Mod(mut module) = item.kind { let tests = mem::take(&mut self.tests); - let tested_submods = mem::take(&mut self.tested_submods); noop_visit_mod(&mut module, self); - let tests = mem::replace(&mut self.tests, tests); - let tested_submods = mem::replace(&mut self.tested_submods, tested_submods); - - if !tests.is_empty() || !tested_submods.is_empty() { - let (it, sym) = mk_reexport_mod(&mut self.cx, item.id, tests, tested_submods); - module.items.push(it); + let mut tests = mem::replace(&mut self.tests, tests); - if !self.cx.path.is_empty() { - self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym)); + if !tests.is_empty() { + let parent = if item.id == ast::DUMMY_NODE_ID { + ast::CRATE_NODE_ID } else { - debug!("pushing nothing, sym: {:?}", sym); - self.cx.toplevel_reexport = Some(sym); + item.id + }; + // Create an identifier that will hygienically resolve the test + // case name, even in another module. + let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass( + module.inner, + AstPass::TestHarness, + &[], + Some(parent), + ); + for test in &mut tests { + // See the comment on `mk_main` for why we're using + // `apply_mark` directly. + test.ident.span = test.ident.span.apply_mark(expn_id, Transparency::Opaque); } + self.cx.test_cases.extend(tests); } - item.node = ast::ItemKind::Mod(module); - } - if ident.name != kw::Invalid { - self.cx.path.pop(); + item.kind = ast::ItemKind::Mod(module); } smallvec![P(item)] } @@ -139,6 +145,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { struct EntryPointCleaner { // Current depth in the ast depth: usize, + def_site: Span, } impl MutVisitor for EntryPointCleaner { @@ -154,9 +161,11 @@ impl MutVisitor for EntryPointCleaner { EntryPointType::MainNamed | EntryPointType::MainAttr | EntryPointType::Start => - item.map(|ast::Item {id, ident, attrs, node, vis, span, tokens}| { - let allow_ident = Ident::with_empty_ctxt(sym::allow); - let dc_nested = attr::mk_nested_word_item(Ident::from_str("dead_code")); + item.map(|ast::Item {id, ident, attrs, kind, vis, span, tokens}| { + let allow_ident = Ident::new(sym::allow, self.def_site); + let dc_nested = attr::mk_nested_word_item( + Ident::from_str_and_span("dead_code", self.def_site), + ); let allow_dead_code_item = attr::mk_list_item(allow_ident, vec![dc_nested]); let allow_dead_code = attr::mk_attr_outer(allow_dead_code_item); @@ -169,7 +178,7 @@ impl MutVisitor for EntryPointCleaner { }) .chain(iter::once(allow_dead_code)) .collect(), - node, + kind, vis, span, tokens, @@ -187,119 +196,106 @@ impl MutVisitor for EntryPointCleaner { } } -/// Creates an item (specifically a module) that "pub use"s the tests passed in. -/// Each tested submodule will contain a similar reexport module that we will export -/// under the name of the original module. That is, `submod::__test_reexports` is -/// reexported like so `pub use submod::__test_reexports as submod`. -fn mk_reexport_mod(cx: &mut TestCtxt<'_>, - parent: ast::NodeId, - tests: Vec, - tested_submods: Vec<(Ident, Ident)>) - -> (P, Ident) { - let super_ = Ident::with_empty_ctxt(kw::Super); - - let items = tests.into_iter().map(|r| { - cx.ext_cx.item_use_simple(DUMMY_SP, dummy_spanned(ast::VisibilityKind::Public), - cx.ext_cx.path(DUMMY_SP, vec![super_, r])) - }).chain(tested_submods.into_iter().map(|(r, sym)| { - let path = cx.ext_cx.path(DUMMY_SP, vec![super_, r, sym]); - cx.ext_cx.item_use_simple_(DUMMY_SP, dummy_spanned(ast::VisibilityKind::Public), - Some(r), path) - })).collect(); - - let reexport_mod = ast::Mod { - inline: true, - inner: DUMMY_SP, - items, - }; - - let name = Ident::from_str("__test_reexports").gensym(); - let parent = if parent == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { parent }; - cx.ext_cx.current_expansion.id = cx.ext_cx.resolver.get_module_scope(parent); - let it = cx.ext_cx.monotonic_expander().flat_map_item(P(ast::Item { - ident: name, - attrs: Vec::new(), - id: ast::DUMMY_NODE_ID, - node: ast::ItemKind::Mod(reexport_mod), - vis: dummy_spanned(ast::VisibilityKind::Public), - span: DUMMY_SP, - tokens: None, - })).pop().unwrap(); - - (it, name) -} - /// Crawl over the crate, inserting test reexports and the test main function fn generate_test_harness(sess: &ParseSess, resolver: &mut dyn Resolver, reexport_test_harness_main: Option, krate: &mut ast::Crate, - sd: &errors::Handler, features: &Features, + panic_strategy: PanicStrategy, test_runner: Option) { - // Remove the entry points - let mut cleaner = EntryPointCleaner { depth: 0 }; - cleaner.visit_crate(krate); - let mut econfig = ExpansionConfig::default("test".to_string()); econfig.features = Some(features); + let ext_cx = ExtCtxt::new(sess, econfig, resolver); + + let expn_id = ext_cx.resolver.expansion_for_ast_pass( + DUMMY_SP, + AstPass::TestHarness, + &[sym::main, sym::test, sym::rustc_attrs], + None, + ); + let def_site = DUMMY_SP.with_def_site_ctxt(expn_id); + + // Remove the entry points + let mut cleaner = EntryPointCleaner { depth: 0, def_site }; + cleaner.visit_crate(krate); + let cx = TestCtxt { - span_diagnostic: sd, - ext_cx: ExtCtxt::new(sess, econfig, resolver), - path: Vec::new(), + ext_cx, + panic_strategy, + def_site, test_cases: Vec::new(), reexport_test_harness_main, - toplevel_reexport: None, test_runner }; TestHarnessGenerator { cx, tests: Vec::new(), - tested_submods: Vec::new(), }.visit_crate(krate); } /// Creates a function item for use as the main function of a test build. /// This function will call the `test_runner` as specified by the crate attribute +/// +/// By default this expands to +/// +/// #[main] +/// pub fn main() { +/// extern crate test; +/// test::test_main_static(&[ +/// &test_const1, +/// &test_const2, +/// &test_const3, +/// ]); +/// } +/// +/// Most of the Ident have the usual def-site hygiene for the AST pass. The +/// exception is the `test_const`s. These have a syntax context that has two +/// opaque marks: one from the expansion of `test` or `test_case`, and one +/// generated in `TestHarnessGenerator::flat_map_item`. When resolving this +/// identifier after failing to find a matching identifier in the root module +/// we remove the outer mark, and try resolving at its def-site, which will +/// then resolve to `test_const`. +/// +/// The expansion here can be controlled by two attributes: +/// +/// `reexport_test_harness_main` provides a different name for the `main` +/// function and `test_runner` provides a path that replaces +/// `test::test_main_static`. fn mk_main(cx: &mut TestCtxt<'_>) -> P { - // Writing this out by hand: - // pub fn main() { - // #![main] - // test::test_main_static(&[..tests]); - // } - let sp = DUMMY_SP.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable( - ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, cx.ext_cx.parse_sess.edition, - [sym::main, sym::test, sym::rustc_attrs][..].into(), - )); + let sp = cx.def_site; let ecx = &cx.ext_cx; - let test_id = Ident::with_empty_ctxt(sym::test); + let test_id = Ident::new(sym::test, sp); + + let runner_name = match cx.panic_strategy { + PanicStrategy::Unwind => "test_main_static", + PanicStrategy::Abort => "test_main_static_abort", + }; // test::test_main_static(...) let mut test_runner = cx.test_runner.clone().unwrap_or( - ecx.path(sp, vec![ - test_id, ecx.ident_of("test_main_static") - ])); + ecx.path(sp, vec![test_id, ecx.ident_of(runner_name, sp)])); test_runner.span = sp; let test_main_path_expr = ecx.expr_path(test_runner); let call_test_main = ecx.expr_call(sp, test_main_path_expr, - vec![mk_tests_slice(cx)]); + vec![mk_tests_slice(cx, sp)]); let call_test_main = ecx.stmt_expr(call_test_main); - // #![main] - let main_meta = ecx.meta_word(sp, sym::main); - let main_attr = ecx.attribute(main_meta); - - // extern crate test as test_gensym + // extern crate test let test_extern_stmt = ecx.stmt_item(sp, ecx.item(sp, test_id, vec![], ast::ItemKind::ExternCrate(None) )); + // #[main] + let main_meta = ecx.meta_word(sp, sym::main); + let main_attr = ecx.attribute(main_meta); + // pub fn main() { ... } let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(vec![])); @@ -317,60 +313,39 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { // Honor the reexport_test_harness_main attribute let main_id = match cx.reexport_test_harness_main { - Some(sym) => Ident::new(sym, sp), - None => Ident::from_str_and_span("main", sp).gensym(), + Some(sym) => Ident::new(sym, sp.with_ctxt(SyntaxContext::root())), + None => Ident::new(sym::main, sp), }; - P(ast::Item { + let main = P(ast::Item { ident: main_id, attrs: vec![main_attr], id: ast::DUMMY_NODE_ID, - node: main, - vis: dummy_spanned(ast::VisibilityKind::Public), + kind: main, + vis: respan(sp, ast::VisibilityKind::Public), span: sp, tokens: None, - }) - -} + }); -fn path_name_i(idents: &[Ident]) -> String { - let mut path_name = "".to_string(); - let mut idents_iter = idents.iter().peekable(); - while let Some(ident) = idents_iter.next() { - path_name.push_str(&ident.as_str()); - if idents_iter.peek().is_some() { - path_name.push_str("::") - } - } - path_name + // Integrate the new item into existing module structures. + let main = AstFragment::Items(smallvec![main]); + cx.ext_cx.monotonic_expander().fully_expand_fragment(main).make_items().pop().unwrap() } /// Creates a slice containing every test like so: -/// &[path::to::test1, path::to::test2] -fn mk_tests_slice(cx: &TestCtxt<'_>) -> P { +/// &[&test1, &test2] +fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P { debug!("building test vector from {} tests", cx.test_cases.len()); let ref ecx = cx.ext_cx; - ecx.expr_vec_slice(DUMMY_SP, + + ecx.expr_vec_slice(sp, cx.test_cases.iter().map(|test| { ecx.expr_addr_of(test.span, - ecx.expr_path(ecx.path(test.span, visible_path(cx, &test.path)))) + ecx.expr_path(ecx.path(test.span, vec![test.ident]))) }).collect()) } -/// Creates a path from the top-level __test module to the test via __test_reexports -fn visible_path(cx: &TestCtxt<'_>, path: &[Ident]) -> Vec{ - let mut visible_path = vec![]; - match cx.toplevel_reexport { - Some(id) => visible_path.push(id), - None => { - cx.span_diagnostic.bug("expected to find top-level re-export name, but found None"); - } - } - visible_path.extend_from_slice(path); - visible_path -} - fn is_test_case(i: &ast::Item) -> bool { attr::contains_name(&i.attrs, sym::rustc_test_marker) } diff --git a/src/libsyntax_ext/trace_macros.rs b/src/libsyntax_ext/trace_macros.rs index 0dce8a36f4c7b..d83c24046d9e5 100644 --- a/src/libsyntax_ext/trace_macros.rs +++ b/src/libsyntax_ext/trace_macros.rs @@ -1,20 +1,27 @@ use syntax::ext::base::{self, ExtCtxt}; use syntax::symbol::kw; use syntax_pos::Span; -use syntax::tokenstream::TokenTree; +use syntax::tokenstream::{TokenTree, TokenStream}; pub fn expand_trace_macros(cx: &mut ExtCtxt<'_>, sp: Span, - tt: &[TokenTree]) + tt: TokenStream) -> Box { - match tt { - [TokenTree::Token(token)] if token.is_keyword(kw::True) => { - cx.set_trace_macros(true); - } - [TokenTree::Token(token)] if token.is_keyword(kw::False) => { - cx.set_trace_macros(false); - } - _ => cx.span_err(sp, "trace_macros! accepts only `true` or `false`"), + let mut cursor = tt.into_trees(); + let mut err = false; + let value = match &cursor.next() { + Some(TokenTree::Token(token)) if token.is_keyword(kw::True) => true, + Some(TokenTree::Token(token)) if token.is_keyword(kw::False) => false, + _ => { + err = true; + false + }, + }; + err |= cursor.next().is_some(); + if err { + cx.span_err(sp, "trace_macros! accepts only `true` or `false`") + } else { + cx.set_trace_macros(value); } base::DummyResult::any_valid(sp) diff --git a/src/libsyntax_pos/Cargo.toml b/src/libsyntax_pos/Cargo.toml index bc13d2a161132..378f7a955a36f 100644 --- a/src/libsyntax_pos/Cargo.toml +++ b/src/libsyntax_pos/Cargo.toml @@ -13,6 +13,7 @@ doctest = false rustc_serialize = { path = "../libserialize", package = "serialize" } rustc_macros = { path = "../librustc_macros" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_index = { path = "../librustc_index" } arena = { path = "../libarena" } scoped-tls = "1.0" unicode-width = "0.1.4" diff --git a/src/libsyntax_pos/edition.rs b/src/libsyntax_pos/edition.rs index 20216568426fe..00cd00f283784 100644 --- a/src/libsyntax_pos/edition.rs +++ b/src/libsyntax_pos/edition.rs @@ -1,7 +1,6 @@ use crate::symbol::{Symbol, sym}; use std::fmt; use std::str::FromStr; -use crate::GLOBALS; /// The edition of the compiler (RFC 2052) #[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Debug, RustcEncodable, RustcDecodable, Eq)] @@ -39,10 +38,6 @@ impl fmt::Display for Edition { } impl Edition { - pub fn from_session() -> Edition { - GLOBALS.with(|globals| globals.edition) - } - pub fn lint_name(&self) -> &'static str { match *self { Edition::Edition2015 => "rust_2015_compatibility", diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index f91a22915445c..e28d93267579a 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -13,8 +13,8 @@ // // This explains why `HygieneData`, `SyntaxContext` and `ExpnId` have interfaces // with a certain amount of redundancy in them. For example, -// `SyntaxContext::outer_expn_info` combines `SyntaxContext::outer` and -// `ExpnId::expn_info` so that two `HygieneData` accesses can be performed within +// `SyntaxContext::outer_expn_data` combines `SyntaxContext::outer` and +// `ExpnId::expn_data` so that two `HygieneData` accesses can be performed within // a single `HygieneData::with` call. // // It also explains why many functions appear in `HygieneData` and again in @@ -56,16 +56,6 @@ struct SyntaxContextData { #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub struct ExpnId(u32); -// FIXME: Find a way to merge this with `ExpnInfo`. -#[derive(Debug)] -struct InternalExpnData { - parent: ExpnId, - /// Each expansion should have an associated expansion info, but sometimes there's a delay - /// between creation of an expansion ID and obtaining its info (e.g. macros are collected - /// first and then resolved later), so we use an `Option` here. - expn_info: Option, -} - /// A property of a macro expansion that determines how identifiers /// produced by that expansion are resolved. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, RustcEncodable, RustcDecodable)] @@ -86,8 +76,8 @@ pub enum Transparency { } impl ExpnId { - pub fn fresh(parent: ExpnId, expn_info: Option) -> Self { - HygieneData::with(|data| data.fresh_expn(parent, expn_info)) + pub fn fresh(expn_data: Option) -> Self { + HygieneData::with(|data| data.fresh_expn(expn_data)) } /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST. @@ -107,21 +97,16 @@ impl ExpnId { } #[inline] - pub fn parent(self) -> ExpnId { - HygieneData::with(|data| data.parent_expn(self)) + pub fn expn_data(self) -> ExpnData { + HygieneData::with(|data| data.expn_data(self).clone()) } #[inline] - pub fn expn_info(self) -> Option { - HygieneData::with(|data| data.expn_info(self).cloned()) - } - - #[inline] - pub fn set_expn_info(self, info: ExpnInfo) { + pub fn set_expn_data(self, expn_data: ExpnData) { HygieneData::with(|data| { - let old_info = &mut data.expn_data[self.0 as usize].expn_info; - assert!(old_info.is_none(), "expansion info is reset for an expansion ID"); - *old_info = Some(info); + let old_expn_data = &mut data.expn_data[self.0 as usize]; + assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID"); + *old_expn_data = Some(expn_data); }) } @@ -134,26 +119,14 @@ impl ExpnId { pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool { HygieneData::with(|data| data.is_descendant_of(self, data.outer_expn(ctxt))) } - - // Used for enabling some compatibility fallback in resolve. - #[inline] - pub fn looks_like_proc_macro_derive(self) -> bool { - HygieneData::with(|data| { - if data.default_transparency(self) == Transparency::Opaque { - if let Some(expn_info) = data.expn_info(self) { - if let ExpnKind::Macro(MacroKind::Derive, _) = expn_info.kind { - return true; - } - } - } - false - }) - } } #[derive(Debug)] crate struct HygieneData { - expn_data: Vec, + /// Each expansion should have an associated expansion data, but sometimes there's a delay + /// between creation of an expansion ID and obtaining its data (e.g. macros are collected + /// first and then resolved later), so we use an `Option` here. + expn_data: Vec>, syntax_context_data: Vec, syntax_context_map: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>, } @@ -161,10 +134,7 @@ crate struct HygieneData { impl HygieneData { crate fn new(edition: Edition) -> Self { HygieneData { - expn_data: vec![InternalExpnData { - parent: ExpnId::root(), - expn_info: Some(ExpnInfo::default(ExpnKind::Root, DUMMY_SP, edition)), - }], + expn_data: vec![Some(ExpnData::default(ExpnKind::Root, DUMMY_SP, edition))], syntax_context_data: vec![SyntaxContextData { outer_expn: ExpnId::root(), outer_transparency: Transparency::Opaque, @@ -181,25 +151,14 @@ impl HygieneData { GLOBALS.with(|globals| f(&mut *globals.hygiene_data.borrow_mut())) } - fn fresh_expn(&mut self, parent: ExpnId, expn_info: Option) -> ExpnId { - self.expn_data.push(InternalExpnData { parent, expn_info }); + fn fresh_expn(&mut self, expn_data: Option) -> ExpnId { + self.expn_data.push(expn_data); ExpnId(self.expn_data.len() as u32 - 1) } - fn parent_expn(&self, expn_id: ExpnId) -> ExpnId { - self.expn_data[expn_id.0 as usize].parent - } - - fn expn_info(&self, expn_id: ExpnId) -> Option<&ExpnInfo> { - if expn_id != ExpnId::root() { - Some(self.expn_data[expn_id.0 as usize].expn_info.as_ref() - .expect("no expansion info for an expansion ID")) - } else { - // FIXME: Some code relies on `expn_info().is_none()` meaning "no expansion". - // Introduce a method for checking for "no expansion" instead and always return - // `ExpnInfo` from this function instead of the `Option`. - None - } + fn expn_data(&self, expn_id: ExpnId) -> &ExpnData { + self.expn_data[expn_id.0 as usize].as_ref() + .expect("no expansion data for an expansion ID") } fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool { @@ -207,17 +166,11 @@ impl HygieneData { if expn_id == ExpnId::root() { return false; } - expn_id = self.parent_expn(expn_id); + expn_id = self.expn_data(expn_id).parent; } true } - fn default_transparency(&self, expn_id: ExpnId) -> Transparency { - self.expn_info(expn_id).map_or( - Transparency::SemiTransparent, |einfo| einfo.default_transparency - ) - } - fn modern(&self, ctxt: SyntaxContext) -> SyntaxContext { self.syntax_context_data[ctxt.0 as usize].opaque } @@ -230,24 +183,25 @@ impl HygieneData { self.syntax_context_data[ctxt.0 as usize].outer_expn } - fn outer_transparency(&self, ctxt: SyntaxContext) -> Transparency { - self.syntax_context_data[ctxt.0 as usize].outer_transparency + fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) { + let data = &self.syntax_context_data[ctxt.0 as usize]; + (data.outer_expn, data.outer_transparency) } fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext { self.syntax_context_data[ctxt.0 as usize].parent } - fn remove_mark(&self, ctxt: &mut SyntaxContext) -> ExpnId { - let outer_expn = self.outer_expn(*ctxt); + fn remove_mark(&self, ctxt: &mut SyntaxContext) -> (ExpnId, Transparency) { + let outer_mark = self.outer_mark(*ctxt); *ctxt = self.parent_ctxt(*ctxt); - outer_expn + outer_mark } fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> { let mut marks = Vec::new(); - while ctxt != SyntaxContext::empty() { - marks.push((self.outer_expn(ctxt), self.outer_transparency(ctxt))); + while ctxt != SyntaxContext::root() { + marks.push(self.outer_mark(ctxt)); ctxt = self.parent_ctxt(ctxt); } marks.reverse(); @@ -255,12 +209,8 @@ impl HygieneData { } fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span { - while span.ctxt() != crate::NO_EXPANSION && span.ctxt() != to { - if let Some(info) = self.expn_info(self.outer_expn(span.ctxt())) { - span = info.call_site; - } else { - break; - } + while span.from_expansion() && span.ctxt() != to { + span = self.expn_data(self.outer_expn(span.ctxt())).call_site; } span } @@ -268,32 +218,27 @@ impl HygieneData { fn adjust(&self, ctxt: &mut SyntaxContext, expn_id: ExpnId) -> Option { let mut scope = None; while !self.is_descendant_of(expn_id, self.outer_expn(*ctxt)) { - scope = Some(self.remove_mark(ctxt)); + scope = Some(self.remove_mark(ctxt).0); } scope } - fn apply_mark(&mut self, ctxt: SyntaxContext, expn_id: ExpnId) -> SyntaxContext { - assert_ne!(expn_id, ExpnId::root()); - self.apply_mark_with_transparency(ctxt, expn_id, self.default_transparency(expn_id)) - } - - fn apply_mark_with_transparency(&mut self, ctxt: SyntaxContext, expn_id: ExpnId, - transparency: Transparency) -> SyntaxContext { + fn apply_mark( + &mut self, ctxt: SyntaxContext, expn_id: ExpnId, transparency: Transparency + ) -> SyntaxContext { assert_ne!(expn_id, ExpnId::root()); if transparency == Transparency::Opaque { return self.apply_mark_internal(ctxt, expn_id, transparency); } - let call_site_ctxt = - self.expn_info(expn_id).map_or(SyntaxContext::empty(), |info| info.call_site.ctxt()); + let call_site_ctxt = self.expn_data(expn_id).call_site.ctxt(); let mut call_site_ctxt = if transparency == Transparency::SemiTransparent { self.modern(call_site_ctxt) } else { self.modern_and_legacy(call_site_ctxt) }; - if call_site_ctxt == SyntaxContext::empty() { + if call_site_ctxt == SyntaxContext::root() { return self.apply_mark_internal(ctxt, expn_id, transparency); } @@ -398,9 +343,41 @@ pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symb })) } +pub fn debug_hygiene_data(verbose: bool) -> String { + HygieneData::with(|data| { + if verbose { + format!("{:#?}", data) + } else { + let mut s = String::from(""); + s.push_str("Expansions:"); + data.expn_data.iter().enumerate().for_each(|(id, expn_info)| { + let expn_info = expn_info.as_ref().expect("no expansion data for an expansion ID"); + s.push_str(&format!( + "\n{}: parent: {:?}, call_site_ctxt: {:?}, kind: {:?}", + id, + expn_info.parent, + expn_info.call_site.ctxt(), + expn_info.kind, + )); + }); + s.push_str("\n\nSyntaxContexts:"); + data.syntax_context_data.iter().enumerate().for_each(|(id, ctxt)| { + s.push_str(&format!( + "\n#{}: parent: {:?}, outer_mark: ({:?}, {:?})", + id, + ctxt.parent, + ctxt.outer_expn, + ctxt.outer_transparency, + )); + }); + s + } + }) +} + impl SyntaxContext { #[inline] - pub const fn empty() -> Self { + pub const fn root() -> Self { SyntaxContext(0) } @@ -414,15 +391,9 @@ impl SyntaxContext { SyntaxContext(raw) } - /// Extend a syntax context with a given expansion and default transparency for that expansion. - pub fn apply_mark(self, expn_id: ExpnId) -> SyntaxContext { - HygieneData::with(|data| data.apply_mark(self, expn_id)) - } - /// Extend a syntax context with a given expansion and transparency. - pub fn apply_mark_with_transparency(self, expn_id: ExpnId, transparency: Transparency) - -> SyntaxContext { - HygieneData::with(|data| data.apply_mark_with_transparency(self, expn_id, transparency)) + crate fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext { + HygieneData::with(|data| data.apply_mark(self, expn_id, transparency)) } /// Pulls a single mark off of the syntax context. This effectively moves the @@ -442,7 +413,7 @@ impl SyntaxContext { /// invocation of f that created g1. /// Returns the mark that was removed. pub fn remove_mark(&mut self) -> ExpnId { - HygieneData::with(|data| data.remove_mark(self)) + HygieneData::with(|data| data.remove_mark(self).0) } pub fn marks(self) -> Vec<(ExpnId, Transparency)> { @@ -515,8 +486,8 @@ impl SyntaxContext { let mut scope = None; let mut glob_ctxt = data.modern(glob_span.ctxt()); while !data.is_descendant_of(expn_id, data.outer_expn(glob_ctxt)) { - scope = Some(data.remove_mark(&mut glob_ctxt)); - if data.remove_mark(self) != scope.unwrap() { + scope = Some(data.remove_mark(&mut glob_ctxt).0); + if data.remove_mark(self).0 != scope.unwrap() { return None; } } @@ -547,9 +518,9 @@ impl SyntaxContext { marks.push(data.remove_mark(&mut glob_ctxt)); } - let scope = marks.last().cloned(); - while let Some(mark) = marks.pop() { - *self = data.apply_mark(*self, mark); + let scope = marks.last().map(|mark| mark.0); + while let Some((expn_id, transparency)) = marks.pop() { + *self = data.apply_mark(*self, expn_id, transparency); } Some(scope) }) @@ -578,20 +549,18 @@ impl SyntaxContext { HygieneData::with(|data| data.outer_expn(self)) } - /// `ctxt.outer_expn_info()` is equivalent to but faster than - /// `ctxt.outer_expn().expn_info()`. + /// `ctxt.outer_expn_data()` is equivalent to but faster than + /// `ctxt.outer_expn().expn_data()`. #[inline] - pub fn outer_expn_info(self) -> Option { - HygieneData::with(|data| data.expn_info(data.outer_expn(self)).cloned()) + pub fn outer_expn_data(self) -> ExpnData { + HygieneData::with(|data| data.expn_data(data.outer_expn(self)).clone()) } - /// `ctxt.outer_expn_with_info()` is equivalent to but faster than - /// `{ let outer = ctxt.outer_expn(); (outer, outer.expn_info()) }`. #[inline] - pub fn outer_expn_with_info(self) -> (ExpnId, Option) { + pub fn outer_mark_with_data(self) -> (ExpnId, Transparency, ExpnData) { HygieneData::with(|data| { - let outer = data.outer_expn(self); - (outer, data.expn_info(outer).cloned()) + let (expn_id, transparency) = data.outer_mark(self); + (expn_id, transparency, data.expn_data(expn_id).clone()) }) } @@ -612,10 +581,16 @@ impl Span { /// other compiler-generated code to set per-span properties like allowed unstable features. /// The returned span belongs to the created expansion and has the new properties, /// but its location is inherited from the current span. - pub fn fresh_expansion(self, parent: ExpnId, expn_info: ExpnInfo) -> Span { + pub fn fresh_expansion(self, expn_data: ExpnData) -> Span { + self.fresh_expansion_with_transparency(expn_data, Transparency::Transparent) + } + + pub fn fresh_expansion_with_transparency( + self, expn_data: ExpnData, transparency: Transparency + ) -> Span { HygieneData::with(|data| { - let expn_id = data.fresh_expn(parent, Some(expn_info)); - self.with_ctxt(data.apply_mark(SyntaxContext::empty(), expn_id)) + let expn_id = data.fresh_expn(Some(expn_data)); + self.with_ctxt(data.apply_mark(SyntaxContext::root(), expn_id, transparency)) }) } } @@ -623,8 +598,12 @@ impl Span { /// A subset of properties from both macro definition and macro call available through global data. /// Avoid using this if you have access to the original definition or call structures. #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] -pub struct ExpnInfo { +pub struct ExpnData { // --- The part unique to each expansion. + /// The kind of this expansion - macro or compiler desugaring. + pub kind: ExpnKind, + /// The expansion that produced this expansion. + pub parent: ExpnId, /// The location of the actual macro invocation or syntax sugar , e.g. /// `let x = foo!();` or `if let Some(y) = x {}` /// @@ -632,19 +611,17 @@ pub struct ExpnInfo { /// `foo!()` invoked `bar!()` internally, and there was an /// expression inside `bar!`; the call_site of the expression in /// the expansion would point to the `bar!` invocation; that - /// call_site span would have its own ExpnInfo, with the call_site + /// call_site span would have its own ExpnData, with the call_site /// pointing to the `foo!` invocation. pub call_site: Span, - /// The kind of this expansion - macro or compiler desugaring. - pub kind: ExpnKind, // --- The part specific to the macro/desugaring definition. - // --- FIXME: Share it between expansions with the same definition. + // --- It may be reasonable to share this part between expansions with the same definition, + // --- but such sharing is known to bring some minor inconveniences without also bringing + // --- noticeable perf improvements (PR #62898). /// The span of the macro definition (possibly dummy). /// This span serves only informational purpose and is not used for resolution. pub def_site: Span, - /// Transparency used by `apply_mark` for the expansion with this expansion info by default. - pub default_transparency: Transparency, /// List of #[unstable]/feature-gated features that the macro is allowed to use /// internally without forcing the whole crate to opt-in /// to them. @@ -659,14 +636,14 @@ pub struct ExpnInfo { pub edition: Edition, } -impl ExpnInfo { - /// Constructs an expansion info with default properties. - pub fn default(kind: ExpnKind, call_site: Span, edition: Edition) -> ExpnInfo { - ExpnInfo { - call_site, +impl ExpnData { + /// Constructs expansion data with default properties. + pub fn default(kind: ExpnKind, call_site: Span, edition: Edition) -> ExpnData { + ExpnData { kind, + parent: ExpnId::root(), + call_site, def_site: DUMMY_SP, - default_transparency: Transparency::SemiTransparent, allow_internal_unstable: None, allow_internal_unsafe: false, local_inner_macros: false, @@ -675,12 +652,17 @@ impl ExpnInfo { } pub fn allow_unstable(kind: ExpnKind, call_site: Span, edition: Edition, - allow_internal_unstable: Lrc<[Symbol]>) -> ExpnInfo { - ExpnInfo { + allow_internal_unstable: Lrc<[Symbol]>) -> ExpnData { + ExpnData { allow_internal_unstable: Some(allow_internal_unstable), - ..ExpnInfo::default(kind, call_site, edition) + ..ExpnData::default(kind, call_site, edition) } } + + #[inline] + pub fn is_root(&self) -> bool { + if let ExpnKind::Root = self.kind { true } else { false } + } } /// Expansion kind. @@ -689,8 +671,9 @@ pub enum ExpnKind { /// No expansion, aka root expansion. Only `ExpnId::root()` has this kind. Root, /// Expansion produced by a macro. - /// FIXME: Some code injected by the compiler before HIR lowering also gets this kind. Macro(MacroKind, Symbol), + /// Transform done by the compiler on the AST. + AstPass(AstPass), /// Desugaring done by the compiler during HIR lowering. Desugaring(DesugaringKind) } @@ -700,6 +683,7 @@ impl ExpnKind { match *self { ExpnKind::Root => kw::PathRoot, ExpnKind::Macro(_, descr) => descr, + ExpnKind::AstPass(kind) => Symbol::intern(kind.descr()), ExpnKind::Desugaring(kind) => Symbol::intern(kind.descr()), } } @@ -725,6 +709,13 @@ impl MacroKind { } } + pub fn descr_expected(self) -> &'static str { + match self { + MacroKind::Attr => "attribute", + _ => self.descr(), + } + } + pub fn article(self) -> &'static str { match self { MacroKind::Attr => "an", @@ -733,6 +724,26 @@ impl MacroKind { } } +/// The kind of AST transform. +#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable)] +pub enum AstPass { + StdImports, + TestHarness, + ProcMacroHarness, + PluginMacroDefs, +} + +impl AstPass { + fn descr(self) -> &'static str { + match self { + AstPass::StdImports => "standard library imports", + AstPass::TestHarness => "test harness", + AstPass::ProcMacroHarness => "proc macro harness", + AstPass::PluginMacroDefs => "plugin macro definitions", + } + } +} + /// The kind of compiler desugaring. #[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable)] pub enum DesugaringKind { @@ -767,14 +778,14 @@ impl DesugaringKind { } } -impl Encodable for SyntaxContext { +impl Encodable for ExpnId { fn encode(&self, _: &mut E) -> Result<(), E::Error> { Ok(()) // FIXME(jseyfried) intercrate hygiene } } -impl Decodable for SyntaxContext { - fn decode(_: &mut D) -> Result { - Ok(SyntaxContext::empty()) // FIXME(jseyfried) intercrate hygiene +impl Decodable for ExpnId { + fn decode(_: &mut D) -> Result { + Ok(ExpnId::root()) // FIXME(jseyfried) intercrate hygiene } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 02a7433d9469d..30ee9b90515ee 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -21,7 +21,8 @@ use rustc_serialize::{Encodable, Decodable, Encoder, Decoder}; pub mod edition; use edition::Edition; pub mod hygiene; -pub use hygiene::{ExpnId, SyntaxContext, ExpnInfo, ExpnKind, MacroKind, DesugaringKind}; +pub use hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind, MacroKind, DesugaringKind}; +use hygiene::Transparency; mod span_encoding; pub use span_encoding::{Span, DUMMY_SP}; @@ -49,7 +50,6 @@ pub struct Globals { symbol_interner: Lock, span_interner: Lock, hygiene_data: Lock, - edition: Edition, } impl Globals { @@ -58,7 +58,6 @@ impl Globals { symbol_interner: Lock::new(symbol::Interner::fresh()), span_interner: Lock::new(span_encoding::SpanInterner::default()), hygiene_data: Lock::new(hygiene::HygieneData::new(edition)), - edition, } } } @@ -288,6 +287,17 @@ impl Span { span.lo.0 == 0 && span.hi.0 == 0 } + /// Returns `true` if this span comes from a macro or desugaring. + #[inline] + pub fn from_expansion(self) -> bool { + self.ctxt() != SyntaxContext::root() + } + + #[inline] + pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span { + Span::new(lo, hi, SyntaxContext::root()) + } + /// Returns a new span representing an empty span at the beginning of this span #[inline] pub fn shrink_to_lo(self) -> Span { @@ -344,20 +354,20 @@ impl Span { /// Returns the source span -- this is either the supplied span, or the span for /// the macro callsite that expanded to it. pub fn source_callsite(self) -> Span { - self.ctxt().outer_expn_info().map(|info| info.call_site.source_callsite()).unwrap_or(self) + let expn_data = self.ctxt().outer_expn_data(); + if !expn_data.is_root() { expn_data.call_site.source_callsite() } else { self } } /// The `Span` for the tokens in the previous macro expansion from which `self` was generated, /// if any. pub fn parent(self) -> Option { - self.ctxt().outer_expn_info().map(|i| i.call_site) + let expn_data = self.ctxt().outer_expn_data(); + if !expn_data.is_root() { Some(expn_data.call_site) } else { None } } /// Edition of the crate from which this span came. pub fn edition(self) -> edition::Edition { - self.ctxt().outer_expn_info().map_or_else(|| { - Edition::from_session() - }, |einfo| einfo.edition) + self.ctxt().outer_expn_data().edition } #[inline] @@ -373,52 +383,42 @@ impl Span { /// Returns the source callee. /// /// Returns `None` if the supplied span has no expansion trace, - /// else returns the `ExpnInfo` for the macro definition + /// else returns the `ExpnData` for the macro definition /// corresponding to the source callsite. - pub fn source_callee(self) -> Option { - fn source_callee(info: ExpnInfo) -> ExpnInfo { - match info.call_site.ctxt().outer_expn_info() { - Some(info) => source_callee(info), - None => info, - } + pub fn source_callee(self) -> Option { + fn source_callee(expn_data: ExpnData) -> ExpnData { + let next_expn_data = expn_data.call_site.ctxt().outer_expn_data(); + if !next_expn_data.is_root() { source_callee(next_expn_data) } else { expn_data } } - self.ctxt().outer_expn_info().map(source_callee) + let expn_data = self.ctxt().outer_expn_data(); + if !expn_data.is_root() { Some(source_callee(expn_data)) } else { None } } /// Checks if a span is "internal" to a macro in which `#[unstable]` /// items can be used (that is, a macro marked with /// `#[allow_internal_unstable]`). pub fn allows_unstable(&self, feature: Symbol) -> bool { - match self.ctxt().outer_expn_info() { - Some(info) => info - .allow_internal_unstable - .map_or(false, |features| features.iter().any(|&f| - f == feature || f == sym::allow_internal_unstable_backcompat_hack - )), - None => false, - } + self.ctxt().outer_expn_data().allow_internal_unstable.map_or(false, |features| { + features.iter().any(|&f| { + f == feature || f == sym::allow_internal_unstable_backcompat_hack + }) + }) } /// Checks if this span arises from a compiler desugaring of kind `kind`. pub fn is_desugaring(&self, kind: DesugaringKind) -> bool { - match self.ctxt().outer_expn_info() { - Some(info) => match info.kind { - ExpnKind::Desugaring(k) => k == kind, - _ => false, - }, - None => false, + match self.ctxt().outer_expn_data().kind { + ExpnKind::Desugaring(k) => k == kind, + _ => false, } } /// Returns the compiler desugaring that created this span, or `None` /// if this span is not from a desugaring. pub fn desugaring_kind(&self) -> Option { - match self.ctxt().outer_expn_info() { - Some(info) => match info.kind { - ExpnKind::Desugaring(k) => Some(k), - _ => None - }, - None => None + match self.ctxt().outer_expn_data().kind { + ExpnKind::Desugaring(k) => Some(k), + _ => None } } @@ -426,21 +426,23 @@ impl Span { /// can be used without triggering the `unsafe_code` lint // (that is, a macro marked with `#[allow_internal_unsafe]`). pub fn allows_unsafe(&self) -> bool { - match self.ctxt().outer_expn_info() { - Some(info) => info.allow_internal_unsafe, - None => false, - } + self.ctxt().outer_expn_data().allow_internal_unsafe } pub fn macro_backtrace(mut self) -> Vec { let mut prev_span = DUMMY_SP; let mut result = vec![]; - while let Some(info) = self.ctxt().outer_expn_info() { + loop { + let expn_data = self.ctxt().outer_expn_data(); + if expn_data.is_root() { + break; + } // Don't print recursive invocations. - if !info.call_site.source_equal(&prev_span) { - let (pre, post) = match info.kind { + if !expn_data.call_site.source_equal(&prev_span) { + let (pre, post) = match expn_data.kind { ExpnKind::Root => break, ExpnKind::Desugaring(..) => ("desugaring of ", ""), + ExpnKind::AstPass(..) => ("", ""), ExpnKind::Macro(macro_kind, _) => match macro_kind { MacroKind::Bang => ("", "!"), MacroKind::Attr => ("#[", "]"), @@ -448,14 +450,14 @@ impl Span { } }; result.push(MacroBacktrace { - call_site: info.call_site, - macro_decl_name: format!("{}{}{}", pre, info.kind.descr(), post), - def_site_span: info.def_site, + call_site: expn_data.call_site, + macro_decl_name: format!("{}{}{}", pre, expn_data.kind.descr(), post), + def_site_span: expn_data.def_site, }); } prev_span = self; - self = info.call_site; + self = expn_data.call_site; } result } @@ -468,9 +470,9 @@ impl Span { // Return the macro span on its own to avoid weird diagnostic output. It is preferable to // have an incomplete span than a completely nonsensical one. if span_data.ctxt != end_data.ctxt { - if span_data.ctxt == SyntaxContext::empty() { + if span_data.ctxt == SyntaxContext::root() { return end; - } else if end_data.ctxt == SyntaxContext::empty() { + } else if end_data.ctxt == SyntaxContext::root() { return self; } // Both spans fall within a macro. @@ -479,7 +481,7 @@ impl Span { Span::new( cmp::min(span_data.lo, end_data.lo), cmp::max(span_data.hi, end_data.hi), - if span_data.ctxt == SyntaxContext::empty() { end_data.ctxt } else { span_data.ctxt }, + if span_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt }, ) } @@ -490,7 +492,7 @@ impl Span { Span::new( span.hi, end.lo, - if end.ctxt == SyntaxContext::empty() { end.ctxt } else { span.ctxt }, + if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt }, ) } @@ -501,7 +503,7 @@ impl Span { Span::new( span.lo, end.lo, - if end.ctxt == SyntaxContext::empty() { end.ctxt } else { span.ctxt }, + if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt }, ) } @@ -512,10 +514,35 @@ impl Span { span.ctxt) } + /// Equivalent of `Span::def_site` from the proc macro API, + /// except that the location is taken from the `self` span. + pub fn with_def_site_ctxt(self, expn_id: ExpnId) -> Span { + self.with_ctxt_from_mark(expn_id, Transparency::Opaque) + } + + /// Equivalent of `Span::call_site` from the proc macro API, + /// except that the location is taken from the `self` span. + pub fn with_call_site_ctxt(&self, expn_id: ExpnId) -> Span { + self.with_ctxt_from_mark(expn_id, Transparency::Transparent) + } + + /// Equivalent of `Span::mixed_site` from the proc macro API, + /// except that the location is taken from the `self` span. + pub fn with_mixed_site_ctxt(&self, expn_id: ExpnId) -> Span { + self.with_ctxt_from_mark(expn_id, Transparency::SemiTransparent) + } + + /// Produces a span with the same location as `self` and context produced by a macro with the + /// given ID and transparency, assuming that macro was defined directly and not produced by + /// some other macro (which is the case for built-in and procedural macros). + pub fn with_ctxt_from_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span { + self.with_ctxt(SyntaxContext::root().apply_mark(expn_id, transparency)) + } + #[inline] - pub fn apply_mark(self, mark: ExpnId) -> Span { + pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span { let span = self.data(); - span.with_ctxt(span.ctxt.apply_mark(mark)) + span.with_ctxt(span.ctxt.apply_mark(expn_id, transparency)) } #[inline] @@ -611,7 +638,7 @@ impl rustc_serialize::UseSpecializedDecodable for Span { d.read_struct("Span", 2, |d| { let lo = d.read_struct_field("lo", 0, Decodable::decode)?; let hi = d.read_struct_field("hi", 1, Decodable::decode)?; - Ok(Span::new(lo, hi, NO_EXPANSION)) + Ok(Span::with_root_ctxt(lo, hi)) }) } } @@ -755,8 +782,6 @@ impl From> for MultiSpan { } } -pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty(); - /// Identifies an offset of a multi-byte character in a `SourceFile`. #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq, Debug)] pub struct MultiByteChar { @@ -865,7 +890,7 @@ pub struct OffsetOverflowError; /// A single source in the `SourceMap`. #[derive(Clone)] pub struct SourceFile { - /// The name of the file that the source came from, source that doesn't + /// The name of the file that the source came from. Source that doesn't /// originate from files has names between angle brackets by convention /// (e.g., ``). pub name: FileName, @@ -903,9 +928,9 @@ impl Encodable for SourceFile { s.emit_struct_field("name", 0, |s| self.name.encode(s))?; s.emit_struct_field("name_was_remapped", 1, |s| self.name_was_remapped.encode(s))?; s.emit_struct_field("src_hash", 2, |s| self.src_hash.encode(s))?; - s.emit_struct_field("start_pos", 4, |s| self.start_pos.encode(s))?; - s.emit_struct_field("end_pos", 5, |s| self.end_pos.encode(s))?; - s.emit_struct_field("lines", 6, |s| { + s.emit_struct_field("start_pos", 3, |s| self.start_pos.encode(s))?; + s.emit_struct_field("end_pos", 4, |s| self.end_pos.encode(s))?; + s.emit_struct_field("lines", 5, |s| { let lines = &self.lines[..]; // Store the length. s.emit_u32(lines.len() as u32)?; @@ -951,13 +976,13 @@ impl Encodable for SourceFile { Ok(()) })?; - s.emit_struct_field("multibyte_chars", 7, |s| { + s.emit_struct_field("multibyte_chars", 6, |s| { self.multibyte_chars.encode(s) })?; - s.emit_struct_field("non_narrow_chars", 8, |s| { + s.emit_struct_field("non_narrow_chars", 7, |s| { self.non_narrow_chars.encode(s) })?; - s.emit_struct_field("name_hash", 9, |s| { + s.emit_struct_field("name_hash", 8, |s| { self.name_hash.encode(s) }) }) @@ -966,7 +991,6 @@ impl Encodable for SourceFile { impl Decodable for SourceFile { fn decode(d: &mut D) -> Result { - d.read_struct("SourceFile", 8, |d| { let name: FileName = d.read_struct_field("name", 0, |d| Decodable::decode(d))?; let name_was_remapped: bool = @@ -974,9 +998,9 @@ impl Decodable for SourceFile { let src_hash: u128 = d.read_struct_field("src_hash", 2, |d| Decodable::decode(d))?; let start_pos: BytePos = - d.read_struct_field("start_pos", 4, |d| Decodable::decode(d))?; - let end_pos: BytePos = d.read_struct_field("end_pos", 5, |d| Decodable::decode(d))?; - let lines: Vec = d.read_struct_field("lines", 6, |d| { + d.read_struct_field("start_pos", 3, |d| Decodable::decode(d))?; + let end_pos: BytePos = d.read_struct_field("end_pos", 4, |d| Decodable::decode(d))?; + let lines: Vec = d.read_struct_field("lines", 5, |d| { let num_lines: u32 = Decodable::decode(d)?; let mut lines = Vec::with_capacity(num_lines as usize); @@ -1005,18 +1029,18 @@ impl Decodable for SourceFile { Ok(lines) })?; let multibyte_chars: Vec = - d.read_struct_field("multibyte_chars", 7, |d| Decodable::decode(d))?; + d.read_struct_field("multibyte_chars", 6, |d| Decodable::decode(d))?; let non_narrow_chars: Vec = - d.read_struct_field("non_narrow_chars", 8, |d| Decodable::decode(d))?; + d.read_struct_field("non_narrow_chars", 7, |d| Decodable::decode(d))?; let name_hash: u128 = - d.read_struct_field("name_hash", 9, |d| Decodable::decode(d))?; + d.read_struct_field("name_hash", 8, |d| Decodable::decode(d))?; Ok(SourceFile { name, name_was_remapped, unmapped_path: None, // `crate_of_origin` has to be set by the importer. - // This value matches up with rustc::hir::def_id::INVALID_CRATE. - // That constant is not available here unfortunately :( + // This value matches up with `rustc::hir::def_id::INVALID_CRATE`. + // That constant is not available here, unfortunately. crate_of_origin: std::u32::MAX - 1, start_pos, end_pos, @@ -1045,16 +1069,17 @@ impl SourceFile { mut src: String, start_pos: BytePos) -> Result { remove_bom(&mut src); + normalize_newlines(&mut src); let src_hash = { - let mut hasher: StableHasher = StableHasher::new(); + let mut hasher: StableHasher = StableHasher::new(); hasher.write(src.as_bytes()); - hasher.finish() + hasher.finish::() }; let name_hash = { - let mut hasher: StableHasher = StableHasher::new(); + let mut hasher: StableHasher = StableHasher::new(); name.hash(&mut hasher); - hasher.finish() + hasher.finish::() }; let end_pos = start_pos.to_usize() + src.len(); if end_pos > u32::max_value() as usize { @@ -1100,10 +1125,10 @@ impl SourceFile { // Check that no-one else have provided the source while we were getting it if *external_src == ExternalSource::AbsentOk { if let Some(src) = src { - let mut hasher: StableHasher = StableHasher::new(); + let mut hasher: StableHasher = StableHasher::new(); hasher.write(src.as_bytes()); - if hasher.finish() == self.src_hash { + if hasher.finish::() == self.src_hash { *external_src = ExternalSource::Present(src); return true; } @@ -1212,6 +1237,61 @@ fn remove_bom(src: &mut String) { } } + +/// Replaces `\r\n` with `\n` in-place in `src`. +/// +/// Returns error if there's a lone `\r` in the string +fn normalize_newlines(src: &mut String) { + if !src.as_bytes().contains(&b'\r') { + return; + } + + // We replace `\r\n` with `\n` in-place, which doesn't break utf-8 encoding. + // While we *can* call `as_mut_vec` and do surgery on the live string + // directly, let's rather steal the contents of `src`. This makes the code + // safe even if a panic occurs. + + let mut buf = std::mem::replace(src, String::new()).into_bytes(); + let mut gap_len = 0; + let mut tail = buf.as_mut_slice(); + loop { + let idx = match find_crlf(&tail[gap_len..]) { + None => tail.len(), + Some(idx) => idx + gap_len, + }; + tail.copy_within(gap_len..idx, 0); + tail = &mut tail[idx - gap_len..]; + if tail.len() == gap_len { + break; + } + gap_len += 1; + } + + // Account for removed `\r`. + // After `set_len`, `buf` is guaranteed to contain utf-8 again. + let new_len = buf.len() - gap_len; + unsafe { + buf.set_len(new_len); + *src = String::from_utf8_unchecked(buf); + } + + fn find_crlf(src: &[u8]) -> Option { + let mut search_idx = 0; + while let Some(idx) = find_cr(&src[search_idx..]) { + if src[search_idx..].get(idx + 1) != Some(&b'\n') { + search_idx += idx + 1; + continue; + } + return Some(search_idx + idx); + } + None + } + + fn find_cr(src: &[u8]) -> Option { + src.iter().position(|&b| b == b'\r') + } +} + // _____________________________________________________________________________ // Pos, BytePos, CharPos // diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index f7e1b983e5446..2b005c3fc421a 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -4,17 +4,16 @@ use arena::DroplessArena; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::indexed_vec::Idx; -use rustc_data_structures::newtype_index; +use rustc_index::vec::Idx; use rustc_macros::symbols; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use rustc_serialize::{UseSpecializedDecodable, UseSpecializedEncodable}; use std::cmp::{PartialEq, Ordering, PartialOrd, Ord}; use std::fmt; use std::hash::{Hash, Hasher}; use std::str; -use crate::hygiene::SyntaxContext; use crate::{Span, DUMMY_SP, GLOBALS}; #[cfg(test)] @@ -83,11 +82,11 @@ symbols! { Yield: "yield", // Edition-specific keywords that are used in stable Rust. + Async: "async", // >= 2018 Edition only + Await: "await", // >= 2018 Edition only Dyn: "dyn", // >= 2018 Edition only // Edition-specific keywords that are used in unstable Rust or reserved for future use. - Async: "async", // >= 2018 Edition only - Await: "await", // >= 2018 Edition only Try: "try", // >= 2018 Edition only // Special lifetime names @@ -197,6 +196,7 @@ symbols! { console, const_compare_raw_pointers, const_constructor, + const_extern_fn, const_fn, const_fn_union, const_generics, @@ -225,9 +225,10 @@ symbols! { custom_inner_attributes, custom_test_frameworks, c_variadic, - Debug, + debug_trait, declare_lint_pass, decl_macro, + Debug, Decodable, Default, default_lib_allocator, @@ -238,6 +239,7 @@ symbols! { deref, deref_mut, derive, + diagnostic, direct, doc, doc_alias, @@ -387,6 +389,7 @@ symbols! { link_cfg, link_llvm_intrinsics, link_name, + link_ordinal, link_section, LintPass, lint_reasons, @@ -412,6 +415,7 @@ symbols! { match_beginning_vert, match_default_bindings, may_dangle, + mem, member_constraints, message, meta, @@ -469,6 +473,7 @@ symbols! { option_env, opt_out_copy, or, + or_patterns, Ord, Ordering, Output, @@ -527,6 +532,7 @@ symbols! { RangeInclusive, RangeTo, RangeToInclusive, + raw_dylib, raw_identifiers, Ready, reason, @@ -567,6 +573,7 @@ symbols! { rustc_conversion_suggestion, rustc_def_path, rustc_deprecated, + rustc_diagnostic_item, rustc_diagnostic_macros, rustc_dirty, rustc_dummy, @@ -593,6 +600,7 @@ symbols! { rustc_peek_definite_init, rustc_peek_maybe_init, rustc_peek_maybe_uninit, + rustc_peek_indirectly_mutable, rustc_private, rustc_proc_macro_decls, rustc_promotable, @@ -601,6 +609,7 @@ symbols! { rustc_std_internal_symbol, rustc_symbol_name, rustc_synthetic, + rustc_reservation_impl, rustc_test_marker, rustc_then_this_would_need, rustc_variance, @@ -609,7 +618,6 @@ symbols! { rust_eh_personality, rust_eh_unwind_resume, rust_oom, - __rust_unstable_column, rvalue_static_promotion, sanitizer_runtime, _Self, @@ -622,6 +630,7 @@ symbols! { size, slice_patterns, slicing_syntax, + soft, Some, specialization, speed, @@ -665,6 +674,7 @@ symbols! { tool_attributes, tool_lints, trace_macros, + track_caller, trait_alias, transmute, transparent, @@ -695,6 +705,7 @@ symbols! { underscore_imports, underscore_lifetimes, uniform_paths, + uninitialized, universal_impl_trait, unmarked_api, unreachable_code, @@ -726,6 +737,7 @@ symbols! { windows, windows_subsystem, Yield, + zeroed, } } @@ -742,25 +754,25 @@ impl Ident { Ident { name, span } } - /// Constructs a new identifier with an empty syntax context. + /// Constructs a new identifier with a dummy span. #[inline] - pub const fn with_empty_ctxt(name: Symbol) -> Ident { + pub const fn with_dummy_span(name: Symbol) -> Ident { Ident::new(name, DUMMY_SP) } #[inline] pub fn invalid() -> Ident { - Ident::with_empty_ctxt(kw::Invalid) + Ident::with_dummy_span(kw::Invalid) } /// Maps an interned string to an identifier with an empty syntax context. pub fn from_interned_str(string: InternedString) -> Ident { - Ident::with_empty_ctxt(string.as_symbol()) + Ident::with_dummy_span(string.as_symbol()) } - /// Maps a string to an identifier with an empty span. + /// Maps a string to an identifier with a dummy span. pub fn from_str(string: &str) -> Ident { - Ident::with_empty_ctxt(Symbol::intern(string)) + Ident::with_dummy_span(Symbol::intern(string)) } /// Maps a string and a span to an identifier. @@ -795,27 +807,25 @@ impl Ident { Ident::new(self.name, self.span.modern_and_legacy()) } - /// Transforms an identifier into one with the same name, but gensymed. - pub fn gensym(self) -> Ident { - let name = with_interner(|interner| interner.gensymed(self.name)); - Ident::new(name, self.span) - } - /// Transforms an underscore identifier into one with the same name, but /// gensymed. Leaves non-underscore identifiers unchanged. pub fn gensym_if_underscore(self) -> Ident { - if self.name == kw::Underscore { self.gensym() } else { self } - } - - // WARNING: this function is deprecated and will be removed in the future. - pub fn is_gensymed(self) -> bool { - with_interner(|interner| interner.is_gensymed(self.name)) + if self.name == kw::Underscore { + let name = with_interner(|interner| interner.gensymed(self.name)); + Ident::new(name, self.span) + } else { + self + } } + /// Convert the name to a `LocalInternedString`. This is a slowish + /// operation because it requires locking the symbol interner. pub fn as_str(self) -> LocalInternedString { self.name.as_str() } + /// Convert the name to an `InternedString`. This is a slowish operation + /// because it requires locking the symbol interner. pub fn as_interned_str(self) -> InternedString { self.name.as_interned_str() } @@ -846,25 +856,26 @@ impl fmt::Display for Ident { } } -impl Encodable for Ident { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - if self.span.ctxt().modern() == SyntaxContext::empty() { - s.emit_str(&self.as_str()) - } else { // FIXME(jseyfried): intercrate hygiene - let mut string = "#".to_owned(); - string.push_str(&self.as_str()); - s.emit_str(&string) - } +impl UseSpecializedEncodable for Ident { + fn default_encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_struct("Ident", 2, |s| { + s.emit_struct_field("name", 0, |s| { + self.name.encode(s) + })?; + s.emit_struct_field("span", 1, |s| { + self.span.encode(s) + }) + }) } } -impl Decodable for Ident { - fn decode(d: &mut D) -> Result { - let string = d.read_str()?; - Ok(if !string.starts_with('#') { - Ident::from_str(&string) - } else { // FIXME(jseyfried): intercrate hygiene - Ident::from_str(&string[1..]).gensym() +impl UseSpecializedDecodable for Ident { + fn default_decode(d: &mut D) -> Result { + d.read_struct("Ident", 2, |d| { + Ok(Ident { + name: d.read_struct_field("name", 0, Decodable::decode)?, + span: d.read_struct_field("span", 1, Decodable::decode)?, + }) }) } } @@ -881,21 +892,24 @@ impl Decodable for Ident { /// /// Examples: /// ``` -/// assert_eq!(Ident::from_str("x"), Ident::from_str("x")) -/// assert_ne!(Ident::from_str("x").gensym(), Ident::from_str("x")) -/// assert_ne!(Ident::from_str("x").gensym(), Ident::from_str("x").gensym()) +/// assert_eq!(Ident::from_str("_"), Ident::from_str("_")) +/// assert_ne!(Ident::from_str("_").gensym_if_underscore(), Ident::from_str("_")) +/// assert_ne!( +/// Ident::from_str("_").gensym_if_underscore(), +/// Ident::from_str("_").gensym_if_underscore(), +/// ) /// ``` /// Internally, a symbol is implemented as an index, and all operations /// (including hashing, equality, and ordering) operate on that index. The use -/// of `newtype_index!` means that `Option` only takes up 4 bytes, -/// because `newtype_index!` reserves the last 256 values for tagging purposes. +/// of `rustc_index::newtype_index!` means that `Option` only takes up 4 bytes, +/// because `rustc_index::newtype_index!` reserves the last 256 values for tagging purposes. /// -/// Note that `Symbol` cannot directly be a `newtype_index!` because it +/// Note that `Symbol` cannot directly be a `rustc_index::newtype_index!` because it /// implements `fmt::Debug`, `Encodable`, and `Decodable` in special ways. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Symbol(SymbolIndex); -newtype_index! { +rustc_index::newtype_index! { pub struct SymbolIndex { .. } } @@ -909,6 +923,25 @@ impl Symbol { with_interner(|interner| interner.intern(string)) } + /// Access the symbol's chars. This is a slowish operation because it + /// requires locking the symbol interner. + pub fn with R, R>(self, f: F) -> R { + with_interner(|interner| { + f(interner.get(self)) + }) + } + + /// Access two symbols' chars. This is a slowish operation because it + /// requires locking the symbol interner, but it is faster than calling + /// `with()` twice. + fn with2 R, R>(self, other: Symbol, f: F) -> R { + with_interner(|interner| { + f(interner.get(self), interner.get(other)) + }) + } + + /// Convert to a `LocalInternedString`. This is a slowish operation because + /// it requires locking the symbol interner. pub fn as_str(self) -> LocalInternedString { with_interner(|interner| unsafe { LocalInternedString { @@ -917,6 +950,8 @@ impl Symbol { }) } + /// Convert to an `InternedString`. This is a slowish operation because it + /// requires locking the symbol interner. pub fn as_interned_str(self) -> InternedString { with_interner(|interner| InternedString { symbol: interner.interned(self) @@ -1057,11 +1092,11 @@ pub mod sym { impl Symbol { fn is_used_keyword_2018(self) -> bool { - self == kw::Dyn + self >= kw::Async && self <= kw::Dyn } fn is_unused_keyword_2018(self) -> bool { - self >= kw::Async && self <= kw::Try + self == kw::Try } /// Used for sanity checking rustdoc keyword sections. @@ -1079,6 +1114,11 @@ impl Symbol { self == kw::DollarCrate } + /// Returns `true` if the symbol is `true` or `false`. + pub fn is_bool_lit(self) -> bool { + self == kw::True || self == kw::False + } + /// This symbol can be a raw identifier. pub fn can_be_raw(self) -> bool { self != kw::Invalid && self != kw::Underscore && !self.is_path_segment_keyword() @@ -1140,39 +1180,11 @@ fn with_interner T>(f: F) -> T { // FIXME: ensure that the interner outlives any thread which uses // `LocalInternedString`, by creating a new thread right after constructing the // interner. -#[derive(Clone, Copy, Hash, PartialOrd, Eq, Ord)] +#[derive(Clone, Copy, Eq, PartialOrd, Ord)] pub struct LocalInternedString { string: &'static str, } -impl LocalInternedString { - /// Maps a string to its interned representation. - pub fn intern(string: &str) -> Self { - let string = with_interner(|interner| { - let symbol = interner.intern(string); - interner.strings[symbol.0.as_usize()] - }); - LocalInternedString { - string: unsafe { std::mem::transmute::<&str, &str>(string) } - } - } - - pub fn as_interned_str(self) -> InternedString { - InternedString { - symbol: Symbol::intern(self.string) - } - } - - #[inline] - pub fn get(&self) -> &str { - // This returns a valid string since we ensure that `self` outlives the interner - // by creating the interner on a thread which outlives threads which can access it. - // This type cannot move to a thread which outlives the interner since it does - // not implement Send. - self.string - } -} - impl std::convert::AsRef for LocalInternedString where str: std::convert::AsRef @@ -1234,18 +1246,6 @@ impl fmt::Display for LocalInternedString { } } -impl Decodable for LocalInternedString { - fn decode(d: &mut D) -> Result { - Ok(LocalInternedString::intern(&d.read_str()?)) - } -} - -impl Encodable for LocalInternedString { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_str(self.string) - } -} - /// An alternative to `Symbol` that is focused on string contents. It has two /// main differences to `Symbol`. /// @@ -1273,28 +1273,19 @@ impl InternedString { } pub fn with R, R>(self, f: F) -> R { - let str = with_interner(|interner| { - interner.get(self.symbol) as *const str - }); - // This is safe because the interner keeps string alive until it is dropped. - // We can access it because we know the interner is still alive since we use a - // scoped thread local to access it, and it was alive at the beginning of this scope - unsafe { f(&*str) } + self.symbol.with(f) } fn with2 R, R>(self, other: &InternedString, f: F) -> R { - let (self_str, other_str) = with_interner(|interner| { - (interner.get(self.symbol) as *const str, - interner.get(other.symbol) as *const str) - }); - // This is safe for the same reason that `with` is safe. - unsafe { f(&*self_str, &*other_str) } + self.symbol.with2(other.symbol, f) } pub fn as_symbol(self) -> Symbol { self.symbol } + /// Convert to a `LocalInternedString`. This is a slowish operation because it + /// requires locking the symbol interner. pub fn as_str(self) -> LocalInternedString { self.symbol.as_str() } diff --git a/src/libsyntax_pos/tests.rs b/src/libsyntax_pos/tests.rs index 78c4e18e6aee0..6bd6016020a27 100644 --- a/src/libsyntax_pos/tests.rs +++ b/src/libsyntax_pos/tests.rs @@ -16,3 +16,23 @@ fn test_lookup_line() { assert_eq!(lookup_line(lines, BytePos(28)), 2); assert_eq!(lookup_line(lines, BytePos(29)), 2); } + +#[test] +fn test_normalize_newlines() { + fn check(before: &str, after: &str) { + let mut actual = before.to_string(); + normalize_newlines(&mut actual); + assert_eq!(actual.as_str(), after); + } + check("", ""); + check("\n", "\n"); + check("\r", "\r"); + check("\r\r", "\r\r"); + check("\r\n", "\n"); + check("hello world", "hello world"); + check("hello\nworld", "hello\nworld"); + check("hello\r\nworld", "hello\nworld"); + check("\r\nhello\r\nworld\r\n", "\nhello\nworld\n"); + check("\r\r\n", "\r\n"); + check("hello\rworld", "hello\rworld"); +} diff --git a/src/libterm/Cargo.toml b/src/libterm/Cargo.toml index 4eba9a9d79cc4..2931e0bda9518 100644 --- a/src/libterm/Cargo.toml +++ b/src/libterm/Cargo.toml @@ -5,6 +5,8 @@ version = "0.0.0" edition = "2018" [lib] -name = "term" path = "lib.rs" -crate-type = ["dylib", "rlib"] + +[dependencies] +core = { path = "../libcore" } +std = { path = "../libstd" } diff --git a/src/libtest/Cargo.toml b/src/libtest/Cargo.toml index a72e4c7050289..170fbb984cf9b 100644 --- a/src/libtest/Cargo.toml +++ b/src/libtest/Cargo.toml @@ -10,8 +10,22 @@ path = "lib.rs" crate-type = ["dylib", "rlib"] [dependencies] -getopts = "0.2.19" +getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] } term = { path = "../libterm" } +std = { path = "../libstd" } +core = { path = "../libcore" } +libc = { version = "0.2", default-features = false } +panic_unwind = { path = "../libpanic_unwind" } +panic_abort = { path = "../libpanic_abort" } # not actually used but needed to always have proc_macro in the sysroot proc_macro = { path = "../libproc_macro" } + +# Forward features to the `std` crate as necessary +[features] +backtrace = ["std/backtrace"] +compiler-builtins-c = ["std/compiler-builtins-c"] +llvm-libunwind = ["std/llvm-libunwind"] +panic-unwind = ["std/panic_unwind"] +panic_immediate_abort = ["std/panic_immediate_abort"] +profiler = ["std/profiler"] diff --git a/src/libtest/formatters/json.rs b/src/libtest/formatters/json.rs index a06497f98626a..dcd733620bf90 100644 --- a/src/libtest/formatters/json.rs +++ b/src/libtest/formatters/json.rs @@ -9,44 +9,64 @@ impl JsonFormatter { Self { out } } - fn write_message(&mut self, s: &str) -> io::Result<()> { + fn writeln_message(&mut self, s: &str) -> io::Result<()> { assert!(!s.contains('\n')); self.out.write_all(s.as_ref())?; self.out.write_all(b"\n") } + fn write_message(&mut self, s: &str) -> io::Result<()> { + assert!(!s.contains('\n')); + + self.out.write_all(s.as_ref()) + } + fn write_event( &mut self, ty: &str, name: &str, evt: &str, - extra: Option, + exec_time: Option<&TestExecTime>, + stdout: Option>, + extra: Option<&str>, ) -> io::Result<()> { - if let Some(extras) = extra { + self.write_message(&*format!( + r#"{{ "type": "{}", "name": "{}", "event": "{}""#, + ty, name, evt + ))?; + if let Some(exec_time) = exec_time { self.write_message(&*format!( - r#"{{ "type": "{}", "name": "{}", "event": "{}", {} }}"#, - ty, name, evt, extras - )) - } else { + r#", "exec_time": "{}""#, + exec_time + ))?; + } + if let Some(stdout) = stdout { + self.write_message(&*format!( + r#", "stdout": "{}""#, + EscapedString(stdout) + ))?; + } + if let Some(extra) = extra { self.write_message(&*format!( - r#"{{ "type": "{}", "name": "{}", "event": "{}" }}"#, - ty, name, evt - )) + r#", {}"#, + extra + ))?; } + self.writeln_message(" }") } } impl OutputFormatter for JsonFormatter { fn write_run_start(&mut self, test_count: usize) -> io::Result<()> { - self.write_message(&*format!( + self.writeln_message(&*format!( r#"{{ "type": "suite", "event": "started", "test_count": {} }}"#, test_count )) } fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> { - self.write_message(&*format!( + self.writeln_message(&*format!( r#"{{ "type": "test", "event": "started", "name": "{}" }}"#, desc.name )) @@ -56,37 +76,55 @@ impl OutputFormatter for JsonFormatter { &mut self, desc: &TestDesc, result: &TestResult, + exec_time: Option<&TestExecTime>, stdout: &[u8], + state: &ConsoleTestState, ) -> io::Result<()> { + let stdout = if (state.options.display_output || *result != TrOk) && stdout.len() > 0 { + Some(String::from_utf8_lossy(stdout)) + } else { + None + }; match *result { - TrOk => self.write_event("test", desc.name.as_slice(), "ok", None), + TrOk => { + self.write_event("test", desc.name.as_slice(), "ok", exec_time, stdout, None) + } TrFailed => { - let extra_data = if stdout.len() > 0 { - Some(format!( - r#""stdout": "{}""#, - EscapedString(String::from_utf8_lossy(stdout)) - )) - } else { - None - }; - - self.write_event("test", desc.name.as_slice(), "failed", extra_data) + self.write_event("test", desc.name.as_slice(), "failed", exec_time, stdout, None) } - TrFailedMsg(ref m) => self.write_event( + TrTimedFail => self.write_event( "test", desc.name.as_slice(), "failed", - Some(format!(r#""message": "{}""#, EscapedString(m))), + exec_time, + stdout, + Some(r#""reason": "time limit exceeded""#), ), - TrIgnored => self.write_event("test", desc.name.as_slice(), "ignored", None), + TrFailedMsg(ref m) => self.write_event( + "test", + desc.name.as_slice(), + "failed", + exec_time, + stdout, + Some(&*format!(r#""message": "{}""#, EscapedString(m))), + ), - TrAllowedFail => { - self.write_event("test", desc.name.as_slice(), "allowed_failure", None) + TrIgnored => { + self.write_event("test", desc.name.as_slice(), "ignored", exec_time, stdout, None) } + TrAllowedFail => self.write_event( + "test", + desc.name.as_slice(), + "allowed_failure", + exec_time, + stdout, + None, + ), + TrBench(ref bs) => { let median = bs.ns_iter_summ.median as usize; let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize; @@ -105,20 +143,20 @@ impl OutputFormatter for JsonFormatter { desc.name, median, deviation, mbps ); - self.write_message(&*line) + self.writeln_message(&*line) } } } fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> { - self.write_message(&*format!( + self.writeln_message(&*format!( r#"{{ "type": "test", "event": "timeout", "name": "{}" }}"#, desc.name )) } fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result { - self.write_message(&*format!( + self.writeln_message(&*format!( "{{ \"type\": \"suite\", \ \"event\": \"{}\", \ \"passed\": {}, \ diff --git a/src/libtest/formatters/mod.rs b/src/libtest/formatters/mod.rs index be5f6a65039b7..dd202fb3ab6fa 100644 --- a/src/libtest/formatters/mod.rs +++ b/src/libtest/formatters/mod.rs @@ -16,7 +16,18 @@ pub(crate) trait OutputFormatter { &mut self, desc: &TestDesc, result: &TestResult, + exec_time: Option<&TestExecTime>, stdout: &[u8], + state: &ConsoleTestState, ) -> io::Result<()>; fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result; } + +pub(crate) fn write_stderr_delimiter(test_output: &mut Vec, test_name: &TestName) { + match test_output.last() { + Some(b'\n') => (), + Some(_) => test_output.push(b'\n'), + None => (), + } + write!(test_output, "---- {} stderr ----\n", test_name).unwrap(); +} diff --git a/src/libtest/formatters/pretty.rs b/src/libtest/formatters/pretty.rs index 4af00428ca87e..2935b4c99cec4 100644 --- a/src/libtest/formatters/pretty.rs +++ b/src/libtest/formatters/pretty.rs @@ -3,6 +3,7 @@ use super::*; pub(crate) struct PrettyFormatter { out: OutputLocation, use_color: bool, + time_options: Option, /// Number of columns to fill when aligning names max_name_len: usize, @@ -16,12 +17,14 @@ impl PrettyFormatter { use_color: bool, max_name_len: usize, is_multithreaded: bool, + time_options: Option, ) -> Self { PrettyFormatter { out, use_color, max_name_len, is_multithreaded, + time_options } } @@ -46,6 +49,10 @@ impl PrettyFormatter { self.write_short_result("FAILED (allowed)", term::color::YELLOW) } + pub fn write_time_failed(&mut self) -> io::Result<()> { + self.write_short_result("FAILED (time limit exceeded)", term::color::RED) + } + pub fn write_bench(&mut self) -> io::Result<()> { self.write_pretty("bench", term::color::CYAN) } @@ -55,8 +62,7 @@ impl PrettyFormatter { result: &str, color: term::color::Color, ) -> io::Result<()> { - self.write_pretty(result, color)?; - self.write_plain("\n") + self.write_pretty(result, color) } pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> { @@ -84,12 +90,48 @@ impl PrettyFormatter { self.out.flush() } - pub fn write_successes(&mut self, state: &ConsoleTestState) -> io::Result<()> { - self.write_plain("\nsuccesses:\n")?; - let mut successes = Vec::new(); + fn write_time( + &mut self, + desc: &TestDesc, + exec_time: Option<&TestExecTime> + ) -> io::Result<()> { + if let (Some(opts), Some(time)) = (self.time_options, exec_time) { + let time_str = format!(" <{}>", time); + + let color = if opts.colored { + if opts.is_critical(desc, time) { + Some(term::color::RED) + } else if opts.is_warn(desc, time) { + Some(term::color::YELLOW) + } else { + None + } + } else { + None + }; + + match color { + Some(color) => self.write_pretty(&time_str, color)?, + None => self.write_plain(&time_str)? + } + } + + Ok(()) + } + + fn write_results( + &mut self, + inputs: &Vec<(TestDesc, Vec)>, + results_type: &str + ) -> io::Result<()> { + let results_out_str = format!("\n{}:\n", results_type); + + self.write_plain(&results_out_str)?; + + let mut results = Vec::new(); let mut stdouts = String::new(); - for &(ref f, ref stdout) in &state.not_failures { - successes.push(f.name.to_string()); + for &(ref f, ref stdout) in inputs { + results.push(f.name.to_string()); if !stdout.is_empty() { stdouts.push_str(&format!("---- {} stdout ----\n", f.name)); let output = String::from_utf8_lossy(stdout); @@ -102,38 +144,24 @@ impl PrettyFormatter { self.write_plain(&stdouts)?; } - self.write_plain("\nsuccesses:\n")?; - successes.sort(); - for name in &successes { + self.write_plain(&results_out_str)?; + results.sort(); + for name in &results { self.write_plain(&format!(" {}\n", name))?; } Ok(()) } + pub fn write_successes(&mut self, state: &ConsoleTestState) -> io::Result<()> { + self.write_results(&state.not_failures, "successes") + } + pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> { - self.write_plain("\nfailures:\n")?; - let mut failures = Vec::new(); - let mut fail_out = String::new(); - for &(ref f, ref stdout) in &state.failures { - failures.push(f.name.to_string()); - if !stdout.is_empty() { - fail_out.push_str(&format!("---- {} stdout ----\n", f.name)); - let output = String::from_utf8_lossy(stdout); - fail_out.push_str(&output); - fail_out.push_str("\n"); - } - } - if !fail_out.is_empty() { - self.write_plain("\n")?; - self.write_plain(&fail_out)?; - } + self.write_results(&state.failures, "failures") + } - self.write_plain("\nfailures:\n")?; - failures.sort(); - for name in &failures { - self.write_plain(&format!(" {}\n", name))?; - } - Ok(()) + pub fn write_time_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> { + self.write_results(&state.time_failures, "failures (time limit exceeded)") } fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> { @@ -162,21 +190,32 @@ impl OutputFormatter for PrettyFormatter { Ok(()) } - fn write_result(&mut self, desc: &TestDesc, result: &TestResult, _: &[u8]) -> io::Result<()> { + fn write_result( + &mut self, + desc: &TestDesc, + result: &TestResult, + exec_time: Option<&TestExecTime>, + _: &[u8], + _: &ConsoleTestState, + ) -> io::Result<()> { if self.is_multithreaded { self.write_test_name(desc)?; } match *result { - TrOk => self.write_ok(), - TrFailed | TrFailedMsg(_) => self.write_failed(), - TrIgnored => self.write_ignored(), - TrAllowedFail => self.write_allowed_fail(), + TrOk => self.write_ok()?, + TrFailed | TrFailedMsg(_) => self.write_failed()?, + TrIgnored => self.write_ignored()?, + TrAllowedFail => self.write_allowed_fail()?, TrBench(ref bs) => { self.write_bench()?; - self.write_plain(&format!(": {}\n", fmt_bench_samples(bs))) + self.write_plain(&format!(": {}", fmt_bench_samples(bs)))?; } + TrTimedFail => self.write_time_failed()?, } + + self.write_time(desc, exec_time)?; + self.write_plain("\n") } fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> { @@ -196,7 +235,13 @@ impl OutputFormatter for PrettyFormatter { } let success = state.failed == 0; if !success { - self.write_failures(state)?; + if !state.failures.is_empty() { + self.write_failures(state)?; + } + + if !state.time_failures.is_empty() { + self.write_time_failures(state)?; + } } self.write_plain("\ntest result: ")?; diff --git a/src/libtest/formatters/terse.rs b/src/libtest/formatters/terse.rs index 1400fba5d6092..8914e7b6b5685 100644 --- a/src/libtest/formatters/terse.rs +++ b/src/libtest/formatters/terse.rs @@ -170,10 +170,17 @@ impl OutputFormatter for TerseFormatter { Ok(()) } - fn write_result(&mut self, desc: &TestDesc, result: &TestResult, _: &[u8]) -> io::Result<()> { + fn write_result( + &mut self, + desc: &TestDesc, + result: &TestResult, + _: Option<&TestExecTime>, + _: &[u8], + _: &ConsoleTestState, + ) -> io::Result<()> { match *result { TrOk => self.write_ok(), - TrFailed | TrFailedMsg(_) => self.write_failed(), + TrFailed | TrFailedMsg(_) | TrTimedFail => self.write_failed(), TrIgnored => self.write_ignored(), TrAllowedFail => self.write_allowed_fail(), TrBench(ref bs) => { diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index ef66c4df99da7..5a77413b2cbbf 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -21,7 +21,8 @@ #![unstable(feature = "test", issue = "50297")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] #![feature(asm)] -#![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc, rustc_private))] +#![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc))] +#![feature(rustc_private)] #![feature(nll)] #![feature(set_stdio)] #![feature(panic_unwind)] @@ -34,16 +35,6 @@ use getopts; extern crate libc; use term; -// FIXME(#54291): rustc and/or LLVM don't yet support building with panic-unwind -// on aarch64-pc-windows-msvc, or thumbv7a-pc-windows-msvc -// so we don't link libtest against libunwind (for the time being) -// even though it means that libtest won't be fully functional on -// these platforms. -// -// See also: https://github.com/rust-lang/rust/issues/54190#issuecomment-422904437 -#[cfg(not(all(windows, any(target_arch = "aarch64", target_arch = "arm"))))] -extern crate panic_unwind; - pub use self::ColorConfig::*; use self::NamePadding::*; use self::OutputLocation::*; @@ -61,10 +52,11 @@ use std::fmt; use std::fs::File; use std::io; use std::io::prelude::*; -use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::panic::{self, catch_unwind, AssertUnwindSafe, PanicInfo}; use std::path::PathBuf; use std::process; -use std::process::Termination; +use std::process::{ExitStatus, Command, Termination}; +use std::str::FromStr; use std::sync::mpsc::{channel, Sender}; use std::sync::{Arc, Mutex}; use std::thread; @@ -76,13 +68,62 @@ mod tests; const TEST_WARN_TIMEOUT_S: u64 = 60; const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in quiet mode +const SECONDARY_TEST_INVOKER_VAR: &'static str = "__RUST_TEST_INVOKE"; + +// Return codes for secondary process. +// Start somewhere other than 0 so we know the return code means what we think +// it means. +const TR_OK: i32 = 50; +const TR_FAILED: i32 = 51; + +/// This small module contains constants used by `report-time` option. +/// Those constants values will be used if corresponding environment variables are not set. +/// +/// To override values for unit-tests, use a constant `RUST_TEST_TIME_UNIT`, +/// To override values for integration tests, use a constant `RUST_TEST_TIME_INTEGRATION`, +/// To override values for doctests, use a constant `RUST_TEST_TIME_DOCTEST`. +/// +/// Example of the expected format is `RUST_TEST_TIME_xxx=100,200`, where 100 means +/// warn time, and 200 means critical time. +pub mod time_constants { + use std::time::Duration; + use super::TEST_WARN_TIMEOUT_S; + + /// Environment variable for overriding default threshold for unit-tests. + pub const UNIT_ENV_NAME: &str = "RUST_TEST_TIME_UNIT"; + + // Unit tests are supposed to be really quick. + pub const UNIT_WARN: Duration = Duration::from_millis(50); + pub const UNIT_CRITICAL: Duration = Duration::from_millis(100); + + /// Environment variable for overriding default threshold for unit-tests. + pub const INTEGRATION_ENV_NAME: &str = "RUST_TEST_TIME_INTEGRATION"; + + // Integration tests may have a lot of work, so they can take longer to execute. + pub const INTEGRATION_WARN: Duration = Duration::from_millis(500); + pub const INTEGRATION_CRITICAL: Duration = Duration::from_millis(1000); + + /// Environment variable for overriding default threshold for unit-tests. + pub const DOCTEST_ENV_NAME: &str = "RUST_TEST_TIME_DOCTEST"; + + // Doctests are similar to integration tests, because they can include a lot of + // initialization code. + pub const DOCTEST_WARN: Duration = INTEGRATION_WARN; + pub const DOCTEST_CRITICAL: Duration = INTEGRATION_CRITICAL; + + // Do not suppose anything about unknown tests, base limits on the + // `TEST_WARN_TIMEOUT_S` constant. + pub const UNKNOWN_WARN: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S); + pub const UNKNOWN_CRITICAL: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S * 2); +} + // to be used by rustc to compile tests in libtest pub mod test { pub use crate::{ assert_test_result, filter_tests, parse_opts, run_test, test_main, test_main_static, - Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, RunIgnored, ShouldPanic, - StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestName, TestOpts, - TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk, + Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, RunIgnored, RunStrategy, + ShouldPanic, StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestName, + TestOpts, TestTimeOptions, TestType, TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk, }; } @@ -98,6 +139,21 @@ pub enum Concurrent { No, } +/// Type of the test according to the [rust book](https://doc.rust-lang.org/cargo/guide/tests.html) +/// conventions. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum TestType { + /// Unit-tests are expected to be in the `src` folder of the crate. + UnitTest, + /// Integration-style tests are expected to be in the `tests` folder of the crate. + IntegrationTest, + /// Doctests are created by the `librustdoc` manually, so it's a different type of test. + DocTest, + /// Tests for the sources that don't follow the project layout convention + /// (e.g. tests in raw `main.rs` compiled by calling `rustc --test` directly). + Unknown, +} + // The name of a test. By convention this follows the rules for rust // paths; i.e., it should be a series of identifiers separated by double // colons. This way if some test runner wants to arrange the tests @@ -233,6 +289,7 @@ pub struct TestDesc { pub ignore: bool, pub should_panic: ShouldPanic, pub allow_fail: bool, + pub test_type: TestType, } #[derive(Debug)] @@ -257,12 +314,14 @@ impl Metric { #[derive(Copy, Clone, Debug)] pub struct Options { display_output: bool, + panic_abort: bool, } impl Options { pub fn new() -> Options { Options { display_output: false, + panic_abort: false, } } @@ -270,11 +329,16 @@ impl Options { self.display_output = display_output; self } + + pub fn panic_abort(mut self, panic_abort: bool) -> Options { + self.panic_abort = panic_abort; + self + } } // The default console test runner. It accepts the command line // arguments and a vector of test_descs. -pub fn test_main(args: &[String], tests: Vec, options: Options) { +pub fn test_main(args: &[String], tests: Vec, options: Option) { let mut opts = match parse_opts(args) { Some(Ok(o)) => o, Some(Err(msg)) => { @@ -283,8 +347,9 @@ pub fn test_main(args: &[String], tests: Vec, options: Options) { } None => return, }; - - opts.options = options; + if let Some(options) = options { + opts.options = options; + } if opts.list { if let Err(e) = list_tests_console(&opts, tests) { eprintln!("error: io error when listing tests: {:?}", e); @@ -302,30 +367,64 @@ pub fn test_main(args: &[String], tests: Vec, options: Options) { } } -// A variant optimized for invocation with a static test vector. -// This will panic (intentionally) when fed any dynamic tests, because -// it is copying the static values out into a dynamic vector and cannot -// copy dynamic values. It is doing this because from this point on -// a Vec is used in order to effect ownership-transfer -// semantics into parallel test runners, which in turn requires a Vec<> -// rather than a &[]. +/// A variant optimized for invocation with a static test vector. +/// This will panic (intentionally) when fed any dynamic tests. +/// +/// This is the entry point for the main function generated by `rustc --test` +/// when panic=unwind. pub fn test_main_static(tests: &[&TestDescAndFn]) { let args = env::args().collect::>(); - let owned_tests = tests - .iter() - .map(|t| match t.testfn { - StaticTestFn(f) => TestDescAndFn { - testfn: StaticTestFn(f), - desc: t.desc.clone(), - }, - StaticBenchFn(f) => TestDescAndFn { - testfn: StaticBenchFn(f), - desc: t.desc.clone(), - }, - _ => panic!("non-static tests passed to test::test_main_static"), - }) - .collect(); - test_main(&args, owned_tests, Options::new()) + let owned_tests: Vec<_> = tests.iter().map(make_owned_test).collect(); + test_main(&args, owned_tests, None) +} + +/// A variant optimized for invocation with a static test vector. +/// This will panic (intentionally) when fed any dynamic tests. +/// +/// Runs tests in panic=abort mode, which involves spawning subprocesses for +/// tests. +/// +/// This is the entry point for the main function generated by `rustc --test` +/// when panic=abort. +pub fn test_main_static_abort(tests: &[&TestDescAndFn]) { + // If we're being run in SpawnedSecondary mode, run the test here. run_test + // will then exit the process. + if let Ok(name) = env::var(SECONDARY_TEST_INVOKER_VAR) { + let test = tests + .iter() + .filter(|test| test.desc.name.as_slice() == name) + .map(make_owned_test) + .next() + .expect("couldn't find a test with the provided name"); + let TestDescAndFn { desc, testfn } = test; + let testfn = match testfn { + StaticTestFn(f) => f, + _ => panic!("only static tests are supported"), + }; + run_test_in_spawned_subprocess(desc, Box::new(testfn)); + } + + let args = env::args().collect::>(); + let owned_tests: Vec<_> = tests.iter().map(make_owned_test).collect(); + test_main(&args, owned_tests, Some(Options::new().panic_abort(true))) +} + +/// Clones static values for putting into a dynamic vector, which test_main() +/// needs to hand out ownership of tests to parallel test runners. +/// +/// This will panic when fed any dynamic tests, because they cannot be cloned. +fn make_owned_test(test: &&TestDescAndFn) -> TestDescAndFn { + match test.testfn { + StaticTestFn(f) => TestDescAndFn { + testfn: StaticTestFn(f), + desc: test.desc.clone(), + }, + StaticBenchFn(f) => TestDescAndFn { + testfn: StaticBenchFn(f), + desc: test.desc.clone(), + }, + _ => panic!("non-static tests passed to test::test_main_static"), + } } /// Invoked when unit tests terminate. Should panic if the unit @@ -362,6 +461,141 @@ pub enum RunIgnored { Only, } +/// Structure denoting time limits for test execution. +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] +pub struct TimeThreshold { + pub warn: Duration, + pub critical: Duration, +} + +impl TimeThreshold { + /// Creates a new `TimeThreshold` instance with provided durations. + pub fn new(warn: Duration, critical: Duration) -> Self { + Self { + warn, + critical, + } + } + + /// Attempts to create a `TimeThreshold` instance with values obtained + /// from the environment variable, and returns `None` if the variable + /// is not set. + /// Environment variable format is expected to match `\d+,\d+`. + /// + /// # Panics + /// + /// Panics if variable with provided name is set but contains inappropriate + /// value. + pub fn from_env_var(env_var_name: &str) -> Option { + let durations_str = env::var(env_var_name).ok()?; + + // Split string into 2 substrings by comma and try to parse numbers. + let mut durations = durations_str + .splitn(2, ',') + .map(|v| { + u64::from_str(v).unwrap_or_else(|_| { + panic!( + "Duration value in variable {} is expected to be a number, but got {}", + env_var_name, v + ) + }) + }); + + // Callback to be called if the environment variable has unexpected structure. + let panic_on_incorrect_value = || { + panic!( + "Duration variable {} expected to have 2 numbers separated by comma, but got {}", + env_var_name, durations_str + ); + }; + + let (warn, critical) = ( + durations.next().unwrap_or_else(panic_on_incorrect_value), + durations.next().unwrap_or_else(panic_on_incorrect_value) + ); + + if warn > critical { + panic!("Test execution warn time should be less or equal to the critical time"); + } + + Some(Self::new(Duration::from_millis(warn), Duration::from_millis(critical))) + } +} + +/// Structure with parameters for calculating test execution time. +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] +pub struct TestTimeOptions { + /// Denotes if the test critical execution time limit excess should be considered + /// a test failure. + pub error_on_excess: bool, + pub colored: bool, + pub unit_threshold: TimeThreshold, + pub integration_threshold: TimeThreshold, + pub doctest_threshold: TimeThreshold, +} + +impl TestTimeOptions { + pub fn new_from_env(error_on_excess: bool, colored: bool) -> Self { + let unit_threshold = + TimeThreshold::from_env_var(time_constants::UNIT_ENV_NAME) + .unwrap_or_else(Self::default_unit); + + let integration_threshold = + TimeThreshold::from_env_var(time_constants::INTEGRATION_ENV_NAME) + .unwrap_or_else(Self::default_integration); + + let doctest_threshold = + TimeThreshold::from_env_var(time_constants::DOCTEST_ENV_NAME) + .unwrap_or_else(Self::default_doctest); + + Self { + error_on_excess, + colored, + unit_threshold, + integration_threshold, + doctest_threshold, + } + } + + pub fn is_warn(&self, test: &TestDesc, exec_time: &TestExecTime) -> bool { + exec_time.0 >= self.warn_time(test) + } + + pub fn is_critical(&self, test: &TestDesc, exec_time: &TestExecTime) -> bool { + exec_time.0 >= self.critical_time(test) + } + + fn warn_time(&self, test: &TestDesc) -> Duration { + match test.test_type { + TestType::UnitTest => self.unit_threshold.warn, + TestType::IntegrationTest => self.integration_threshold.warn, + TestType::DocTest => self.doctest_threshold.warn, + TestType::Unknown => time_constants::UNKNOWN_WARN, + } + } + + fn critical_time(&self, test: &TestDesc) -> Duration { + match test.test_type { + TestType::UnitTest => self.unit_threshold.critical, + TestType::IntegrationTest => self.integration_threshold.critical, + TestType::DocTest => self.doctest_threshold.critical, + TestType::Unknown => time_constants::UNKNOWN_CRITICAL, + } + } + + fn default_unit() -> TimeThreshold { + TimeThreshold::new(time_constants::UNIT_WARN, time_constants::UNIT_CRITICAL) + } + + fn default_integration() -> TimeThreshold { + TimeThreshold::new(time_constants::INTEGRATION_WARN, time_constants::INTEGRATION_CRITICAL) + } + + fn default_doctest() -> TimeThreshold { + TimeThreshold::new(time_constants::DOCTEST_WARN, time_constants::DOCTEST_CRITICAL) + } +} + #[derive(Debug)] pub struct TestOpts { pub list: bool, @@ -377,11 +611,14 @@ pub struct TestOpts { pub format: OutputFormat, pub test_threads: Option, pub skip: Vec, + pub time_options: Option, pub options: Options, } /// Result of parsing the options. pub type OptRes = Result; +/// Result of parsing the option part. +type OptPartRes = Result, String>; fn optgroups() -> getopts::Options { let mut opts = getopts::Options::new(); @@ -448,12 +685,47 @@ fn optgroups() -> getopts::Options { json = Output a json document", "pretty|terse|json", ) + .optflag( + "", + "show-output", + "Show captured stdout of successful tests" + ) .optopt( "Z", "", "Enable nightly-only flags: unstable-options = Allow use of experimental features", "unstable-options", + ) + .optflagopt( + "", + "report-time", + "Show execution time of each test. Awailable values: + plain = do not colorize the execution time (default); + colored = colorize output according to the `color` parameter value; + + Threshold values for colorized output can be configured via + `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and + `RUST_TEST_TIME_DOCTEST` environment variables. + + Expected format of environment variable is `VARIABLE=WARN_TIME,CRITICAL_TIME`. + + Not available for --format=terse", + "plain|colored" + ) + .optflag( + "", + "ensure-time", + "Treat excess of the test execution time limit as error. + + Threshold values for this option can be configured via + `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and + `RUST_TEST_TIME_DOCTEST` environment variables. + + Expected format of environment variable is `VARIABLE=WARN_TIME,CRITICAL_TIME`. + + `CRITICAL_TIME` here means the limit that should not be exceeded by test. + " ); return opts; } @@ -502,6 +774,45 @@ fn is_nightly() -> bool { bootstrap || !disable_unstable_features } +// Gets the option value and checks if unstable features are enabled. +macro_rules! unstable_optflag { + ($matches:ident, $allow_unstable:ident, $option_name:literal) => {{ + let opt = $matches.opt_present($option_name); + if !$allow_unstable && opt { + return Some(Err(format!( + "The \"{}\" flag is only accepted on the nightly compiler", + $option_name + ))); + } + + opt + }}; +} + +// Gets the CLI options assotiated with `report-time` feature. +fn get_time_options( + matches: &getopts::Matches, + allow_unstable: bool) +-> Option> { + let report_time = unstable_optflag!(matches, allow_unstable, "report-time"); + let colored_opt_str = matches.opt_str("report-time"); + let mut report_time_colored = report_time && colored_opt_str == Some("colored".into()); + let ensure_test_time = unstable_optflag!(matches, allow_unstable, "ensure-time"); + + // If `ensure-test-time` option is provided, time output is enforced, + // so user won't be confused if any of tests will silently fail. + let options = if report_time || ensure_test_time { + if ensure_test_time && !report_time { + report_time_colored = true; + } + Some(TestTimeOptions::new_from_env(ensure_test_time, report_time_colored)) + } else { + None + }; + + Some(Ok(options)) +} + // Parses command line arguments into test options pub fn parse_opts(args: &[String]) -> Option { let mut allow_unstable = false; @@ -540,19 +851,9 @@ pub fn parse_opts(args: &[String]) -> Option { None }; - let exclude_should_panic = matches.opt_present("exclude-should-panic"); - if !allow_unstable && exclude_should_panic { - return Some(Err( - "The \"exclude-should-panic\" flag is only accepted on the nightly compiler".into(), - )); - } + let exclude_should_panic = unstable_optflag!(matches, allow_unstable, "exclude-should-panic"); - let include_ignored = matches.opt_present("include-ignored"); - if !allow_unstable && include_ignored { - return Some(Err( - "The \"include-ignored\" flag is only accepted on the nightly compiler".into(), - )); - } + let include_ignored = unstable_optflag!(matches, allow_unstable, "include-ignored"); let run_ignored = match (include_ignored, matches.opt_present("ignored")) { (true, true) => { @@ -582,6 +883,12 @@ pub fn parse_opts(args: &[String]) -> Option { }; } + let time_options = match get_time_options(&matches, allow_unstable) { + Some(Ok(val)) => val, + Some(Err(e)) => return Some(Err(e)), + None => panic!("Unexpected output from `get_time_options`"), + }; + let test_threads = match matches.opt_str("test-threads") { Some(n_str) => match n_str.parse::() { Ok(0) => return Some(Err("argument for --test-threads must not be 0".to_string())), @@ -647,19 +954,20 @@ pub fn parse_opts(args: &[String]) -> Option { format, test_threads, skip: matches.opt_strs("skip"), - options: Options::new(), + time_options, + options: Options::new().display_output(matches.opt_present("show-output")), }; Some(Ok(test_opts)) } -#[derive(Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct BenchSamples { ns_iter_summ: stats::Summary, mb_s: usize, } -#[derive(Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub enum TestResult { TrOk, TrFailed, @@ -667,10 +975,21 @@ pub enum TestResult { TrIgnored, TrAllowedFail, TrBench(BenchSamples), + TrTimedFail, } unsafe impl Send for TestResult {} +/// The meassured execution time of a unit test. +#[derive(Clone, PartialEq)] +pub struct TestExecTime(Duration); + +impl fmt::Display for TestExecTime { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:.3}s", self.0.as_secs_f64()) + } +} + enum OutputLocation { Pretty(Box), Raw(T), @@ -704,6 +1023,7 @@ struct ConsoleTestState { metrics: MetricMap, failures: Vec<(TestDesc, Vec)>, not_failures: Vec<(TestDesc, Vec)>, + time_failures: Vec<(TestDesc, Vec)>, options: Options, } @@ -726,21 +1046,35 @@ impl ConsoleTestState { metrics: MetricMap::new(), failures: Vec::new(), not_failures: Vec::new(), + time_failures: Vec::new(), options: opts.options, }) } - pub fn write_log>(&mut self, msg: S) -> io::Result<()> { - let msg = msg.as_ref(); + pub fn write_log( + &mut self, + msg: F, + ) -> io::Result<()> + where + S: AsRef, + F: FnOnce() -> S, + { match self.log_out { None => Ok(()), - Some(ref mut o) => o.write_all(msg.as_bytes()), + Some(ref mut o) => { + let msg = msg(); + let msg = msg.as_ref(); + o.write_all(msg.as_bytes()) + }, } } - pub fn write_log_result(&mut self, test: &TestDesc, result: &TestResult) -> io::Result<()> { - self.write_log(format!( - "{} {}\n", + pub fn write_log_result(&mut self,test: &TestDesc, + result: &TestResult, + exec_time: Option<&TestExecTime>, + ) -> io::Result<()> { + self.write_log(|| format!( + "{} {}", match *result { TrOk => "ok".to_owned(), TrFailed => "failed".to_owned(), @@ -748,9 +1082,14 @@ impl ConsoleTestState { TrIgnored => "ignored".to_owned(), TrAllowedFail => "failed (allowed)".to_owned(), TrBench(ref bs) => fmt_bench_samples(bs), + TrTimedFail => "failed (time limit exceeded)".to_owned(), }, - test.name - )) + test.name, + ))?; + if let Some(exec_time) = exec_time { + self.write_log(|| format!(" <{}>", exec_time))?; + } + self.write_log(|| "\n") } fn current_test_count(&self) -> usize { @@ -837,7 +1176,7 @@ pub fn list_tests_console(opts: &TestOpts, tests: Vec) -> io::Res }; writeln!(output, "{}: {}", name, fntype)?; - st.write_log(format!("{} {}\n", fntype, name))?; + st.write_log(|| format!("{} {}\n", fntype, name))?; } fn plural(count: u32, s: &str) -> String { @@ -878,9 +1217,9 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec) -> io::Resu TeFilteredOut(filtered_out) => Ok(st.filtered_out = filtered_out), TeWait(ref test) => out.write_test_start(test), TeTimeout(ref test) => out.write_timeout(test), - TeResult(test, result, stdout) => { - st.write_log_result(&test, &result)?; - out.write_result(&test, &result, &*stdout)?; + TeResult(test, result, exec_time, stdout) => { + st.write_log_result(&test, &result, exec_time.as_ref())?; + out.write_result(&test, &result, exec_time.as_ref(), &*stdout, &st)?; match result { TrOk => { st.passed += 1; @@ -906,6 +1245,10 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec) -> io::Resu stdout.extend_from_slice(format!("note: {}", msg).as_bytes()); st.failures.push((test, stdout)); } + TrTimedFail => { + st.failed += 1; + st.time_failures.push((test, stdout)); + } } Ok(()) } @@ -931,6 +1274,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec) -> io::Resu use_color(opts), max_name_len, is_multithreaded, + opts.time_options, )), OutputFormat::Terse => Box::new(TerseFormatter::new( output, @@ -965,12 +1309,11 @@ fn use_color(opts: &TestOpts) -> bool { #[cfg(any( target_os = "cloudabi", - target_os = "redox", all(target_arch = "wasm32", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx") ))] fn stdout_isatty() -> bool { - // FIXME: Implement isatty on Redox and SGX + // FIXME: Implement isatty on SGX false } #[cfg(unix)] @@ -999,12 +1342,12 @@ fn stdout_isatty() -> bool { pub enum TestEvent { TeFiltered(Vec), TeWait(TestDesc), - TeResult(TestDesc, TestResult, Vec), + TeResult(TestDesc, TestResult, Option, Vec), TeTimeout(TestDesc), TeFilteredOut(usize), } -pub type MonitorMsg = (TestDesc, TestResult, Vec); +pub type MonitorMsg = (TestDesc, TestResult, Option, Vec); struct Sink(Arc>>); impl Write for Sink { @@ -1016,6 +1359,18 @@ impl Write for Sink { } } +#[derive(Clone, Copy)] +pub enum RunStrategy { + /// Runs the test in the current process, and sends the result back over the + /// supplied channel. + InProcess, + + /// Spawns a subprocess to run the test, and sends the result back over the + /// supplied channel. Requires `argv[0]` to exist and point to the binary + /// that's currently running. + SpawnPrimary, +} + pub fn run_tests(opts: &TestOpts, tests: Vec, mut callback: F) -> io::Result<()> where F: FnMut(TestEvent) -> io::Result<()>, @@ -1063,6 +1418,11 @@ where let mut pending = 0; let (tx, rx) = channel::(); + let run_strategy = if opts.options.panic_abort { + RunStrategy::SpawnPrimary + } else { + RunStrategy::InProcess + }; let mut running_tests: TestMap = HashMap::default(); @@ -1099,9 +1459,9 @@ where while !remaining.is_empty() { let test = remaining.pop().unwrap(); callback(TeWait(test.desc.clone()))?; - run_test(opts, !opts.run_tests, test, tx.clone(), Concurrent::No); - let (test, result, stdout) = rx.recv().unwrap(); - callback(TeResult(test, result, stdout))?; + run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::No); + let (test, result, exec_time, stdout) = rx.recv().unwrap(); + callback(TeResult(test, result, exec_time, stdout))?; } } else { while pending > 0 || !remaining.is_empty() { @@ -1110,7 +1470,7 @@ where let timeout = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S); running_tests.insert(test.desc.clone(), timeout); callback(TeWait(test.desc.clone()))?; //here no pad - run_test(opts, !opts.run_tests, test, tx.clone(), Concurrent::Yes); + run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::Yes); pending += 1; } @@ -1130,10 +1490,10 @@ where } } - let (desc, result, stdout) = res.unwrap(); + let (desc, result, exec_time, stdout) = res.unwrap(); running_tests.remove(&desc); - callback(TeResult(desc, result, stdout))?; + callback(TeResult(desc, result, exec_time, stdout))?; pending -= 1; } } @@ -1142,9 +1502,9 @@ where // All benchmarks run at the end, in serial. for b in filtered_benchs { callback(TeWait(b.desc.clone()))?; - run_test(opts, false, b, tx.clone(), Concurrent::No); - let (test, result, stdout) = rx.recv().unwrap(); - callback(TeResult(test, result, stdout))?; + run_test(opts, false, b, run_strategy, tx.clone(), Concurrent::No); + let (test, result, exec_time, stdout) = rx.recv().unwrap(); + callback(TeResult(test, result, exec_time, stdout))?; } } Ok(()) @@ -1193,15 +1553,15 @@ fn get_concurrency() -> usize { } } - #[cfg(target_os = "redox")] + #[cfg(target_os = "vxworks")] fn num_cpus() -> usize { - // FIXME: Implement num_cpus on Redox + // FIXME: Implement num_cpus on vxWorks 1 } - #[cfg(target_os = "vxworks")] + #[cfg(target_os = "redox")] fn num_cpus() -> usize { - // FIXME: Implement num_cpus on vxWorks + // FIXME: Implement num_cpus on Redox 1 } @@ -1221,7 +1581,7 @@ fn get_concurrency() -> usize { target_os = "ios", target_os = "linux", target_os = "macos", - target_os = "solaris" + target_os = "solaris", ))] fn num_cpus() -> usize { unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize } @@ -1369,54 +1729,51 @@ pub fn run_test( opts: &TestOpts, force_ignore: bool, test: TestDescAndFn, + strategy: RunStrategy, monitor_ch: Sender, concurrency: Concurrent, ) { let TestDescAndFn { desc, testfn } = test; - let ignore_because_panic_abort = cfg!(target_arch = "wasm32") + let ignore_because_no_process_support = cfg!(target_arch = "wasm32") && !cfg!(target_os = "emscripten") && desc.should_panic != ShouldPanic::No; - if force_ignore || desc.ignore || ignore_because_panic_abort { - monitor_ch.send((desc, TrIgnored, Vec::new())).unwrap(); + if force_ignore || desc.ignore || ignore_because_no_process_support { + monitor_ch.send((desc, TrIgnored, None, Vec::new())).unwrap(); return; } + struct TestRunOpts { + pub strategy: RunStrategy, + pub nocapture: bool, + pub concurrency: Concurrent, + pub time: Option, + } + fn run_test_inner( desc: TestDesc, monitor_ch: Sender, - nocapture: bool, testfn: Box, - concurrency: Concurrent, + opts: TestRunOpts, ) { - // Buffer for capturing standard I/O - let data = Arc::new(Mutex::new(Vec::new())); - let data2 = data.clone(); - + let concurrency = opts.concurrency; let name = desc.name.clone(); - let runtest = move || { - let oldio = if !nocapture { - Some(( - io::set_print(Some(Box::new(Sink(data2.clone())))), - io::set_panic(Some(Box::new(Sink(data2)))), - )) - } else { - None - }; - - let result = catch_unwind(AssertUnwindSafe(testfn)); - - if let Some((printio, panicio)) = oldio { - io::set_print(printio); - io::set_panic(panicio); - }; - let test_result = calc_result(&desc, result); - let stdout = data.lock().unwrap().to_vec(); - monitor_ch - .send((desc.clone(), test_result, stdout)) - .unwrap(); + let runtest = move || { + match opts.strategy { + RunStrategy::InProcess => + run_test_in_process( + desc, + opts.nocapture, + opts.time.is_some(), + testfn, + monitor_ch, + opts.time + ), + RunStrategy::SpawnPrimary => + spawn_test_subprocess(desc, opts.time.is_some(), monitor_ch, opts.time), + } }; // If the platform is single-threaded we're just going to run @@ -1431,27 +1788,43 @@ pub fn run_test( } } + let test_run_opts = TestRunOpts { + strategy, + nocapture: opts.nocapture, + concurrency, + time: opts.time_options + }; + match testfn { DynBenchFn(bencher) => { + // Benchmarks aren't expected to panic, so we run them all in-process. crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| { bencher.run(harness) }); } StaticBenchFn(benchfn) => { + // Benchmarks aren't expected to panic, so we run them all in-process. crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| { (benchfn.clone())(harness) }); } DynTestFn(f) => { - let cb = move || __rust_begin_short_backtrace(f); - run_test_inner(desc, monitor_ch, opts.nocapture, Box::new(cb), concurrency) + match strategy { + RunStrategy::InProcess => (), + _ => panic!("Cannot run dynamic test fn out-of-process"), + }; + run_test_inner( + desc, + monitor_ch, + Box::new(move || __rust_begin_short_backtrace(f)), + test_run_opts, + ); } StaticTestFn(f) => run_test_inner( desc, monitor_ch, - opts.nocapture, Box::new(move || __rust_begin_short_backtrace(f)), - concurrency, + test_run_opts, ), } } @@ -1462,8 +1835,13 @@ fn __rust_begin_short_backtrace(f: F) { f() } -fn calc_result(desc: &TestDesc, task_result: Result<(), Box>) -> TestResult { - match (&desc.should_panic, task_result) { +fn calc_result<'a>( + desc: &TestDesc, + task_result: Result<(), &'a (dyn Any + 'static + Send)>, + time_opts: &Option, + exec_time: &Option +) -> TestResult { + let result = match (&desc.should_panic, task_result) { (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TrOk, (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => { if err @@ -1482,8 +1860,197 @@ fn calc_result(desc: &TestDesc, task_result: Result<(), Box>) -> } } } + (&ShouldPanic::Yes, Ok(())) => TrFailedMsg("test did not panic as expected".to_string()), _ if desc.allow_fail => TrAllowedFail, _ => TrFailed, + }; + + // If test is already failed (or allowed to fail), do not change the result. + if result != TrOk { + return result; + } + + // Check if test is failed due to timeout. + if let (Some(opts), Some(time)) = (time_opts, exec_time) { + if opts.error_on_excess && opts.is_critical(desc, time) { + return TrTimedFail; + } + } + + result +} + +fn get_result_from_exit_code( + desc: &TestDesc, + code: i32, + time_opts: &Option, + exec_time: &Option, +) -> TestResult { + let result = match (desc.allow_fail, code) { + (_, TR_OK) => TrOk, + (true, TR_FAILED) => TrAllowedFail, + (false, TR_FAILED) => TrFailed, + (_, _) => TrFailedMsg(format!("got unexpected return code {}", code)), + }; + + // If test is already failed (or allowed to fail), do not change the result. + if result != TrOk { + return result; + } + + // Check if test is failed due to timeout. + if let (Some(opts), Some(time)) = (time_opts, exec_time) { + if opts.error_on_excess && opts.is_critical(desc, time) { + return TrTimedFail; + } + } + + result +} + +fn run_test_in_process( + desc: TestDesc, + nocapture: bool, + report_time: bool, + testfn: Box, + monitor_ch: Sender, + time_opts: Option, +) { + // Buffer for capturing standard I/O + let data = Arc::new(Mutex::new(Vec::new())); + + let oldio = if !nocapture { + Some(( + io::set_print(Some(Box::new(Sink(data.clone())))), + io::set_panic(Some(Box::new(Sink(data.clone())))), + )) + } else { + None + }; + + let start = if report_time { + Some(Instant::now()) + } else { + None + }; + let result = catch_unwind(AssertUnwindSafe(testfn)); + let exec_time = start.map(|start| { + let duration = start.elapsed(); + TestExecTime(duration) + }); + + if let Some((printio, panicio)) = oldio { + io::set_print(printio); + io::set_panic(panicio); + } + + let test_result = match result { + Ok(()) => calc_result(&desc, Ok(()), &time_opts, &exec_time), + Err(e) => calc_result(&desc, Err(e.as_ref()), &time_opts, &exec_time), + }; + let stdout = data.lock().unwrap().to_vec(); + monitor_ch.send((desc.clone(), test_result, exec_time, stdout)).unwrap(); +} + +fn spawn_test_subprocess( + desc: TestDesc, + report_time: bool, + monitor_ch: Sender, + time_opts: Option, +) { + let (result, test_output, exec_time) = (|| { + let args = env::args().collect::>(); + let current_exe = &args[0]; + + let start = if report_time { + Some(Instant::now()) + } else { + None + }; + let output = match Command::new(current_exe) + .env(SECONDARY_TEST_INVOKER_VAR, desc.name.as_slice()) + .output() { + Ok(out) => out, + Err(e) => { + let err = format!("Failed to spawn {} as child for test: {:?}", args[0], e); + return (TrFailed, err.into_bytes(), None); + } + }; + let exec_time = start.map(|start| { + let duration = start.elapsed(); + TestExecTime(duration) + }); + + let std::process::Output { stdout, stderr, status } = output; + let mut test_output = stdout; + formatters::write_stderr_delimiter(&mut test_output, &desc.name); + test_output.extend_from_slice(&stderr); + + let result = match (|| -> Result { + let exit_code = get_exit_code(status)?; + Ok(get_result_from_exit_code(&desc, exit_code, &time_opts, &exec_time)) + })() { + Ok(r) => r, + Err(e) => { + write!(&mut test_output, "Unexpected error: {}", e).unwrap(); + TrFailed + } + }; + + (result, test_output, exec_time) + })(); + + monitor_ch.send((desc.clone(), result, exec_time, test_output)).unwrap(); +} + +fn run_test_in_spawned_subprocess( + desc: TestDesc, + testfn: Box, +) -> ! { + let builtin_panic_hook = panic::take_hook(); + let record_result = Arc::new(move |panic_info: Option<&'_ PanicInfo<'_>>| { + let test_result = match panic_info { + Some(info) => calc_result(&desc, Err(info.payload()), &None, &None), + None => calc_result(&desc, Ok(()), &None, &None), + }; + + // We don't support serializing TrFailedMsg, so just + // print the message out to stderr. + if let TrFailedMsg(msg) = &test_result { + eprintln!("{}", msg); + } + + if let Some(info) = panic_info { + builtin_panic_hook(info); + } + + if let TrOk = test_result { + process::exit(TR_OK); + } else { + process::exit(TR_FAILED); + } + }); + let record_result2 = record_result.clone(); + panic::set_hook(Box::new(move |info| record_result2(Some(&info)))); + testfn(); + record_result(None); + unreachable!("panic=abort callback should have exited the process") +} + +#[cfg(not(unix))] +fn get_exit_code(status: ExitStatus) -> Result { + status.code().ok_or("received no exit code from child process".into()) +} + +#[cfg(unix)] +fn get_exit_code(status: ExitStatus) -> Result { + use std::os::unix::process::ExitStatusExt; + match status.code() { + Some(code) => Ok(code), + None => match status.signal() { + Some(signal) => Err(format!("child process exited with signal {}", signal)), + None => Err("child process exited with unknown signal".into()), + } } } @@ -1635,7 +2202,9 @@ where } pub mod bench { - use super::{BenchMode, BenchSamples, Bencher, MonitorMsg, Sender, Sink, TestDesc, TestResult}; + use super::{ + BenchMode, BenchSamples, Bencher, MonitorMsg, Sender, Sink, TestDesc, TestResult + }; use crate::stats; use std::cmp; use std::io; @@ -1653,12 +2222,10 @@ pub mod bench { }; let data = Arc::new(Mutex::new(Vec::new())); - let data2 = data.clone(); - let oldio = if !nocapture { Some(( - io::set_print(Some(Box::new(Sink(data2.clone())))), - io::set_panic(Some(Box::new(Sink(data2)))), + io::set_print(Some(Box::new(Sink(data.clone())))), + io::set_panic(Some(Box::new(Sink(data.clone())))), )) } else { None @@ -1669,7 +2236,7 @@ pub mod bench { if let Some((printio, panicio)) = oldio { io::set_print(printio); io::set_panic(panicio); - }; + } let test_result = match result { //bs.bench(f) { @@ -1697,7 +2264,7 @@ pub mod bench { }; let stdout = data.lock().unwrap().to_vec(); - monitor_ch.send((desc, test_result, stdout)).unwrap(); + monitor_ch.send((desc, test_result, None, stdout)).unwrap(); } pub fn run_once(f: F) diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index 6577ec8ad2391..aab8d012fdf68 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -115,7 +115,7 @@ pub trait Stats { } /// Extracted collection of all the summary statistics of a sample set. -#[derive(Clone, PartialEq, Copy)] +#[derive(Debug, Clone, PartialEq, Copy)] #[allow(missing_docs)] pub struct Summary { pub sum: f64, diff --git a/src/libtest/tests.rs b/src/libtest/tests.rs index f574743e4b669..880d02a28ff06 100644 --- a/src/libtest/tests.rs +++ b/src/libtest/tests.rs @@ -1,11 +1,12 @@ use super::*; use crate::test::{ - filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, RunIgnored, - ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TrFailed, TrFailedMsg, - TrIgnored, TrOk, + filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, RunIgnored, RunStrategy, + ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TestTimeOptions, + TestType, TrFailedMsg, TrIgnored, TrOk, }; use std::sync::mpsc::channel; +use std::time::Duration; impl TestOpts { fn new() -> TestOpts { @@ -23,6 +24,7 @@ impl TestOpts { format: OutputFormat::Pretty, test_threads: None, skip: vec![], + time_options: None, options: Options::new(), } } @@ -36,6 +38,7 @@ fn one_ignored_one_unignored_test() -> Vec { ignore: true, should_panic: ShouldPanic::No, allow_fail: false, + test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(move || {})), }, @@ -45,6 +48,7 @@ fn one_ignored_one_unignored_test() -> Vec { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, + test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(move || {})), }, @@ -62,12 +66,13 @@ pub fn do_not_run_ignored_tests() { ignore: true, should_panic: ShouldPanic::No, allow_fail: false, + test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); - run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); - let (_, res, _) = rx.recv().unwrap(); + run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); + let (_, res, _, _) = rx.recv().unwrap(); assert!(res != TrOk); } @@ -80,12 +85,13 @@ pub fn ignored_tests_result_in_ignored() { ignore: true, should_panic: ShouldPanic::No, allow_fail: false, + test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); - run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); - let (_, res, _) = rx.recv().unwrap(); + run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); + let (_, res, _, _) = rx.recv().unwrap(); assert!(res == TrIgnored); } @@ -100,12 +106,13 @@ fn test_should_panic() { ignore: false, should_panic: ShouldPanic::Yes, allow_fail: false, + test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); - run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); - let (_, res, _) = rx.recv().unwrap(); + run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); + let (_, res, _, _) = rx.recv().unwrap(); assert!(res == TrOk); } @@ -120,12 +127,13 @@ fn test_should_panic_good_message() { ignore: false, should_panic: ShouldPanic::YesWithMessage("error message"), allow_fail: false, + test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); - run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); - let (_, res, _) = rx.recv().unwrap(); + run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); + let (_, res, _, _) = rx.recv().unwrap(); assert!(res == TrOk); } @@ -142,12 +150,13 @@ fn test_should_panic_bad_message() { ignore: false, should_panic: ShouldPanic::YesWithMessage(expected), allow_fail: false, + test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); - run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); - let (_, res, _) = rx.recv().unwrap(); + run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); + let (_, res, _, _) = rx.recv().unwrap(); assert!(res == TrFailedMsg(format!("{} '{}'", failed_msg, expected))); } @@ -160,13 +169,145 @@ fn test_should_panic_but_succeeds() { ignore: false, should_panic: ShouldPanic::Yes, allow_fail: false, + test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(f)), }; let (tx, rx) = channel(); - run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); - let (_, res, _) = rx.recv().unwrap(); - assert!(res == TrFailed); + run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); + let (_, res, _, _) = rx.recv().unwrap(); + assert!(res == TrFailedMsg("test did not panic as expected".to_string())); +} + +fn report_time_test_template(report_time: bool) -> Option { + fn f() {} + let desc = TestDescAndFn { + desc: TestDesc { + name: StaticTestName("whatever"), + ignore: false, + should_panic: ShouldPanic::No, + allow_fail: false, + test_type: TestType::Unknown, + }, + testfn: DynTestFn(Box::new(f)), + }; + let time_options = if report_time { + Some(TestTimeOptions::default()) + } else { + None + }; + + let test_opts = TestOpts { + time_options, + ..TestOpts::new() + }; + let (tx, rx) = channel(); + run_test(&test_opts, false, desc, RunStrategy::InProcess, tx, Concurrent::No); + let (_, _, exec_time, _) = rx.recv().unwrap(); + exec_time +} + +#[test] +fn test_should_not_report_time() { + let exec_time = report_time_test_template(false); + assert!(exec_time.is_none()); +} + +#[test] +fn test_should_report_time() { + let exec_time = report_time_test_template(true); + assert!(exec_time.is_some()); +} + +fn time_test_failure_template(test_type: TestType) -> TestResult { + fn f() {} + let desc = TestDescAndFn { + desc: TestDesc { + name: StaticTestName("whatever"), + ignore: false, + should_panic: ShouldPanic::No, + allow_fail: false, + test_type + }, + testfn: DynTestFn(Box::new(f)), + }; + // `Default` will initialize all the thresholds to 0 milliseconds. + let mut time_options = TestTimeOptions::default(); + time_options.error_on_excess = true; + + let test_opts = TestOpts { + time_options: Some(time_options), + ..TestOpts::new() + }; + let (tx, rx) = channel(); + run_test(&test_opts, false, desc, RunStrategy::InProcess, tx, Concurrent::No); + let (_, result, _, _) = rx.recv().unwrap(); + + result +} + +#[test] +fn test_error_on_exceed() { + let types = [TestType::UnitTest, TestType::IntegrationTest, TestType::DocTest]; + + for test_type in types.into_iter() { + let result = time_test_failure_template(*test_type); + + assert_eq!(result, TestResult::TrTimedFail); + } + + // Check that for unknown tests thresholds aren't applied. + let result = time_test_failure_template(TestType::Unknown); + assert_eq!(result, TestResult::TrOk); +} + +fn typed_test_desc(test_type: TestType) -> TestDesc { + TestDesc { + name: StaticTestName("whatever"), + ignore: false, + should_panic: ShouldPanic::No, + allow_fail: false, + test_type + } +} + +fn test_exec_time(millis: u64) -> TestExecTime { + TestExecTime(Duration::from_millis(millis)) +} + +#[test] +fn test_time_options_threshold() { + let unit = TimeThreshold::new(Duration::from_millis(50), Duration::from_millis(100)); + let integration = TimeThreshold::new(Duration::from_millis(500), Duration::from_millis(1000)); + let doc = TimeThreshold::new(Duration::from_millis(5000), Duration::from_millis(10000)); + + let options = TestTimeOptions { + error_on_excess: false, + colored: false, + unit_threshold: unit.clone(), + integration_threshold: integration.clone(), + doctest_threshold: doc.clone(), + }; + + let test_vector = [ + (TestType::UnitTest, unit.warn.as_millis() - 1, false, false), + (TestType::UnitTest, unit.warn.as_millis(), true, false), + (TestType::UnitTest, unit.critical.as_millis(), true, true), + (TestType::IntegrationTest, integration.warn.as_millis() - 1, false, false), + (TestType::IntegrationTest, integration.warn.as_millis(), true, false), + (TestType::IntegrationTest, integration.critical.as_millis(), true, true), + (TestType::DocTest, doc.warn.as_millis() - 1, false, false), + (TestType::DocTest, doc.warn.as_millis(), true, false), + (TestType::DocTest, doc.critical.as_millis(), true, true), + ]; + + for (test_type, time, expected_warn, expected_critical) in test_vector.into_iter() { + let test_desc = typed_test_desc(*test_type); + let exec_time = test_exec_time(*time as u64); + + assert_eq!(options.is_warn(&test_desc, &exec_time), *expected_warn); + assert_eq!(options.is_critical(&test_desc, &exec_time), *expected_critical); + } } #[test] @@ -180,6 +321,17 @@ fn parse_ignored_flag() { assert_eq!(opts.run_ignored, RunIgnored::Only); } +#[test] +fn parse_show_output_flag() { + let args = vec![ + "progname".to_string(), + "filter".to_string(), + "--show-output".to_string(), + ]; + let opts = parse_opts(&args).unwrap().unwrap(); + assert!(opts.options.display_output); +} + #[test] fn parse_include_ignored_flag() { let args = vec![ @@ -239,6 +391,7 @@ pub fn exclude_should_panic_option() { ignore: false, should_panic: ShouldPanic::Yes, allow_fail: false, + test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(move || {})), }); @@ -260,6 +413,7 @@ pub fn exact_filter_match() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, + test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(move || {})), }) @@ -371,6 +525,7 @@ pub fn sort_tests() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, + test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(testfn)), }; @@ -447,6 +602,7 @@ pub fn test_bench_no_iter() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, + test_type: TestType::Unknown, }; crate::bench::benchmark(desc, tx, true, f); @@ -466,6 +622,7 @@ pub fn test_bench_iter() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, + test_type: TestType::Unknown, }; crate::bench::benchmark(desc, tx, true, f); @@ -479,6 +636,7 @@ fn should_sort_failures_before_printing_them() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, + test_type: TestType::Unknown, }; let test_b = TestDesc { @@ -486,9 +644,10 @@ fn should_sort_failures_before_printing_them() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, + test_type: TestType::Unknown, }; - let mut out = PrettyFormatter::new(Raw(Vec::new()), false, 10, false); + let mut out = PrettyFormatter::new(Raw(Vec::new()), false, 10, false, None); let st = ConsoleTestState { log_out: None, @@ -503,6 +662,7 @@ fn should_sort_failures_before_printing_them() { failures: vec![(test_b, Vec::new()), (test_a, Vec::new())], options: Options::new(), not_failures: Vec::new(), + time_failures: Vec::new(), }; out.write_failures(&st).unwrap(); diff --git a/src/libunwind/Cargo.toml b/src/libunwind/Cargo.toml index f0f1bab425d7a..f10df8c85ba0a 100644 --- a/src/libunwind/Cargo.toml +++ b/src/libunwind/Cargo.toml @@ -22,7 +22,7 @@ compiler_builtins = "0.1.0" cfg-if = "0.1.8" [build-dependencies] -cc = { optional = true, version = "1.0.1" } +cc = { version = "1.0.1" } [features] -llvm-libunwind = ["cc"] +llvm-libunwind = [] diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index da31a49ddf21f..f24d957d67b75 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -4,17 +4,15 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); let target = env::var("TARGET").expect("TARGET was not set"); - // FIXME: the not(bootstrap) part is needed because of the issue addressed by #62286, - // and could be removed once that change is in beta. - if cfg!(all(not(bootstrap), feature = "llvm-libunwind")) && - (target.contains("linux") || + if cfg!(feature = "llvm-libunwind") && + ((target.contains("linux") && !target.contains("musl")) || target.contains("fuchsia")) { // Build the unwinding from libunwind C/C++ source code. - #[cfg(all(not(bootstrap), feature = "llvm-libunwind"))] llvm_libunwind::compile(); } else if target.contains("linux") { if target.contains("musl") { - // musl is handled in lib.rs + // linking for musl is handled in lib.rs + llvm_libunwind::compile(); } else if !target.contains("android") { println!("cargo:rustc-link-lib=gcc_s"); } @@ -25,7 +23,11 @@ fn main() { } else if target.contains("netbsd") { println!("cargo:rustc-link-lib=gcc_s"); } else if target.contains("openbsd") { - println!("cargo:rustc-link-lib=c++abi"); + if target.contains("sparc64") { + println!("cargo:rustc-link-lib=gcc"); + } else { + println!("cargo:rustc-link-lib=c++abi"); + } } else if target.contains("solaris") { println!("cargo:rustc-link-lib=gcc_s"); } else if target.contains("dragonfly") { @@ -46,7 +48,6 @@ fn main() { } } -#[cfg(all(not(bootstrap), feature = "llvm-libunwind"))] mod llvm_libunwind { use std::env; use std::path::Path; @@ -98,6 +99,15 @@ mod llvm_libunwind { cfg.file(root.join("src").join(src)); } + if target_env == "musl" { + // use the same C compiler command to compile C++ code so we do not need to setup the + // C++ compiler env variables on the builders + cfg.cpp(false); + // linking for musl is handled in lib.rs + cfg.cargo_metadata(false); + println!("cargo:rustc-link-search=native={}", env::var("OUT_DIR").unwrap()); + } + cfg.compile("unwind"); } } diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs index aacbfc547d472..7c9eaa51fd94e 100644 --- a/src/libunwind/libunwind.rs +++ b/src/libunwind/libunwind.rs @@ -70,7 +70,7 @@ pub enum _Unwind_Context {} pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception); -#[cfg_attr(all(not(bootstrap), feature = "llvm-libunwind", +#[cfg_attr(all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), link(name = "unwind", kind = "static"))] extern "C" { @@ -97,7 +97,7 @@ if #[cfg(all(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm } pub use _Unwind_Action::*; - #[cfg_attr(all(not(bootstrap), feature = "llvm-libunwind", + #[cfg_attr(all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), link(name = "unwind", kind = "static"))] extern "C" { @@ -153,7 +153,7 @@ if #[cfg(all(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm pub const UNWIND_POINTER_REG: c_int = 12; pub const UNWIND_IP_REG: c_int = 15; - #[cfg_attr(all(not(bootstrap), feature = "llvm-libunwind", + #[cfg_attr(all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), link(name = "unwind", kind = "static"))] extern "C" { @@ -218,7 +218,7 @@ if #[cfg(all(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm cfg_if::cfg_if! { if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { // Not 32-bit iOS - #[cfg_attr(all(not(bootstrap), feature = "llvm-libunwind", + #[cfg_attr(all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), link(name = "unwind", kind = "static"))] extern "C" { @@ -230,7 +230,7 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { } } else { // 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace() - #[cfg_attr(all(not(bootstrap), feature = "llvm-libunwind", + #[cfg_attr(all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), link(name = "unwind", kind = "static"))] extern "C" { diff --git a/src/llvm-project b/src/llvm-project index 9b64ca5b7e1e3..14a3b123074e0 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 9b64ca5b7e1e3583978f9ac8af6d93b220a13d90 +Subproject commit 14a3b123074e066d64a99886941473058e52197d diff --git a/src/stage0.txt b/src/stage0.txt index 14d65bef8f6dd..9509d3e99612f 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.x.0` for Cargo where they were released on `date`. -date: 2019-07-04 +date: 2019-09-25 rustc: beta cargo: beta @@ -25,7 +25,7 @@ cargo: beta # # This means that there's a small window of time (a few days) where artifacts # are downloaded from dev-static.rust-lang.org instead of static.rust-lang.org. -# In order to ease this transition we have an extra key which is in the +# In order to ease this transition we have an extra key which is in the # configuration file below. When uncommented this will instruct the bootstrap.py # script to download from dev-static.rust-lang.org. # diff --git a/src/stdarch b/src/stdarch index 4791ba85e7645..e0ab2c165ace0 160000 --- a/src/stdarch +++ b/src/stdarch @@ -1 +1 @@ -Subproject commit 4791ba85e7645c02146dd416288480943670d1ca +Subproject commit e0ab2c165ace03a61139b61f1d9b86b07028850f diff --git a/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs b/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs index d50a7910fe0b3..9050e8f1671d9 100644 --- a/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs +++ b/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs @@ -1,4 +1,5 @@ // compile-flags:-Zshare-generics=yes +// no-prefer-dynamic #![crate_type="rlib"] diff --git a/src/test/codegen-units/partitioning/shared-generics.rs b/src/test/codegen-units/partitioning/shared-generics.rs index 010412b8baeb3..58e485be00321 100644 --- a/src/test/codegen-units/partitioning/shared-generics.rs +++ b/src/test/codegen-units/partitioning/shared-generics.rs @@ -1,4 +1,5 @@ // ignore-tidy-linelength +// no-prefer-dynamic // compile-flags:-Zprint-mono-items=eager -Zshare-generics=yes -Zincremental=tmp/partitioning-tests/shared-generics-exe #![crate_type="rlib"] diff --git a/src/test/codegen/README.md b/src/test/codegen/README.md new file mode 100644 index 0000000000000..00de55eeab1f4 --- /dev/null +++ b/src/test/codegen/README.md @@ -0,0 +1,2 @@ +The files here use the LLVM FileCheck framework, documented at +. diff --git a/src/test/codegen/adjustments.rs b/src/test/codegen/adjustments.rs index ae2ff9994fdf0..ded310d0aebb1 100644 --- a/src/test/codegen/adjustments.rs +++ b/src/test/codegen/adjustments.rs @@ -3,7 +3,7 @@ #![crate_type = "lib"] // Hack to get the correct size for the length part in slices -// CHECK: @helper([[USIZE:i[0-9]+]] %arg0) +// CHECK: @helper([[USIZE:i[0-9]+]] %_1) #[no_mangle] pub fn helper(_: usize) { } diff --git a/src/test/codegen/c-variadic.rs b/src/test/codegen/c-variadic.rs index 13be5ced27fa9..2acf95de97ee8 100644 --- a/src/test/codegen/c-variadic.rs +++ b/src/test/codegen/c-variadic.rs @@ -1,7 +1,9 @@ // compile-flags: -C no-prepopulate-passes +// ignore-tidy-linelength #![crate_type = "lib"] #![feature(c_variadic)] +#![feature(unwind_attributes)] #![no_std] use core::ffi::VaList; @@ -10,36 +12,41 @@ extern "C" { fn foreign_c_variadic_1(_: VaList, ...); } +#[unwind(aborts)] // FIXME(#58794) pub unsafe extern "C" fn use_foreign_c_variadic_0() { // Ensure that we correctly call foreign C-variadic functions. - // CHECK: invoke void (i32, ...) @foreign_c_variadic_0(i32 0) + // CHECK: invoke void (i32, ...) @foreign_c_variadic_0([[PARAM:i32( signext)?]] 0) foreign_c_variadic_0(0); - // CHECK: invoke void (i32, ...) @foreign_c_variadic_0(i32 0, i32 42) + // CHECK: invoke void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42) foreign_c_variadic_0(0, 42i32); - // CHECK: invoke void (i32, ...) @foreign_c_variadic_0(i32 0, i32 42, i32 1024) + // CHECK: invoke void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024) foreign_c_variadic_0(0, 42i32, 1024i32); - // CHECK: invoke void (i32, ...) @foreign_c_variadic_0(i32 0, i32 42, i32 1024, i32 0) + // CHECK: invoke void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024, [[PARAM]] 0) foreign_c_variadic_0(0, 42i32, 1024i32, 0i32); } // Ensure that we do not remove the `va_list` passed to the foreign function when // removing the "spoofed" `VaListImpl` that is used by Rust defined C-variadics. +#[unwind(aborts)] // FIXME(#58794) pub unsafe extern "C" fn use_foreign_c_variadic_1_0(ap: VaList) { // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap) foreign_c_variadic_1(ap); } +#[unwind(aborts)] // FIXME(#58794) pub unsafe extern "C" fn use_foreign_c_variadic_1_1(ap: VaList) { - // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, i32 42) + // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 42) foreign_c_variadic_1(ap, 42i32); } +#[unwind(aborts)] // FIXME(#58794) pub unsafe extern "C" fn use_foreign_c_variadic_1_2(ap: VaList) { - // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, i32 2, i32 42) + // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42) foreign_c_variadic_1(ap, 2i32, 42i32); } +#[unwind(aborts)] // FIXME(#58794) pub unsafe extern "C" fn use_foreign_c_variadic_1_3(ap: VaList) { - // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, i32 2, i32 42, i32 0) + // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42, [[PARAM]] 0) foreign_c_variadic_1(ap, 2i32, 42i32, 0i32); } @@ -58,12 +65,12 @@ pub unsafe extern "C" fn c_variadic(n: i32, mut ap: ...) -> i32 { // Ensure that we generate the correct `call` signature when calling a Rust // defined C-variadic. pub unsafe fn test_c_variadic_call() { - // CHECK: call i32 (i32, ...) @c_variadic(i32 0) + // CHECK: call [[RET:(signext )?i32]] (i32, ...) @c_variadic([[PARAM]] 0) c_variadic(0); - // CHECK: call i32 (i32, ...) @c_variadic(i32 0, i32 42) + // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42) c_variadic(0, 42i32); - // CHECK: call i32 (i32, ...) @c_variadic(i32 0, i32 42, i32 1024) + // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024) c_variadic(0, 42i32, 1024i32); - // CHECK: call i32 (i32, ...) @c_variadic(i32 0, i32 42, i32 1024, i32 0) + // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024, [[PARAM]] 0) c_variadic(0, 42i32, 1024i32, 0i32); } diff --git a/src/test/codegen/fastcall-inreg.rs b/src/test/codegen/fastcall-inreg.rs index e152e6e9d1333..f67487c83ba23 100644 --- a/src/test/codegen/fastcall-inreg.rs +++ b/src/test/codegen/fastcall-inreg.rs @@ -49,27 +49,27 @@ #![crate_type = "lib"] pub mod tests { - // CHECK: @f1(i32 inreg %arg0, i32 inreg %arg1, i32 %arg2) + // CHECK: @f1(i32 inreg %_1, i32 inreg %_2, i32 %_3) #[no_mangle] pub extern "fastcall" fn f1(_: i32, _: i32, _: i32) {} - // CHECK: @f2(i32* inreg %arg0, i32* inreg %arg1, i32* %arg2) + // CHECK: @f2(i32* inreg %_1, i32* inreg %_2, i32* %_3) #[no_mangle] pub extern "fastcall" fn f2(_: *const i32, _: *const i32, _: *const i32) {} - // CHECK: @f3(float %arg0, i32 inreg %arg1, i32 inreg %arg2, i32 %arg3) + // CHECK: @f3(float %_1, i32 inreg %_2, i32 inreg %_3, i32 %_4) #[no_mangle] pub extern "fastcall" fn f3(_: f32, _: i32, _: i32, _: i32) {} - // CHECK: @f4(i32 inreg %arg0, float %arg1, i32 inreg %arg2, i32 %arg3) + // CHECK: @f4(i32 inreg %_1, float %_2, i32 inreg %_3, i32 %_4) #[no_mangle] pub extern "fastcall" fn f4(_: i32, _: f32, _: i32, _: i32) {} - // CHECK: @f5(i64 %arg0, i32 %arg1) + // CHECK: @f5(i64 %_1, i32 %_2) #[no_mangle] pub extern "fastcall" fn f5(_: i64, _: i32) {} - // CHECK: @f6(i1 inreg zeroext %arg0, i32 inreg %arg1, i32 %arg2) + // CHECK: @f6(i1 inreg zeroext %_1, i32 inreg %_2, i32 %_3) #[no_mangle] pub extern "fastcall" fn f6(_: bool, _: i32, _: i32) {} } diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index bd121ef24adae..7e1791cd4f296 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -18,48 +18,48 @@ pub fn boolean(x: bool) -> bool { x } -// CHECK: @readonly_borrow(i32* noalias readonly align 4 dereferenceable(4) %arg0) +// CHECK: @readonly_borrow(i32* noalias readonly align 4 dereferenceable(4) %_1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn readonly_borrow(_: &i32) { } -// CHECK: @static_borrow(i32* noalias readonly align 4 dereferenceable(4) %arg0) +// CHECK: @static_borrow(i32* noalias readonly align 4 dereferenceable(4) %_1) // static borrow may be captured #[no_mangle] pub fn static_borrow(_: &'static i32) { } -// CHECK: @named_borrow(i32* noalias readonly align 4 dereferenceable(4) %arg0) +// CHECK: @named_borrow(i32* noalias readonly align 4 dereferenceable(4) %_1) // borrow with named lifetime may be captured #[no_mangle] pub fn named_borrow<'r>(_: &'r i32) { } -// CHECK: @unsafe_borrow(i16* align 2 dereferenceable(2) %arg0) +// CHECK: @unsafe_borrow(i16* align 2 dereferenceable(2) %_1) // unsafe interior means this isn't actually readonly and there may be aliases ... #[no_mangle] pub fn unsafe_borrow(_: &UnsafeInner) { } -// CHECK: @mutable_unsafe_borrow(i16* align 2 dereferenceable(2) %arg0) +// CHECK: @mutable_unsafe_borrow(i16* align 2 dereferenceable(2) %_1) // ... unless this is a mutable borrow, those never alias #[no_mangle] pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) { } -// CHECK: @mutable_borrow(i32* align 4 dereferenceable(4) %arg0) +// CHECK: @mutable_borrow(i32* align 4 dereferenceable(4) %_1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn mutable_borrow(_: &mut i32) { } -// CHECK: @indirect_struct(%S* noalias nocapture dereferenceable(32) %arg0) +// CHECK: @indirect_struct(%S* noalias nocapture dereferenceable(32) %_1) #[no_mangle] pub fn indirect_struct(_: S) { } -// CHECK: @borrowed_struct(%S* noalias readonly align 4 dereferenceable(32) %arg0) +// CHECK: @borrowed_struct(%S* noalias readonly align 4 dereferenceable(32) %_1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn borrowed_struct(_: &S) { @@ -80,36 +80,36 @@ pub fn struct_return() -> S { } // Hack to get the correct size for the length part in slices -// CHECK: @helper([[USIZE:i[0-9]+]] %arg0) +// CHECK: @helper([[USIZE:i[0-9]+]] %_1) #[no_mangle] pub fn helper(_: usize) { } -// CHECK: @slice([0 x i8]* noalias nonnull readonly align 1 %arg0.0, [[USIZE]] %arg0.1) +// CHECK: @slice([0 x i8]* noalias nonnull readonly align 1 %_1.0, [[USIZE]] %_1.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn slice(_: &[u8]) { } -// CHECK: @mutable_slice([0 x i8]* nonnull align 1 %arg0.0, [[USIZE]] %arg0.1) +// CHECK: @mutable_slice([0 x i8]* nonnull align 1 %_1.0, [[USIZE]] %_1.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn mutable_slice(_: &mut [u8]) { } -// CHECK: @unsafe_slice([0 x i16]* nonnull align 2 %arg0.0, [[USIZE]] %arg0.1) +// CHECK: @unsafe_slice([0 x i16]* nonnull align 2 %_1.0, [[USIZE]] %_1.1) // unsafe interior means this isn't actually readonly and there may be aliases ... #[no_mangle] pub fn unsafe_slice(_: &[UnsafeInner]) { } -// CHECK: @str([0 x i8]* noalias nonnull readonly align 1 %arg0.0, [[USIZE]] %arg0.1) +// CHECK: @str([0 x i8]* noalias nonnull readonly align 1 %_1.0, [[USIZE]] %_1.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn str(_: &[u8]) { } -// CHECK: @trait_borrow({}* nonnull align 1 %arg0.0, [3 x [[USIZE]]]* noalias readonly align {{.*}} dereferenceable({{.*}}) %arg0.1) +// CHECK: @trait_borrow({}* nonnull align 1 %_1.0, [3 x [[USIZE]]]* noalias readonly align {{.*}} dereferenceable({{.*}}) %_1.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn trait_borrow(_: &Drop) { diff --git a/src/test/codegen/integer-cmp.rs b/src/test/codegen/integer-cmp.rs new file mode 100644 index 0000000000000..8ada3cf09d073 --- /dev/null +++ b/src/test/codegen/integer-cmp.rs @@ -0,0 +1,28 @@ +// This is test for more optimal Ord implementation for integers. +// See for more info. + +// compile-flags: -C opt-level=3 + +#![crate_type = "lib"] + +use std::cmp::Ordering; + +// CHECK-LABEL: @cmp_signed +#[no_mangle] +pub fn cmp_signed(a: i64, b: i64) -> Ordering { +// CHECK: icmp slt +// CHECK: icmp ne +// CHECK: zext i1 +// CHECK: select i1 + a.cmp(&b) +} + +// CHECK-LABEL: @cmp_unsigned +#[no_mangle] +pub fn cmp_unsigned(a: u32, b: u32) -> Ordering { +// CHECK: icmp ult +// CHECK: icmp ne +// CHECK: zext i1 +// CHECK: select i1 + a.cmp(&b) +} diff --git a/src/test/codegen/issue-45222.rs b/src/test/codegen/issue-45222.rs index 7f99ca724cf73..7aadc8a095498 100644 --- a/src/test/codegen/issue-45222.rs +++ b/src/test/codegen/issue-45222.rs @@ -5,7 +5,6 @@ // verify that LLVM recognizes a loop involving 0..=n and will const-fold it. -//------------------------------------------------------------------------------ // Example from original issue #45222 fn foo2(n: u64) -> u64 { @@ -25,7 +24,6 @@ pub fn check_foo2() -> u64 { foo2(100000) } -//------------------------------------------------------------------------------ // Simplified example of #45222 fn triangle_inc(n: u64) -> u64 { @@ -43,7 +41,6 @@ pub fn check_triangle_inc() -> u64 { triangle_inc(100000) } -//------------------------------------------------------------------------------ // Demo in #48012 fn foo3r(n: u64) -> u64 { diff --git a/src/test/codegen/iter-fold-closure-no-dupes.rs b/src/test/codegen/iter-fold-closure-no-dupes.rs new file mode 100644 index 0000000000000..ec58f7068abac --- /dev/null +++ b/src/test/codegen/iter-fold-closure-no-dupes.rs @@ -0,0 +1,14 @@ +//! Check that fold closures aren't duplicated for each iterator type. +// compile-flags: -C opt-level=0 + +fn main() { + (0i32..10).by_ref().count(); + (0i32..=10).by_ref().count(); +} + +// `count` calls `fold`, which calls `try_fold` -- find the `fold` closure: +// CHECK: {{^define.*Iterator::fold::.*closure}} +// +// Only one closure is needed for both `count` calls, even from different +// monomorphized iterator types, as it's only generic over the item type. +// CHECK-NOT: {{^define.*Iterator::fold::.*closure}} diff --git a/src/test/codegen/iter-fold-closure-no-iterator.rs b/src/test/codegen/iter-fold-closure-no-iterator.rs new file mode 100644 index 0000000000000..fbeafd5f39582 --- /dev/null +++ b/src/test/codegen/iter-fold-closure-no-iterator.rs @@ -0,0 +1,10 @@ +//! Check that fold closures aren't generic in the iterator type. +// compile-flags: -C opt-level=0 + +fn main() { + (0i32..10).by_ref().count(); +} + +// `count` calls `fold`, which calls `try_fold` -- that `fold` closure should +// not be generic in the iterator type, only in the item type. +// CHECK-NOT: {{^define.*Iterator::fold::.*closure.*Range}} diff --git a/src/test/codegen/non-terminate/infinite-loop-1.rs b/src/test/codegen/non-terminate/infinite-loop-1.rs new file mode 100644 index 0000000000000..56b360e0a7f48 --- /dev/null +++ b/src/test/codegen/non-terminate/infinite-loop-1.rs @@ -0,0 +1,17 @@ +// compile-flags: -C opt-level=3 -Z insert-sideeffect + +#![crate_type = "lib"] + +fn infinite_loop() -> u8 { + loop {} +} + +// CHECK-LABEL: @test +#[no_mangle] +fn test() -> u8 { + // CHECK-NOT: unreachable + // CHECK: br label %{{.+}} + // CHECK-NOT: unreachable + let x = infinite_loop(); + x +} diff --git a/src/test/codegen/non-terminate/infinite-loop-2.rs b/src/test/codegen/non-terminate/infinite-loop-2.rs new file mode 100644 index 0000000000000..2921ab6dc04af --- /dev/null +++ b/src/test/codegen/non-terminate/infinite-loop-2.rs @@ -0,0 +1,19 @@ +// compile-flags: -C opt-level=3 -Z insert-sideeffect + +#![crate_type = "lib"] + +fn infinite_loop() -> u8 { + let i = 2; + while i > 1 {} + 1 +} + +// CHECK-LABEL: @test +#[no_mangle] +fn test() -> u8 { + // CHECK-NOT: unreachable + // CHECK: br label %{{.+}} + // CHECK-NOT: unreachable + let x = infinite_loop(); + x +} diff --git a/src/test/codegen/non-terminate/infinite-recursion.rs b/src/test/codegen/non-terminate/infinite-recursion.rs new file mode 100644 index 0000000000000..1f292ce379fc0 --- /dev/null +++ b/src/test/codegen/non-terminate/infinite-recursion.rs @@ -0,0 +1,14 @@ +// compile-flags: -C opt-level=3 -Z insert-sideeffect + +#![crate_type = "lib"] + +#![allow(unconditional_recursion)] + +// CHECK-LABEL: @infinite_recursion +#[no_mangle] +fn infinite_recursion() -> u8 { + // CHECK-NOT: ret i8 undef + // CHECK: br label %{{.+}} + // CHECK-NOT: ret i8 undef + infinite_recursion() +} diff --git a/src/test/codegen/personality_lifetimes.rs b/src/test/codegen/personality_lifetimes.rs index 0d3d537a2723d..05888c0e733ad 100644 --- a/src/test/codegen/personality_lifetimes.rs +++ b/src/test/codegen/personality_lifetimes.rs @@ -20,12 +20,13 @@ pub fn test() { let _s = S; // Check that the personality slot alloca gets a lifetime start in each cleanup block, not just // in the first one. + // CHECK: [[SLOT:%[0-9]+]] = alloca { i8*, i32 } // CHECK-LABEL: cleanup: - // CHECK: bitcast{{.*}}personalityslot - // CHECK-NEXT: call void @llvm.lifetime.start + // CHECK: [[BITCAST:%[0-9]+]] = bitcast { i8*, i32 }* [[SLOT]] to i8* + // CHECK-NEXT: call void @llvm.lifetime.start.{{.*}}({{.*}}, i8* [[BITCAST]]) // CHECK-LABEL: cleanup1: - // CHECK: bitcast{{.*}}personalityslot - // CHECK-NEXT: call void @llvm.lifetime.start + // CHECK: [[BITCAST1:%[0-9]+]] = bitcast { i8*, i32 }* [[SLOT]] to i8* + // CHECK-NEXT: call void @llvm.lifetime.start.{{.*}}({{.*}}, i8* [[BITCAST1]]) might_unwind(); let _t = S; might_unwind(); diff --git a/src/test/codegen/refs.rs b/src/test/codegen/refs.rs index cbb9942347673..15f99fd0c22a0 100644 --- a/src/test/codegen/refs.rs +++ b/src/test/codegen/refs.rs @@ -3,7 +3,7 @@ #![crate_type = "lib"] // Hack to get the correct size for the length part in slices -// CHECK: @helper([[USIZE:i[0-9]+]] %arg0) +// CHECK: @helper([[USIZE:i[0-9]+]] %_1) #[no_mangle] pub fn helper(_: usize) { } diff --git a/src/test/codegen/repeat-trusted-len.rs b/src/test/codegen/repeat-trusted-len.rs index c348a8f7b8b8f..87f29f6047c6a 100644 --- a/src/test/codegen/repeat-trusted-len.rs +++ b/src/test/codegen/repeat-trusted-len.rs @@ -6,7 +6,7 @@ use std::iter; -// CHECK: @helper([[USIZE:i[0-9]+]] %arg0) +// CHECK: @helper([[USIZE:i[0-9]+]] %_1) #[no_mangle] pub fn helper(_: usize) { } diff --git a/src/test/codegen/repr-transparent.rs b/src/test/codegen/repr-transparent.rs index c9f3837565808..e705d5ce3cd72 100644 --- a/src/test/codegen/repr-transparent.rs +++ b/src/test/codegen/repr-transparent.rs @@ -14,21 +14,21 @@ pub struct Zst2(()); #[repr(transparent)] pub struct F32(f32); -// CHECK: define float @test_F32(float %arg0) +// CHECK: define float @test_F32(float %_1) #[no_mangle] pub extern fn test_F32(_: F32) -> F32 { loop {} } #[repr(transparent)] pub struct Ptr(*mut u8); -// CHECK: define i8* @test_Ptr(i8* %arg0) +// CHECK: define i8* @test_Ptr(i8* %_1) #[no_mangle] pub extern fn test_Ptr(_: Ptr) -> Ptr { loop {} } #[repr(transparent)] pub struct WithZst(u64, Zst1); -// CHECK: define i64 @test_WithZst(i64 %arg0) +// CHECK: define i64 @test_WithZst(i64 %_1) #[no_mangle] pub extern fn test_WithZst(_: WithZst) -> WithZst { loop {} } @@ -36,14 +36,14 @@ pub extern fn test_WithZst(_: WithZst) -> WithZst { loop {} } pub struct WithZeroSizedArray(*const f32, [i8; 0]); // Apparently we use i32* when newtype-unwrapping f32 pointers. Whatever. -// CHECK: define i32* @test_WithZeroSizedArray(i32* %arg0) +// CHECK: define i32* @test_WithZeroSizedArray(i32* %_1) #[no_mangle] pub extern fn test_WithZeroSizedArray(_: WithZeroSizedArray) -> WithZeroSizedArray { loop {} } #[repr(transparent)] pub struct Generic(T); -// CHECK: define double @test_Generic(double %arg0) +// CHECK: define double @test_Generic(double %_1) #[no_mangle] pub extern fn test_Generic(_: Generic) -> Generic { loop {} } @@ -53,14 +53,14 @@ pub struct GenericPlusZst(T, Zst2); #[repr(u8)] pub enum Bool { True, False, FileNotFound } -// CHECK: define{{( zeroext)?}} i8 @test_Gpz(i8{{( zeroext)?}} %arg0) +// CHECK: define{{( zeroext)?}} i8 @test_Gpz(i8{{( zeroext)?}} %_1) #[no_mangle] pub extern fn test_Gpz(_: GenericPlusZst) -> GenericPlusZst { loop {} } #[repr(transparent)] pub struct LifetimePhantom<'a, T: 'a>(*const T, PhantomData<&'a T>); -// CHECK: define i16* @test_LifetimePhantom(i16* %arg0) +// CHECK: define i16* @test_LifetimePhantom(i16* %_1) #[no_mangle] pub extern fn test_LifetimePhantom(_: LifetimePhantom) -> LifetimePhantom { loop {} } @@ -70,28 +70,28 @@ pub struct UnitPhantom { val: T, unit: PhantomData } pub struct Px; -// CHECK: define float @test_UnitPhantom(float %arg0) +// CHECK: define float @test_UnitPhantom(float %_1) #[no_mangle] pub extern fn test_UnitPhantom(_: UnitPhantom) -> UnitPhantom { loop {} } #[repr(transparent)] pub struct TwoZsts(Zst1, i8, Zst2); -// CHECK: define{{( signext)?}} i8 @test_TwoZsts(i8{{( signext)?}} %arg0) +// CHECK: define{{( signext)?}} i8 @test_TwoZsts(i8{{( signext)?}} %_1) #[no_mangle] pub extern fn test_TwoZsts(_: TwoZsts) -> TwoZsts { loop {} } #[repr(transparent)] pub struct Nested1(Zst2, Generic); -// CHECK: define double @test_Nested1(double %arg0) +// CHECK: define double @test_Nested1(double %_1) #[no_mangle] pub extern fn test_Nested1(_: Nested1) -> Nested1 { loop {} } #[repr(transparent)] pub struct Nested2(Nested1, Zst1); -// CHECK: define double @test_Nested2(double %arg0) +// CHECK: define double @test_Nested2(double %_1) #[no_mangle] pub extern fn test_Nested2(_: Nested2) -> Nested2 { loop {} } @@ -101,7 +101,7 @@ struct f32x4(f32, f32, f32, f32); #[repr(transparent)] pub struct Vector(f32x4); -// CHECK: define <4 x float> @test_Vector(<4 x float> %arg0) +// CHECK: define <4 x float> @test_Vector(<4 x float> %_1) #[no_mangle] pub extern fn test_Vector(_: Vector) -> Vector { loop {} } @@ -111,7 +111,7 @@ impl Mirror for T { type It = Self; } #[repr(transparent)] pub struct StructWithProjection(::It); -// CHECK: define float @test_Projection(float %arg0) +// CHECK: define float @test_Projection(float %_1) #[no_mangle] pub extern fn test_Projection(_: StructWithProjection) -> StructWithProjection { loop {} } @@ -120,7 +120,7 @@ pub enum EnumF32 { Variant(F32) } -// CHECK: define float @test_EnumF32(float %arg0) +// CHECK: define float @test_EnumF32(float %_1) #[no_mangle] pub extern fn test_EnumF32(_: EnumF32) -> EnumF32 { loop {} } @@ -129,7 +129,7 @@ pub enum EnumF32WithZsts { Variant(Zst1, F32, Zst2) } -// CHECK: define float @test_EnumF32WithZsts(float %arg0) +// CHECK: define float @test_EnumF32WithZsts(float %_1) #[no_mangle] pub extern fn test_EnumF32WithZsts(_: EnumF32WithZsts) -> EnumF32WithZsts { loop {} } @@ -138,7 +138,7 @@ pub union UnionF32 { field: F32, } -// CHECK: define float @test_UnionF32(float %arg0) +// CHECK: define float @test_UnionF32(float %_1) #[no_mangle] pub extern fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} } @@ -149,7 +149,7 @@ pub union UnionF32WithZsts { zst2: Zst2, } -// CHECK: define float @test_UnionF32WithZsts(float %arg0) +// CHECK: define float @test_UnionF32WithZsts(float %_1) #[no_mangle] pub extern fn test_UnionF32WithZsts(_: UnionF32WithZsts) -> UnionF32WithZsts { loop {} } diff --git a/src/test/codegen/scalar-pair-bool.rs b/src/test/codegen/scalar-pair-bool.rs index 78d1025b13c77..d91ee7f816ded 100644 --- a/src/test/codegen/scalar-pair-bool.rs +++ b/src/test/codegen/scalar-pair-bool.rs @@ -20,24 +20,24 @@ pub fn pair_i32_bool(pair: (i32, bool)) -> (i32, bool) { pair } -// CHECK: define { i8, i8 } @pair_and_or(i1 zeroext %arg0.0, i1 zeroext %arg0.1) +// CHECK: define { i8, i8 } @pair_and_or(i1 zeroext %_1.0, i1 zeroext %_1.1) #[no_mangle] pub fn pair_and_or((a, b): (bool, bool)) -> (bool, bool) { // Make sure it can operate directly on the unpacked args - // CHECK: and i1 %arg0.0, %arg0.1 - // CHECK: or i1 %arg0.0, %arg0.1 + // CHECK: and i1 %_1.0, %_1.1 + // CHECK: or i1 %_1.0, %_1.1 (a && b, a || b) } -// CHECK: define void @pair_branches(i1 zeroext %arg0.0, i1 zeroext %arg0.1) +// CHECK: define void @pair_branches(i1 zeroext %_1.0, i1 zeroext %_1.1) #[no_mangle] pub fn pair_branches((a, b): (bool, bool)) { // Make sure it can branch directly on the unpacked bool args - // CHECK: br i1 %arg0.0 + // CHECK: br i1 %_1.0 if a { println!("Hello!"); } - // CHECK: br i1 %arg0.1 + // CHECK: br i1 %_1.1 if b { println!("Goodbye!"); } diff --git a/src/test/codegen/union-abi.rs b/src/test/codegen/union-abi.rs index b7baffe16695a..7339df17b057a 100644 --- a/src/test/codegen/union-abi.rs +++ b/src/test/codegen/union-abi.rs @@ -16,38 +16,38 @@ pub struct i64x4(i64, i64, i64, i64); #[derive(Copy, Clone)] pub union UnionI64x4{ a:(), b: i64x4 } -// CHECK: define void @test_UnionI64x4(<4 x i64>* {{.*}} %arg0) +// CHECK: define void @test_UnionI64x4(<4 x i64>* {{.*}} %_1) #[no_mangle] pub fn test_UnionI64x4(_: UnionI64x4) { loop {} } pub union UnionI64x4_{ a: i64x4, b: (), c:i64x4, d: Unhab, e: ((),()), f: UnionI64x4 } -// CHECK: define void @test_UnionI64x4_(<4 x i64>* {{.*}} %arg0) +// CHECK: define void @test_UnionI64x4_(<4 x i64>* {{.*}} %_1) #[no_mangle] pub fn test_UnionI64x4_(_: UnionI64x4_) { loop {} } pub union UnionI64x4I64{ a: i64x4, b: i64 } -// CHECK: define void @test_UnionI64x4I64(%UnionI64x4I64* {{.*}} %arg0) +// CHECK: define void @test_UnionI64x4I64(%UnionI64x4I64* {{.*}} %_1) #[no_mangle] pub fn test_UnionI64x4I64(_: UnionI64x4I64) { loop {} } pub union UnionI64x4Tuple{ a: i64x4, b: (i64, i64, i64, i64) } -// CHECK: define void @test_UnionI64x4Tuple(%UnionI64x4Tuple* {{.*}} %arg0) +// CHECK: define void @test_UnionI64x4Tuple(%UnionI64x4Tuple* {{.*}} %_1) #[no_mangle] pub fn test_UnionI64x4Tuple(_: UnionI64x4Tuple) { loop {} } pub union UnionF32{a:f32} -// CHECK: define float @test_UnionF32(float %arg0) +// CHECK: define float @test_UnionF32(float %_1) #[no_mangle] pub fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} } pub union UnionF32F32{a:f32, b:f32} -// CHECK: define float @test_UnionF32F32(float %arg0) +// CHECK: define float @test_UnionF32F32(float %_1) #[no_mangle] pub fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { loop {} } @@ -58,13 +58,13 @@ pub union UnionF32U32{a:f32, b:u32} pub fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { loop {} } pub union UnionU128{a:u128} -// CHECK: define i128 @test_UnionU128(i128 %arg0) +// CHECK: define i128 @test_UnionU128(i128 %_1) #[no_mangle] pub fn test_UnionU128(_: UnionU128) -> UnionU128 { loop {} } #[repr(C)] pub union CUnionU128{a:u128} -// CHECK: define void @test_CUnionU128(%CUnionU128* {{.*}} %arg0) +// CHECK: define void @test_CUnionU128(%CUnionU128* {{.*}} %_1) #[no_mangle] pub fn test_CUnionU128(_: CUnionU128) { loop {} } diff --git a/src/test/codegen/var-names.rs b/src/test/codegen/var-names.rs new file mode 100644 index 0000000000000..3140a7c6b6cc2 --- /dev/null +++ b/src/test/codegen/var-names.rs @@ -0,0 +1,15 @@ +// compile-flags: -O -C no-prepopulate-passes + +#![crate_type = "lib"] + +// CHECK-LABEL: define i32 @test(i32 %a, i32 %b) +#[no_mangle] +pub fn test(a: u32, b: u32) -> u32 { + let c = a + b; + // CHECK: %c = add i32 %a, %b + let d = c; + let e = d * a; + // CHECK-NEXT: %e = mul i32 %c, %a + e + // CHECK-NEXT: ret i32 %e +} diff --git a/src/test/ui/issues/issue-44415.rs b/src/test/compile-fail/issue-44415.rs similarity index 100% rename from src/test/ui/issues/issue-44415.rs rename to src/test/compile-fail/issue-44415.rs diff --git a/src/test/compile-fail/two-panic-runtimes.rs b/src/test/compile-fail/two-panic-runtimes.rs index 66b184e521abc..671d44564e66f 100644 --- a/src/test/compile-fail/two-panic-runtimes.rs +++ b/src/test/compile-fail/two-panic-runtimes.rs @@ -5,6 +5,7 @@ // aux-build:panic-runtime-lang-items.rs #![no_std] +#![no_main] extern crate panic_runtime_unwind; extern crate panic_runtime_unwind2; diff --git a/src/test/debuginfo/boxed-struct.rs b/src/test/debuginfo/boxed-struct.rs index c0ff90c3ffb9b..8709fb681704b 100644 --- a/src/test/debuginfo/boxed-struct.rs +++ b/src/test/debuginfo/boxed-struct.rs @@ -8,11 +8,11 @@ // gdb-command:run -// gdb-command:print *unique +// gdb-command:print *boxed_with_padding // gdbg-check:$1 = {x = 99, y = 999, z = 9999, w = 99999} // gdbr-check:$1 = boxed_struct::StructWithSomePadding {x: 99, y: 999, z: 9999, w: 99999} -// gdb-command:print *unique_dtor +// gdb-command:print *boxed_with_dtor // gdbg-check:$2 = {x = 77, y = 777, z = 7777, w = 77777} // gdbr-check:$2 = boxed_struct::StructWithDestructor {x: 77, y: 777, z: 7777, w: 77777} @@ -21,13 +21,13 @@ // lldb-command:run -// lldb-command:print *unique +// lldb-command:print *boxed_with_padding // lldbg-check:[...]$0 = StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 } -// lldbr-check:(boxed_struct::StructWithSomePadding) *unique = StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 } +// lldbr-check:(boxed_struct::StructWithSomePadding) *boxed_with_padding = StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 } -// lldb-command:print *unique_dtor +// lldb-command:print *boxed_with_dtor // lldbg-check:[...]$1 = StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 } -// lldbr-check:(boxed_struct::StructWithDestructor) *unique_dtor = StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 } +// lldbr-check:(boxed_struct::StructWithDestructor) *boxed_with_dtor = StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 } #![allow(unused_variables)] #![feature(box_syntax)] @@ -54,9 +54,9 @@ impl Drop for StructWithDestructor { fn main() { - let unique: Box<_> = box StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 }; + let boxed_with_padding: Box<_> = box StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 }; - let unique_dtor: Box<_> = box StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 }; + let boxed_with_dtor: Box<_> = box StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 }; zzz(); // #break } diff --git a/src/test/debuginfo/function-arg-initialization.rs b/src/test/debuginfo/function-arg-initialization.rs index fef62534b304d..8c86d2cf435b6 100644 --- a/src/test/debuginfo/function-arg-initialization.rs +++ b/src/test/debuginfo/function-arg-initialization.rs @@ -242,12 +242,12 @@ fn non_immediate_args(a: BigStruct, b: BigStruct) { fn binding(a: i64, b: u64, c: f64) { let x = 0; // #break - println!("") + println!() } fn assignment(mut a: u64, b: u64, c: f64) { a = b; // #break - println!("") + println!() } fn function_call(x: u64, y: u64, z: f64) { diff --git a/src/test/debuginfo/generator-objects.rs b/src/test/debuginfo/generator-objects.rs index c6f98e5782b1f..bfa7a05cad057 100644 --- a/src/test/debuginfo/generator-objects.rs +++ b/src/test/debuginfo/generator-objects.rs @@ -10,31 +10,31 @@ // gdb-command:run // gdb-command:print b -// gdb-check:$1 = generator_objects::main::generator {__0: 0x[...], <>: {__state: 0, 0: generator_objects::main::generator::Unresumed, 1: generator_objects::main::generator::Returned, 2: generator_objects::main::generator::Panicked, 3: generator_objects::main::generator::Suspend0 {[...]}, 4: generator_objects::main::generator::Suspend1 {[...]}}} +// gdb-check:$1 = generator_objects::main::generator-0 {__0: 0x[...], <>: {__state: 0, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}} // gdb-command:continue // gdb-command:print b -// gdb-check:$2 = generator_objects::main::generator {__0: 0x[...], <>: {__state: 3, 0: generator_objects::main::generator::Unresumed, 1: generator_objects::main::generator::Returned, 2: generator_objects::main::generator::Panicked, 3: generator_objects::main::generator::Suspend0 {c: 6, d: 7}, 4: generator_objects::main::generator::Suspend1 {[...]}}} +// gdb-check:$2 = generator_objects::main::generator-0 {__0: 0x[...], <>: {__state: 3, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {c: 6, d: 7}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}} // gdb-command:continue // gdb-command:print b -// gdb-check:$3 = generator_objects::main::generator {__0: 0x[...], <>: {__state: 4, 0: generator_objects::main::generator::Unresumed, 1: generator_objects::main::generator::Returned, 2: generator_objects::main::generator::Panicked, 3: generator_objects::main::generator::Suspend0 {[...]}, 4: generator_objects::main::generator::Suspend1 {c: 7, d: 8}}} +// gdb-check:$3 = generator_objects::main::generator-0 {__0: 0x[...], <>: {__state: 4, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {c: 7, d: 8}}} // gdb-command:continue // gdb-command:print b -// gdb-check:$4 = generator_objects::main::generator {__0: 0x[...], <>: {__state: 1, 0: generator_objects::main::generator::Unresumed, 1: generator_objects::main::generator::Returned, 2: generator_objects::main::generator::Panicked, 3: generator_objects::main::generator::Suspend0 {[...]}, 4: generator_objects::main::generator::Suspend1 {[...]}}} +// gdb-check:$4 = generator_objects::main::generator-0 {__0: 0x[...], <>: {__state: 1, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}} // === LLDB TESTS ================================================================================== // lldb-command:run // lldb-command:print b -// lldbg-check:(generator_objects::main::generator) $0 = generator(&0x[...]) +// lldbg-check:(generator_objects::main::generator-0) $0 = generator-0(&0x[...]) // lldb-command:continue // lldb-command:print b -// lldbg-check:(generator_objects::main::generator) $1 = generator(&0x[...]) +// lldbg-check:(generator_objects::main::generator-0) $1 = generator-0(&0x[...]) // lldb-command:continue // lldb-command:print b -// lldbg-check:(generator_objects::main::generator) $2 = generator(&0x[...]) +// lldbg-check:(generator_objects::main::generator-0) $2 = generator-0(&0x[...]) // lldb-command:continue // lldb-command:print b -// lldbg-check:(generator_objects::main::generator) $3 = generator(&0x[...]) +// lldbg-check:(generator_objects::main::generator-0) $3 = generator-0(&0x[...]) #![feature(omit_gdb_pretty_printer_section, generators, generator_trait)] #![omit_gdb_pretty_printer_section] diff --git a/src/test/debuginfo/issue-22656.rs b/src/test/debuginfo/issue-22656.rs index 86d31909a0b3b..e4634d96a6f31 100644 --- a/src/test/debuginfo/issue-22656.rs +++ b/src/test/debuginfo/issue-22656.rs @@ -15,7 +15,7 @@ // lldbg-check:[...]$0 = vec![1, 2, 3] // lldbr-check:(alloc::vec::Vec) v = vec![1, 2, 3] // lldb-command:print zs -// lldbg-check:[...]$1 = StructWithZeroSizedField { x: ZeroSizedStruct, y: 123, z: ZeroSizedStruct, w: 456 } +// lldbg-check:[...]$1 = StructWithZeroSizedField { x: ZeroSizedStruct[...], y: 123, z: ZeroSizedStruct[...], w: 456 } // lldbr-check:(issue_22656::StructWithZeroSizedField) zs = StructWithZeroSizedField { x: ZeroSizedStruct { }, y: 123, z: ZeroSizedStruct { }, w: 456 } // lldbr-command:continue diff --git a/src/test/debuginfo/issue-57822.rs b/src/test/debuginfo/issue-57822.rs new file mode 100644 index 0000000000000..f18e41db0e6ba --- /dev/null +++ b/src/test/debuginfo/issue-57822.rs @@ -0,0 +1,55 @@ +// This test makes sure that the LLDB pretty printer does not throw an exception +// for nested closures and generators. + +// Require LLVM with DW_TAG_variant_part and a gdb that can read it. +// min-system-llvm-version: 8.0 +// min-gdb-version: 8.2 +// ignore-tidy-linelength + +// compile-flags:-g + +// === GDB TESTS =================================================================================== + +// gdb-command:run + +// gdb-command:print g +// gdb-check:$1 = issue_57822::main::closure-1 (issue_57822::main::closure-0 (1)) + +// gdb-command:print b +// gdb-check:$2 = issue_57822::main::generator-3 {__0: issue_57822::main::generator-2 {__0: 2, <>: {[...]}}, <>: {[...]}} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print g +// lldbg-check:(issue_57822::main::closure-1) $0 = closure-1(closure-0(1)) + +// lldb-command:print b +// lldbg-check:(issue_57822::main::generator-3) $1 = generator-3(generator-2(2)) + +#![feature(omit_gdb_pretty_printer_section, generators, generator_trait)] +#![omit_gdb_pretty_printer_section] + +use std::ops::Generator; +use std::pin::Pin; + +fn main() { + let mut x = 1; + let f = move || x; + let g = move || f(); + + let mut y = 2; + let mut a = move || { + y += 1; + yield; + }; + let mut b = move || { + Pin::new(&mut a).resume(); + yield; + }; + + zzz(); // #break +} + +fn zzz() { () } diff --git a/src/test/incremental/hashes/call_expressions.rs b/src/test/incremental/hashes/call_expressions.rs index d859cbef39f09..50d3657d417f3 100644 --- a/src/test/incremental/hashes/call_expressions.rs +++ b/src/test/incremental/hashes/call_expressions.rs @@ -18,7 +18,7 @@ fn callee1(_x: u32, _y: i64) {} fn callee2(_x: u32, _y: i64) {} -// Change Callee (Function) ---------------------------------------------------- +// Change Callee (Function) #[cfg(cfail1)] pub fn change_callee_function() { callee1(1, 2) @@ -33,7 +33,7 @@ pub fn change_callee_function() { -// Change Argument (Function) -------------------------------------------------- +// Change Argument (Function) #[cfg(cfail1)] pub fn change_argument_function() { callee1(1, 2) @@ -48,7 +48,7 @@ pub fn change_argument_function() { -// Change Callee Indirectly (Function) ----------------------------------------- +// Change Callee Indirectly (Function) mod change_callee_indirectly_function { #[cfg(cfail1)] use super::callee1 as callee; @@ -73,7 +73,7 @@ impl Struct { fn method2(&self, _x: char, _y: bool) {} } -// Change Callee (Method) ------------------------------------------------------ +// Change Callee (Method) #[cfg(cfail1)] pub fn change_callee_method() { let s = Struct; @@ -90,7 +90,7 @@ pub fn change_callee_method() { -// Change Argument (Method) ---------------------------------------------------- +// Change Argument (Method) #[cfg(cfail1)] pub fn change_argument_method() { let s = Struct; @@ -107,7 +107,7 @@ pub fn change_argument_method() { -// Change Callee (Method, UFCS) ------------------------------------------------ +// Change Callee (Method, UFCS) #[cfg(cfail1)] pub fn change_ufcs_callee_method() { let s = Struct; @@ -124,7 +124,7 @@ pub fn change_ufcs_callee_method() { -// Change Argument (Method, UFCS) ---------------------------------------------- +// Change Argument (Method, UFCS) #[cfg(cfail1)] pub fn change_argument_method_ufcs() { let s = Struct; @@ -141,7 +141,7 @@ pub fn change_argument_method_ufcs() { -// Change To UFCS -------------------------------------------------------------- +// Change To UFCS #[cfg(cfail1)] pub fn change_to_ufcs() { let s = Struct; @@ -164,7 +164,7 @@ impl Struct2 { fn method1(&self, _x: char, _y: bool) {} } -// Change UFCS Callee Indirectly ----------------------------------------------- +// Change UFCS Callee Indirectly pub mod change_ufcs_callee_indirectly { #[cfg(cfail1)] use super::Struct as Struct; diff --git a/src/test/incremental/hashes/closure_expressions.rs b/src/test/incremental/hashes/closure_expressions.rs index 24ab6b8e18455..08693560d0b6e 100644 --- a/src/test/incremental/hashes/closure_expressions.rs +++ b/src/test/incremental/hashes/closure_expressions.rs @@ -14,7 +14,7 @@ #![crate_type="rlib"] -// Change closure body --------------------------------------------------------- +// Change closure body #[cfg(cfail1)] pub fn change_closure_body() { let _ = || 1u32; @@ -29,7 +29,7 @@ pub fn change_closure_body() { -// Add parameter --------------------------------------------------------------- +// Add parameter #[cfg(cfail1)] pub fn add_parameter() { let x = 0u32; @@ -46,7 +46,7 @@ pub fn add_parameter() { -// Change parameter pattern ---------------------------------------------------- +// Change parameter pattern #[cfg(cfail1)] pub fn change_parameter_pattern() { let _ = |x: (u32,)| x; @@ -61,7 +61,7 @@ pub fn change_parameter_pattern() { -// Add `move` to closure ------------------------------------------------------- +// Add `move` to closure #[cfg(cfail1)] pub fn add_move() { let _ = || 1; @@ -76,7 +76,7 @@ pub fn add_move() { -// Add type ascription to parameter -------------------------------------------- +// Add type ascription to parameter #[cfg(cfail1)] pub fn add_type_ascription_to_parameter() { let closure = |x| x + 1u32; @@ -93,7 +93,7 @@ pub fn add_type_ascription_to_parameter() { -// Change parameter type ------------------------------------------------------- +// Change parameter type #[cfg(cfail1)] pub fn change_parameter_type() { let closure = |x: u32| (x as u64) + 1; diff --git a/src/test/incremental/hashes/consts.rs b/src/test/incremental/hashes/consts.rs index 8e713a1d99237..3d2eed89636e8 100644 --- a/src/test/incremental/hashes/consts.rs +++ b/src/test/incremental/hashes/consts.rs @@ -14,7 +14,7 @@ #![crate_type="rlib"] -// Change const visibility --------------------------------------------------- +// Change const visibility #[cfg(cfail1)] const CONST_VISIBILITY: u8 = 0; @@ -24,7 +24,7 @@ const CONST_VISIBILITY: u8 = 0; pub const CONST_VISIBILITY: u8 = 0; -// Change type from i32 to u32 ------------------------------------------------ +// Change type from i32 to u32 #[cfg(cfail1)] const CONST_CHANGE_TYPE_1: i32 = 0; @@ -34,7 +34,7 @@ const CONST_CHANGE_TYPE_1: i32 = 0; const CONST_CHANGE_TYPE_1: u32 = 0; -// Change type from Option to Option -------------------------------- +// Change type from Option to Option #[cfg(cfail1)] const CONST_CHANGE_TYPE_2: Option = None; @@ -44,7 +44,7 @@ const CONST_CHANGE_TYPE_2: Option = None; const CONST_CHANGE_TYPE_2: Option = None; -// Change value between simple literals --------------------------------------- +// Change value between simple literals #[rustc_clean(cfg="cfail2", except="HirBody")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_VALUE_1: i16 = { @@ -56,7 +56,7 @@ const CONST_CHANGE_VALUE_1: i16 = { }; -// Change value between expressions ------------------------------------------- +// Change value between expressions #[rustc_clean(cfg="cfail2", except="HirBody")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_VALUE_2: i16 = { @@ -88,7 +88,7 @@ const CONST_CHANGE_VALUE_4: i16 = { }; -// Change type indirectly ----------------------------------------------------- +// Change type indirectly struct ReferencedType1; struct ReferencedType2; diff --git a/src/test/incremental/hashes/for_loops.rs b/src/test/incremental/hashes/for_loops.rs index ca45d36a6b0e4..70820dfaea4a0 100644 --- a/src/test/incremental/hashes/for_loops.rs +++ b/src/test/incremental/hashes/for_loops.rs @@ -94,7 +94,7 @@ pub fn change_iterable() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, promoted_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_iterable() { let mut _x = 0; diff --git a/src/test/incremental/hashes/function_interfaces.rs b/src/test/incremental/hashes/function_interfaces.rs index 84680a52ff3ce..9cc2d3bcf6045 100644 --- a/src/test/incremental/hashes/function_interfaces.rs +++ b/src/test/incremental/hashes/function_interfaces.rs @@ -11,7 +11,6 @@ #![allow(warnings)] -#![feature(intrinsics)] #![feature(linkage)] #![feature(rustc_attrs)] #![crate_type = "rlib"] @@ -93,21 +92,10 @@ pub unsafe fn make_unsafe() {} #[cfg(cfail1)] pub fn make_extern() {} -#[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, mir_built, typeck_tables_of, fn_sig")] -#[rustc_clean(cfg = "cfail3")] -pub extern "C" fn make_extern() {} - - -// Extern C Extern Rust-Intrinsic ---------------------------------------------- - -#[cfg(cfail1)] -pub extern "C" fn make_intrinsic() {} - #[cfg(not(cfail1))] #[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, typeck_tables_of, fn_sig")] #[rustc_clean(cfg = "cfail3")] -pub extern "rust-intrinsic" fn make_intrinsic() {} +pub extern "C" fn make_extern() {} // Type Parameter -------------------------------------------------------------- diff --git a/src/test/incremental/hashes/if_expressions.rs b/src/test/incremental/hashes/if_expressions.rs index b84c393573b91..4b73f1371f872 100644 --- a/src/test/incremental/hashes/if_expressions.rs +++ b/src/test/incremental/hashes/if_expressions.rs @@ -14,7 +14,7 @@ #![feature(rustc_attrs)] #![crate_type="rlib"] -// Change condition (if) ------------------------------------------------------- +// Change condition (if) #[cfg(cfail1)] pub fn change_condition(x: bool) -> u32 { if x { @@ -35,7 +35,7 @@ pub fn change_condition(x: bool) -> u32 { return 0 } -// Change then branch (if) ----------------------------------------------------- +// Change then branch (if) #[cfg(cfail1)] pub fn change_then_branch(x: bool) -> u32 { if x { @@ -58,7 +58,7 @@ pub fn change_then_branch(x: bool) -> u32 { -// Change else branch (if) ----------------------------------------------------- +// Change else branch (if) #[cfg(cfail1)] pub fn change_else_branch(x: bool) -> u32 { if x { @@ -81,7 +81,7 @@ pub fn change_else_branch(x: bool) -> u32 { -// Add else branch (if) -------------------------------------------------------- +// Add else branch (if) #[cfg(cfail1)] pub fn add_else_branch(x: bool) -> u32 { let mut ret = 1; @@ -109,7 +109,7 @@ pub fn add_else_branch(x: bool) -> u32 { -// Change condition (if let) --------------------------------------------------- +// Change condition (if let) #[cfg(cfail1)] pub fn change_condition_if_let(x: Option) -> u32 { if let Some(_x) = x { @@ -132,7 +132,7 @@ pub fn change_condition_if_let(x: Option) -> u32 { -// Change then branch (if let) ------------------------------------------------- +// Change then branch (if let) #[cfg(cfail1)] pub fn change_then_branch_if_let(x: Option) -> u32 { if let Some(x) = x { @@ -155,7 +155,7 @@ pub fn change_then_branch_if_let(x: Option) -> u32 { -// Change else branch (if let) ------------------------------------------------- +// Change else branch (if let) #[cfg(cfail1)] pub fn change_else_branch_if_let(x: Option) -> u32 { if let Some(x) = x { @@ -178,7 +178,7 @@ pub fn change_else_branch_if_let(x: Option) -> u32 { -// Add else branch (if let) ---------------------------------------------------- +// Add else branch (if let) #[cfg(cfail1)] pub fn add_else_branch_if_let(x: Option) -> u32 { let mut ret = 1; diff --git a/src/test/incremental/hashes/indexing_expressions.rs b/src/test/incremental/hashes/indexing_expressions.rs index 4d39ed68701dd..08cf19d776028 100644 --- a/src/test/incremental/hashes/indexing_expressions.rs +++ b/src/test/incremental/hashes/indexing_expressions.rs @@ -13,7 +13,7 @@ #![feature(rustc_attrs)] #![crate_type="rlib"] -// Change simple index --------------------------------------------------------- +// Change simple index #[cfg(cfail1)] fn change_simple_index(slice: &[u32]) -> u32 { slice[3] @@ -30,7 +30,7 @@ fn change_simple_index(slice: &[u32]) -> u32 { -// Change lower bound ---------------------------------------------------------- +// Change lower bound #[cfg(cfail1)] fn change_lower_bound(slice: &[u32]) -> &[u32] { &slice[3..5] @@ -47,7 +47,7 @@ fn change_lower_bound(slice: &[u32]) -> &[u32] { -// Change upper bound ---------------------------------------------------------- +// Change upper bound #[cfg(cfail1)] fn change_upper_bound(slice: &[u32]) -> &[u32] { &slice[3..5] @@ -64,7 +64,7 @@ fn change_upper_bound(slice: &[u32]) -> &[u32] { -// Add lower bound ------------------------------------------------------------- +// Add lower bound #[cfg(cfail1)] fn add_lower_bound(slice: &[u32]) -> &[u32] { &slice[..4] @@ -81,7 +81,7 @@ fn add_lower_bound(slice: &[u32]) -> &[u32] { -// Add upper bound ------------------------------------------------------------- +// Add upper bound #[cfg(cfail1)] fn add_upper_bound(slice: &[u32]) -> &[u32] { &slice[3..] @@ -98,7 +98,7 @@ fn add_upper_bound(slice: &[u32]) -> &[u32] { -// Change mutability ----------------------------------------------------------- +// Change mutability #[cfg(cfail1)] fn change_mutability(slice: &mut [u32]) -> u32 { (&mut slice[3..5])[0] @@ -115,7 +115,7 @@ fn change_mutability(slice: &mut [u32]) -> u32 { -// Exclusive to inclusive range ------------------------------------------------ +// Exclusive to inclusive range #[cfg(cfail1)] fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] { &slice[3..7] diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs index 882383e841957..24d436f5f9727 100644 --- a/src/test/incremental/hashes/inherent_impls.rs +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -42,7 +42,10 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] + #[rustc_clean( + cfg="cfail2", + except="HirBody,optimized_mir,promoted_mir,mir_built,typeck_tables_of" + )] #[rustc_clean(cfg="cfail3")] pub fn method_body() { println!("Hello, world!"); @@ -63,7 +66,10 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] + #[rustc_clean( + cfg="cfail2", + except="HirBody,optimized_mir,promoted_mir,mir_built,typeck_tables_of" + )] #[rustc_clean(cfg="cfail3")] #[inline] pub fn method_body_inlined() { @@ -97,7 +103,7 @@ impl Foo { #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(cfg="cfail2", except="type_of,predicates_of")] + #[rustc_dirty(cfg="cfail2", except="type_of,predicates_of,promoted_mir")] #[rustc_clean(cfg="cfail3")] pub fn method_selfness(&self) { } } @@ -263,7 +269,7 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="Hir,HirBody,mir_built,fn_sig,typeck_tables_of")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody,fn_sig,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub extern fn make_method_extern(&self) { } } diff --git a/src/test/incremental/hashes/inline_asm.rs b/src/test/incremental/hashes/inline_asm.rs index deb1c45a52885..c50ee73d71438 100644 --- a/src/test/incremental/hashes/inline_asm.rs +++ b/src/test/incremental/hashes/inline_asm.rs @@ -16,7 +16,7 @@ -// Change template ------------------------------------------------------------- +// Change template #[cfg(cfail1)] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_template(a: i32) -> i32 { @@ -51,7 +51,7 @@ pub fn change_template(a: i32) -> i32 { -// Change output ------------------------------------------------------------- +// Change output #[cfg(cfail1)] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_output(a: i32) -> i32 { @@ -88,7 +88,7 @@ pub fn change_output(a: i32) -> i32 { -// Change input ------------------------------------------------------------- +// Change input #[cfg(cfail1)] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_input(_a: i32, _b: i32) -> i32 { @@ -123,7 +123,7 @@ pub fn change_input(_a: i32, _b: i32) -> i32 { -// Change input constraint ----------------------------------------------------- +// Change input constraint #[cfg(cfail1)] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_input_constraint(_a: i32, _b: i32) -> i32 { @@ -158,7 +158,7 @@ pub fn change_input_constraint(_a: i32, _b: i32) -> i32 { -// Change clobber -------------------------------------------------------------- +// Change clobber #[cfg(cfail1)] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_clobber(_a: i32) -> i32 { @@ -193,7 +193,7 @@ pub fn change_clobber(_a: i32) -> i32 { -// Change options -------------------------------------------------------------- +// Change options #[cfg(cfail1)] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_options(_a: i32) -> i32 { diff --git a/src/test/incremental/hashes/loop_expressions.rs b/src/test/incremental/hashes/loop_expressions.rs index 6222d948c98e9..a2222db4c59ad 100644 --- a/src/test/incremental/hashes/loop_expressions.rs +++ b/src/test/incremental/hashes/loop_expressions.rs @@ -14,7 +14,7 @@ #![crate_type="rlib"] -// Change loop body ------------------------------------------------------------ +// Change loop body #[cfg(cfail1)] pub fn change_loop_body() { let mut _x = 0; @@ -37,7 +37,7 @@ pub fn change_loop_body() { -// Add break ------------------------------------------------------------------- +// Add break #[cfg(cfail1)] pub fn add_break() { let mut _x = 0; @@ -59,7 +59,7 @@ pub fn add_break() { -// Add loop label -------------------------------------------------------------- +// Add loop label #[cfg(cfail1)] pub fn add_loop_label() { let mut _x = 0; @@ -82,7 +82,7 @@ pub fn add_loop_label() { -// Add loop label to break ----------------------------------------------------- +// Add loop label to break #[cfg(cfail1)] pub fn add_loop_label_to_break() { let mut _x = 0; @@ -105,7 +105,7 @@ pub fn add_loop_label_to_break() { -// Change break label ---------------------------------------------------------- +// Change break label #[cfg(cfail1)] pub fn change_break_label() { let mut _x = 0; @@ -132,7 +132,7 @@ pub fn change_break_label() { -// Add loop label to continue -------------------------------------------------- +// Add loop label to continue #[cfg(cfail1)] pub fn add_loop_label_to_continue() { let mut _x = 0; @@ -155,7 +155,7 @@ pub fn add_loop_label_to_continue() { -// Change continue label ---------------------------------------------------------- +// Change continue label #[cfg(cfail1)] pub fn change_continue_label() { let mut _x = 0; @@ -182,7 +182,7 @@ pub fn change_continue_label() { -// Change continue to break ---------------------------------------------------- +// Change continue to break #[cfg(cfail1)] pub fn change_continue_to_break() { let mut _x = 0; diff --git a/src/test/incremental/hashes/panic_exprs.rs b/src/test/incremental/hashes/panic_exprs.rs index b370fcce8efda..70b0a5ab78cd7 100644 --- a/src/test/incremental/hashes/panic_exprs.rs +++ b/src/test/incremental/hashes/panic_exprs.rs @@ -17,7 +17,7 @@ #![crate_type="rlib"] -// Indexing expression --------------------------------------------------------- +// Indexing expression #[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn indexing(slice: &[u8]) -> u8 { @@ -32,7 +32,7 @@ pub fn indexing(slice: &[u8]) -> u8 { } -// Arithmetic overflow plus ---------------------------------------------------- +// Arithmetic overflow plus #[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn arithmetic_overflow_plus(val: i32) -> i32 { @@ -47,7 +47,7 @@ pub fn arithmetic_overflow_plus(val: i32) -> i32 { } -// Arithmetic overflow minus ---------------------------------------------------- +// Arithmetic overflow minus #[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn arithmetic_overflow_minus(val: i32) -> i32 { @@ -62,7 +62,7 @@ pub fn arithmetic_overflow_minus(val: i32) -> i32 { } -// Arithmetic overflow mult ---------------------------------------------------- +// Arithmetic overflow mult #[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn arithmetic_overflow_mult(val: i32) -> i32 { @@ -77,7 +77,7 @@ pub fn arithmetic_overflow_mult(val: i32) -> i32 { } -// Arithmetic overflow negation ------------------------------------------------ +// Arithmetic overflow negation #[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn arithmetic_overflow_negation(val: i32) -> i32 { @@ -92,7 +92,7 @@ pub fn arithmetic_overflow_negation(val: i32) -> i32 { } -// Division by zero ------------------------------------------------------------ +// Division by zero #[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn division_by_zero(val: i32) -> i32 { @@ -106,7 +106,7 @@ pub fn division_by_zero(val: i32) -> i32 { } } -// Division by zero ------------------------------------------------------------ +// Division by zero #[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn mod_by_zero(val: i32) -> i32 { @@ -121,7 +121,7 @@ pub fn mod_by_zero(val: i32) -> i32 { } -// shift left ------------------------------------------------------------------ +// shift left #[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn shift_left(val: i32, shift: usize) -> i32 { @@ -136,7 +136,7 @@ pub fn shift_left(val: i32, shift: usize) -> i32 { } -// shift right ------------------------------------------------------------------ +// shift right #[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn shift_right(val: i32, shift: usize) -> i32 { diff --git a/src/test/incremental/hashes/statics.rs b/src/test/incremental/hashes/statics.rs index 6f74e0fdbc06e..d70ebb08b715a 100644 --- a/src/test/incremental/hashes/statics.rs +++ b/src/test/incremental/hashes/statics.rs @@ -16,7 +16,7 @@ #![crate_type="rlib"] -// Change static visibility --------------------------------------------------- +// Change static visibility #[cfg(cfail1)] static STATIC_VISIBILITY: u8 = 0; @@ -26,7 +26,7 @@ static STATIC_VISIBILITY: u8 = 0; pub static STATIC_VISIBILITY: u8 = 0; -// Change static mutability --------------------------------------------------- +// Change static mutability #[cfg(cfail1)] static STATIC_MUTABILITY: u8 = 0; @@ -36,7 +36,7 @@ static STATIC_MUTABILITY: u8 = 0; static mut STATIC_MUTABILITY: u8 = 0; -// Add linkage attribute ------------------------------------------------------ +// Add linkage attribute #[cfg(cfail1)] static STATIC_LINKAGE: u8 = 0; @@ -47,7 +47,7 @@ static STATIC_LINKAGE: u8 = 0; static STATIC_LINKAGE: u8 = 0; -// Add no_mangle attribute ---------------------------------------------------- +// Add no_mangle attribute #[cfg(cfail1)] static STATIC_NO_MANGLE: u8 = 0; @@ -58,7 +58,7 @@ static STATIC_NO_MANGLE: u8 = 0; static STATIC_NO_MANGLE: u8 = 0; -// Add thread_local attribute ------------------------------------------------- +// Add thread_local attribute #[cfg(cfail1)] static STATIC_THREAD_LOCAL: u8 = 0; @@ -69,7 +69,7 @@ static STATIC_THREAD_LOCAL: u8 = 0; static STATIC_THREAD_LOCAL: u8 = 0; -// Change type from i16 to u64 ------------------------------------------------ +// Change type from i16 to u64 #[cfg(cfail1)] static STATIC_CHANGE_TYPE_1: i16 = 0; @@ -79,7 +79,7 @@ static STATIC_CHANGE_TYPE_1: i16 = 0; static STATIC_CHANGE_TYPE_1: u64 = 0; -// Change type from Option to Option --------------------------------- +// Change type from Option to Option #[cfg(cfail1)] static STATIC_CHANGE_TYPE_2: Option = None; @@ -89,7 +89,7 @@ static STATIC_CHANGE_TYPE_2: Option = None; static STATIC_CHANGE_TYPE_2: Option = None; -// Change value between simple literals --------------------------------------- +// Change value between simple literals #[rustc_clean(cfg="cfail2", except="HirBody")] #[rustc_clean(cfg="cfail3")] static STATIC_CHANGE_VALUE_1: i16 = { @@ -101,7 +101,7 @@ static STATIC_CHANGE_VALUE_1: i16 = { }; -// Change value between expressions ------------------------------------------- +// Change value between expressions #[rustc_clean(cfg="cfail2", except="HirBody")] #[rustc_clean(cfg="cfail3")] static STATIC_CHANGE_VALUE_2: i16 = { @@ -133,7 +133,7 @@ static STATIC_CHANGE_VALUE_4: i16 = { }; -// Change type indirectly ----------------------------------------------------- +// Change type indirectly struct ReferencedType1; struct ReferencedType2; diff --git a/src/test/incremental/hashes/struct_constructors.rs b/src/test/incremental/hashes/struct_constructors.rs index b708b99eabc99..456d5e74751ae 100644 --- a/src/test/incremental/hashes/struct_constructors.rs +++ b/src/test/incremental/hashes/struct_constructors.rs @@ -20,7 +20,7 @@ pub struct RegularStruct { z: i16, } -// Change field value (regular struct) ----------------------------------------- +// Change field value (regular struct) #[cfg(cfail1)] pub fn change_field_value_regular_struct() -> RegularStruct { RegularStruct { @@ -43,7 +43,7 @@ pub fn change_field_value_regular_struct() -> RegularStruct { -// Change field order (regular struct) ----------------------------------------- +// Change field order (regular struct) #[cfg(cfail1)] pub fn change_field_order_regular_struct() -> RegularStruct { RegularStruct { @@ -66,7 +66,7 @@ pub fn change_field_order_regular_struct() -> RegularStruct { -// Add field (regular struct) -------------------------------------------------- +// Add field (regular struct) #[cfg(cfail1)] pub fn add_field_regular_struct() -> RegularStruct { let struct1 = RegularStruct { @@ -100,7 +100,7 @@ pub fn add_field_regular_struct() -> RegularStruct { -// Change field label (regular struct) ----------------------------------------- +// Change field label (regular struct) #[cfg(cfail1)] pub fn change_field_label_regular_struct() -> RegularStruct { let struct1 = RegularStruct { @@ -141,7 +141,7 @@ pub struct RegularStruct2 { z: i8, } -// Change constructor path (regular struct) ------------------------------------ +// Change constructor path (regular struct) #[cfg(cfail1)] pub fn change_constructor_path_regular_struct() { let _ = RegularStruct { @@ -164,7 +164,7 @@ pub fn change_constructor_path_regular_struct() { -// Change constructor path indirectly (regular struct) ------------------------- +// Change constructor path indirectly (regular struct) pub mod change_constructor_path_indirectly_regular_struct { #[cfg(cfail1)] use super::RegularStruct as Struct; @@ -189,7 +189,7 @@ pub mod change_constructor_path_indirectly_regular_struct { pub struct TupleStruct(i32, i64, i16); -// Change field value (tuple struct) ------------------------------------------- +// Change field value (tuple struct) #[cfg(cfail1)] pub fn change_field_value_tuple_struct() -> TupleStruct { TupleStruct(0, 1, 2) @@ -206,7 +206,7 @@ pub fn change_field_value_tuple_struct() -> TupleStruct { pub struct TupleStruct2(u16, u16, u16); -// Change constructor path (tuple struct) -------------------------------------- +// Change constructor path (tuple struct) #[cfg(cfail1)] pub fn change_constructor_path_tuple_struct() { let _ = TupleStruct(0, 1, 2); @@ -221,7 +221,7 @@ pub fn change_constructor_path_tuple_struct() { -// Change constructor path indirectly (tuple struct) --------------------------- +// Change constructor path indirectly (tuple struct) pub mod change_constructor_path_indirectly_tuple_struct { #[cfg(cfail1)] use super::TupleStruct as Struct; diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs index 30b4e306820ed..3006cdccfbb55 100644 --- a/src/test/incremental/hashes/trait_defs.rs +++ b/src/test/incremental/hashes/trait_defs.rs @@ -18,10 +18,9 @@ #![feature(rustc_attrs)] #![crate_type="rlib"] #![feature(associated_type_defaults)] -#![feature(intrinsics)] -// Change trait visibility -------------------------------------------------------- +// Change trait visibility #[cfg(cfail1)] trait TraitVisibility { } @@ -32,7 +31,7 @@ pub trait TraitVisibility { } -// Change trait unsafety ---------------------------------------------------------- +// Change trait unsafety #[cfg(cfail1)] trait TraitUnsafety { } @@ -43,7 +42,7 @@ unsafe trait TraitUnsafety { } -// Add method --------------------------------------------------------------------- +// Add method #[cfg(cfail1)] trait TraitAddMethod { } @@ -57,7 +56,7 @@ pub trait TraitAddMethod { -// Change name of method ---------------------------------------------------------- +// Change name of method #[cfg(cfail1)] trait TraitChangeMethodName { fn method(); @@ -72,7 +71,7 @@ trait TraitChangeMethodName { -// Add return type to method ------------------------------------------------------ +// Add return type to method #[cfg(cfail1)] trait TraitAddReturnType { fn method(); @@ -89,7 +88,7 @@ trait TraitAddReturnType { -// Change return type of method --------------------------------------------------- +// Change return type of method #[cfg(cfail1)] trait TraitChangeReturnType { fn method() -> u32; @@ -106,7 +105,7 @@ trait TraitChangeReturnType { -// Add parameter to method -------------------------------------------------------- +// Add parameter to method #[cfg(cfail1)] trait TraitAddParameterToMethod { fn method(); @@ -123,7 +122,7 @@ trait TraitAddParameterToMethod { -// Change name of method parameter ------------------------------------------------ +// Change name of method parameter #[cfg(cfail1)] trait TraitChangeMethodParameterName { fn method(a: u32); @@ -148,7 +147,7 @@ trait TraitChangeMethodParameterName { -// Change type of method parameter (i32 => i64) ----------------------------------- +// Change type of method parameter (i32 => i64) #[cfg(cfail1)] trait TraitChangeMethodParameterType { fn method(a: i32); @@ -165,7 +164,7 @@ trait TraitChangeMethodParameterType { -// Change type of method parameter (&i32 => &mut i32) ----------------------------- +// Change type of method parameter (&i32 => &mut i32) #[cfg(cfail1)] trait TraitChangeMethodParameterTypeRef { fn method(a: &i32); @@ -182,7 +181,7 @@ trait TraitChangeMethodParameterTypeRef { -// Change order of method parameters ---------------------------------------------- +// Change order of method parameters #[cfg(cfail1)] trait TraitChangeMethodParametersOrder { fn method(a: i32, b: i64); @@ -199,7 +198,7 @@ trait TraitChangeMethodParametersOrder { -// Add default implementation to method ------------------------------------------- +// Add default implementation to method #[cfg(cfail1)] trait TraitAddMethodAutoImplementation { fn method(); @@ -216,7 +215,7 @@ trait TraitAddMethodAutoImplementation { -// Change order of methods -------------------------------------------------------- +// Change order of methods #[cfg(cfail1)] trait TraitChangeOrderOfMethods { fn method0(); @@ -233,7 +232,7 @@ trait TraitChangeOrderOfMethods { -// Change mode of self parameter -------------------------------------------------- +// Change mode of self parameter #[cfg(cfail1)] trait TraitChangeModeSelfRefToMut { fn method(&self); @@ -284,7 +283,7 @@ trait TraitChangeModeSelfOwnToRef { -// Add unsafe modifier to method -------------------------------------------------- +// Add unsafe modifier to method #[cfg(cfail1)] trait TraitAddUnsafeModifier { fn method(); @@ -301,7 +300,7 @@ trait TraitAddUnsafeModifier { -// Add extern modifier to method -------------------------------------------------- +// Add extern modifier to method #[cfg(cfail1)] trait TraitAddExternModifier { fn method(); @@ -318,7 +317,7 @@ trait TraitAddExternModifier { -// Change extern "C" to extern "rust-intrinsic" ----------------------------------- +// Change extern "C" to extern "stdcall" #[cfg(cfail1)] trait TraitChangeExternCToRustIntrinsic { extern "C" fn method(); @@ -330,12 +329,12 @@ trait TraitChangeExternCToRustIntrinsic { trait TraitChangeExternCToRustIntrinsic { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - extern "rust-intrinsic" fn method(); + extern "stdcall" fn method(); } -// Add type parameter to method --------------------------------------------------- +// Add type parameter to method #[cfg(cfail1)] trait TraitAddTypeParameterToMethod { fn method(); @@ -352,7 +351,7 @@ trait TraitAddTypeParameterToMethod { -// Add lifetime parameter to method ----------------------------------------------- +// Add lifetime parameter to method #[cfg(cfail1)] trait TraitAddLifetimeParameterToMethod { fn method(); @@ -373,7 +372,7 @@ trait TraitAddLifetimeParameterToMethod { trait ReferencedTrait0 { } trait ReferencedTrait1 { } -// Add trait bound to method type parameter --------------------------------------- +// Add trait bound to method type parameter #[cfg(cfail1)] trait TraitAddTraitBoundToMethodTypeParameter { fn method(); @@ -390,7 +389,7 @@ trait TraitAddTraitBoundToMethodTypeParameter { -// Add builtin bound to method type parameter ------------------------------------- +// Add builtin bound to method type parameter #[cfg(cfail1)] trait TraitAddBuiltinBoundToMethodTypeParameter { fn method(); @@ -407,7 +406,7 @@ trait TraitAddBuiltinBoundToMethodTypeParameter { -// Add lifetime bound to method lifetime parameter ------------------------------------ +// Add lifetime bound to method lifetime parameter #[cfg(cfail1)] trait TraitAddLifetimeBoundToMethodLifetimeParameter { fn method<'a, 'b>(a: &'a u32, b: &'b u32); @@ -424,7 +423,7 @@ trait TraitAddLifetimeBoundToMethodLifetimeParameter { -// Add second trait bound to method type parameter -------------------------------- +// Add second trait bound to method type parameter #[cfg(cfail1)] trait TraitAddSecondTraitBoundToMethodTypeParameter { fn method(); @@ -441,7 +440,7 @@ trait TraitAddSecondTraitBoundToMethodTypeParameter { -// Add second builtin bound to method type parameter ------------------------------ +// Add second builtin bound to method type parameter #[cfg(cfail1)] trait TraitAddSecondBuiltinBoundToMethodTypeParameter { fn method(); @@ -458,7 +457,7 @@ trait TraitAddSecondBuiltinBoundToMethodTypeParameter { -// Add second lifetime bound to method lifetime parameter ----------------------------- +// Add second lifetime bound to method lifetime parameter #[cfg(cfail1)] trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { fn method<'a, 'b, 'c: 'a>(a: &'a u32, b: &'b u32, c: &'c u32); @@ -475,7 +474,7 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { -// Add associated type ------------------------------------------------------------ +// Add associated type #[cfg(cfail1)] trait TraitAddAssociatedType { @@ -495,7 +494,7 @@ trait TraitAddAssociatedType { -// Add trait bound to associated type --------------------------------------------- +// Add trait bound to associated type #[cfg(cfail1)] trait TraitAddTraitBoundToAssociatedType { type Associated; @@ -519,7 +518,7 @@ trait TraitAddTraitBoundToAssociatedType { -// Add lifetime bound to associated type ------------------------------------------ +// Add lifetime bound to associated type #[cfg(cfail1)] trait TraitAddLifetimeBoundToAssociatedType<'a> { type Associated; @@ -540,7 +539,7 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> { -// Add default to associated type ------------------------------------------------- +// Add default to associated type #[cfg(cfail1)] trait TraitAddDefaultToAssociatedType { type Associated; @@ -561,7 +560,7 @@ trait TraitAddDefaultToAssociatedType { -// Add associated constant -------------------------------------------------------- +// Add associated constant #[cfg(cfail1)] trait TraitAddAssociatedConstant { fn method(); @@ -578,7 +577,7 @@ trait TraitAddAssociatedConstant { -// Add initializer to associated constant ----------------------------------------- +// Add initializer to associated constant #[cfg(cfail1)] trait TraitAddInitializerToAssociatedConstant { const Value: u32; @@ -601,7 +600,7 @@ trait TraitAddInitializerToAssociatedConstant { -// Change type of associated constant --------------------------------------------- +// Change type of associated constant #[cfg(cfail1)] trait TraitChangeTypeOfAssociatedConstant { const Value: u32; @@ -624,7 +623,7 @@ trait TraitChangeTypeOfAssociatedConstant { -// Add super trait ---------------------------------------------------------------- +// Add super trait #[cfg(cfail1)] trait TraitAddSuperTrait { } @@ -635,7 +634,7 @@ trait TraitAddSuperTrait : ReferencedTrait0 { } -// Add builtin bound (Send or Copy) ----------------------------------------------- +// Add builtin bound (Send or Copy) #[cfg(cfail1)] trait TraitAddBuiltiBound { } @@ -646,7 +645,7 @@ trait TraitAddBuiltiBound : Send { } -// Add 'static lifetime bound to trait -------------------------------------------- +// Add 'static lifetime bound to trait #[cfg(cfail1)] trait TraitAddStaticLifetimeBound { } @@ -657,7 +656,7 @@ trait TraitAddStaticLifetimeBound : 'static { } -// Add super trait as second bound ------------------------------------------------ +// Add super trait as second bound #[cfg(cfail1)] trait TraitAddTraitAsSecondBound : ReferencedTrait0 { } @@ -676,7 +675,7 @@ trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { } -// Add builtin bound as second bound ---------------------------------------------- +// Add builtin bound as second bound #[cfg(cfail1)] trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 { } @@ -695,7 +694,7 @@ trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { } -// Add 'static bounds as second bound --------------------------------------------- +// Add 'static bounds as second bound #[cfg(cfail1)] trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 { } @@ -714,7 +713,7 @@ trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { } -// Add type parameter to trait ---------------------------------------------------- +// Add type parameter to trait #[cfg(cfail1)] trait TraitAddTypeParameterToTrait { } @@ -725,7 +724,7 @@ trait TraitAddTypeParameterToTrait { } -// Add lifetime parameter to trait ------------------------------------------------ +// Add lifetime parameter to trait #[cfg(cfail1)] trait TraitAddLifetimeParameterToTrait { } @@ -736,7 +735,7 @@ trait TraitAddLifetimeParameterToTrait<'a> { } -// Add trait bound to type parameter of trait ------------------------------------- +// Add trait bound to type parameter of trait #[cfg(cfail1)] trait TraitAddTraitBoundToTypeParameterOfTrait { } @@ -747,7 +746,7 @@ trait TraitAddTraitBoundToTypeParameterOfTrait { } -// Add lifetime bound to type parameter of trait ---------------------------------- +// Add lifetime bound to type parameter of trait #[cfg(cfail1)] trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T> { } @@ -758,7 +757,7 @@ trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { } -// Add lifetime bound to lifetime parameter of trait ------------------------------ +// Add lifetime bound to lifetime parameter of trait #[cfg(cfail1)] trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a, 'b> { } @@ -769,7 +768,7 @@ trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b> { } -// Add builtin bound to type parameter of trait ----------------------------------- +// Add builtin bound to type parameter of trait #[cfg(cfail1)] trait TraitAddBuiltinBoundToTypeParameterOfTrait { } @@ -780,7 +779,7 @@ trait TraitAddBuiltinBoundToTypeParameterOfTrait { } -// Add second type parameter to trait --------------------------------------------- +// Add second type parameter to trait #[cfg(cfail1)] trait TraitAddSecondTypeParameterToTrait { } @@ -791,7 +790,7 @@ trait TraitAddSecondTypeParameterToTrait { } -// Add second lifetime parameter to trait ----------------------------------------- +// Add second lifetime parameter to trait #[cfg(cfail1)] trait TraitAddSecondLifetimeParameterToTrait<'a> { } @@ -802,7 +801,7 @@ trait TraitAddSecondLifetimeParameterToTrait<'a, 'b> { } -// Add second trait bound to type parameter of trait ------------------------------ +// Add second trait bound to type parameter of trait #[cfg(cfail1)] trait TraitAddSecondTraitBoundToTypeParameterOfTrait { } @@ -813,7 +812,7 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTrait { } @@ -824,7 +823,7 @@ trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { } -// Add second lifetime bound to lifetime parameter of trait------------------------ +// Add second lifetime bound to lifetime parameter of trait #[cfg(cfail1)] trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b, 'c> { } @@ -835,7 +834,7 @@ trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b + 'c, 'b, 'c> -// Add second builtin bound to type parameter of trait ---------------------------- +// Add second builtin bound to type parameter of trait #[cfg(cfail1)] trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait { } @@ -846,13 +845,12 @@ trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait { } -// -------------------------------------------------------------------------------- struct ReferenceType0 {} struct ReferenceType1 {} -// Add trait bound to type parameter of trait in where clause---------------------- +// Add trait bound to type parameter of trait in where clause #[cfg(cfail1)] trait TraitAddTraitBoundToTypeParameterOfTraitWhere { } @@ -863,7 +861,7 @@ trait TraitAddTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 -// Add lifetime bound to type parameter of trait in where clause------------------- +// Add lifetime bound to type parameter of trait in where clause #[cfg(cfail1)] trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> { } @@ -874,7 +872,7 @@ trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { } -// Add lifetime bound to lifetime parameter of trait in where clause--------------- +// Add lifetime bound to lifetime parameter of trait in where clause #[cfg(cfail1)] trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> { } @@ -885,7 +883,7 @@ trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> where 'a: 'b -// Add builtin bound to type parameter of trait in where clause-------------------- +// Add builtin bound to type parameter of trait in where clause #[cfg(cfail1)] trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere { } @@ -896,7 +894,7 @@ trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } -// Add second trait bound to type parameter of trait in where clause--------------- +// Add second trait bound to type parameter of trait in where clause #[cfg(cfail1)] trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 { } @@ -908,7 +906,7 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere -// Add second lifetime bound to type parameter of trait in where clause------------ +// Add second lifetime bound to type parameter of trait in where clause #[cfg(cfail1)] trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a { } @@ -919,7 +917,7 @@ trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: -// Add second lifetime bound to lifetime parameter of trait in where clause-------- +// Add second lifetime bound to lifetime parameter of trait in where clause #[cfg(cfail1)] trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b { } @@ -930,7 +928,7 @@ trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> whe -// Add second builtin bound to type parameter of trait in where clause------------- +// Add second builtin bound to type parameter of trait in where clause #[cfg(cfail1)] trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } @@ -940,7 +938,7 @@ trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send + Sync { } -// Change return type of method indirectly by modifying a use statement------------ +// Change return type of method indirectly by modifying a use statement mod change_return_type_of_method_indirectly_use { #[cfg(cfail1)] use super::ReferenceType0 as ReturnType; @@ -958,7 +956,7 @@ mod change_return_type_of_method_indirectly_use { -// Change type of method parameter indirectly by modifying a use statement--------- +// Change type of method parameter indirectly by modifying a use statement mod change_method_parameter_type_indirectly_by_use { #[cfg(cfail1)] use super::ReferenceType0 as ArgType; diff --git a/src/test/incremental/hashes/while_let_loops.rs b/src/test/incremental/hashes/while_let_loops.rs index 39b28ec190639..da3c957741fb2 100644 --- a/src/test/incremental/hashes/while_let_loops.rs +++ b/src/test/incremental/hashes/while_let_loops.rs @@ -14,7 +14,7 @@ #![crate_type="rlib"] -// Change loop body ------------------------------------------------------------ +// Change loop body #[cfg(cfail1)] pub fn change_loop_body() { let mut _x = 0; @@ -37,7 +37,7 @@ pub fn change_loop_body() { -// Change loop body ------------------------------------------------------------ +// Change loop body #[cfg(cfail1)] pub fn change_loop_condition() { let mut _x = 0; @@ -60,7 +60,7 @@ pub fn change_loop_condition() { -// Add break ------------------------------------------------------------------- +// Add break #[cfg(cfail1)] pub fn add_break() { let mut _x = 0; @@ -82,7 +82,7 @@ pub fn add_break() { -// Add loop label -------------------------------------------------------------- +// Add loop label #[cfg(cfail1)] pub fn add_loop_label() { let mut _x = 0; @@ -105,7 +105,7 @@ pub fn add_loop_label() { -// Add loop label to break ----------------------------------------------------- +// Add loop label to break #[cfg(cfail1)] pub fn add_loop_label_to_break() { let mut _x = 0; @@ -128,7 +128,7 @@ pub fn add_loop_label_to_break() { -// Change break label ---------------------------------------------------------- +// Change break label #[cfg(cfail1)] pub fn change_break_label() { let mut _x = 0; @@ -155,7 +155,7 @@ pub fn change_break_label() { -// Add loop label to continue -------------------------------------------------- +// Add loop label to continue #[cfg(cfail1)] pub fn add_loop_label_to_continue() { let mut _x = 0; @@ -178,7 +178,7 @@ pub fn add_loop_label_to_continue() { -// Change continue label ---------------------------------------------------------- +// Change continue label #[cfg(cfail1)] pub fn change_continue_label() { let mut _x = 0; @@ -205,7 +205,7 @@ pub fn change_continue_label() { -// Change continue to break ---------------------------------------------------- +// Change continue to break #[cfg(cfail1)] pub fn change_continue_to_break() { let mut _x = 0; diff --git a/src/test/incremental/hashes/while_loops.rs b/src/test/incremental/hashes/while_loops.rs index 0607218546950..3be42e7a4ee7a 100644 --- a/src/test/incremental/hashes/while_loops.rs +++ b/src/test/incremental/hashes/while_loops.rs @@ -14,7 +14,7 @@ #![crate_type="rlib"] -// Change loop body ------------------------------------------------------------ +// Change loop body #[cfg(cfail1)] pub fn change_loop_body() { let mut _x = 0; @@ -37,7 +37,7 @@ pub fn change_loop_body() { -// Change loop body ------------------------------------------------------------ +// Change loop body #[cfg(cfail1)] pub fn change_loop_condition() { let mut _x = 0; @@ -60,7 +60,7 @@ pub fn change_loop_condition() { -// Add break ------------------------------------------------------------------- +// Add break #[cfg(cfail1)] pub fn add_break() { let mut _x = 0; @@ -82,7 +82,7 @@ pub fn add_break() { -// Add loop label -------------------------------------------------------------- +// Add loop label #[cfg(cfail1)] pub fn add_loop_label() { let mut _x = 0; @@ -105,7 +105,7 @@ pub fn add_loop_label() { -// Add loop label to break ----------------------------------------------------- +// Add loop label to break #[cfg(cfail1)] pub fn add_loop_label_to_break() { let mut _x = 0; @@ -128,7 +128,7 @@ pub fn add_loop_label_to_break() { -// Change break label ---------------------------------------------------------- +// Change break label #[cfg(cfail1)] pub fn change_break_label() { let mut _x = 0; @@ -155,7 +155,7 @@ pub fn change_break_label() { -// Add loop label to continue -------------------------------------------------- +// Add loop label to continue #[cfg(cfail1)] pub fn add_loop_label_to_continue() { let mut _x = 0; @@ -178,7 +178,7 @@ pub fn add_loop_label_to_continue() { -// Change continue label ---------------------------------------------------------- +// Change continue label #[cfg(cfail1)] pub fn change_continue_label() { let mut _x = 0; @@ -205,7 +205,7 @@ pub fn change_continue_label() { -// Change continue to break ---------------------------------------------------- +// Change continue to break #[cfg(cfail1)] pub fn change_continue_to_break() { let mut _x = 0; diff --git a/src/test/mir-opt/box_expr.rs b/src/test/mir-opt/box_expr.rs index d9fa3d3d4736d..8dc6b73edf6d4 100644 --- a/src/test/mir-opt/box_expr.rs +++ b/src/test/mir-opt/box_expr.rs @@ -57,25 +57,18 @@ impl Drop for S { // } // // bb5: { -// drop(_4) -> [return: bb8, unwind: bb6]; +// StorageDead(_4); +// StorageDead(_3); +// _0 = (); +// drop(_1) -> bb8; // } -// // bb6 (cleanup): { // drop(_1) -> bb1; // } -// // bb7 (cleanup): { // drop(_4) -> bb6; // } -// // bb8: { -// StorageDead(_4); -// StorageDead(_3); -// _0 = (); -// drop(_1) -> bb9; -// } -// -// bb9: { // StorageDead(_1); // return; // } diff --git a/src/test/mir-opt/const_prop/read_immutable_static.rs b/src/test/mir-opt/const_prop/read_immutable_static.rs new file mode 100644 index 0000000000000..c2902dbd7c129 --- /dev/null +++ b/src/test/mir-opt/const_prop/read_immutable_static.rs @@ -0,0 +1,29 @@ +// compile-flags: -O + +static FOO: u8 = 2; + +fn main() { + let x = FOO + FOO; +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _2 = (FOO: u8); +// ... +// _3 = (FOO: u8); +// _1 = Add(move _2, move _3); +// ... +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _2 = const 2u8; +// ... +// _3 = const 2u8; +// _1 = Add(move _2, move _3); +// ... +// } +// END rustc.main.ConstProp.after.mir diff --git a/src/test/mir-opt/const_prop/reify_fn_ptr.rs b/src/test/mir-opt/const_prop/reify_fn_ptr.rs index 7e36b2a6b1b39..ad7f195676a68 100644 --- a/src/test/mir-opt/const_prop/reify_fn_ptr.rs +++ b/src/test/mir-opt/const_prop/reify_fn_ptr.rs @@ -16,7 +16,7 @@ fn main() { // START rustc.main.ConstProp.after.mir // bb0: { // ... -// _3 = const Scalar(AllocId(1).0x0) : fn(); +// _3 = const main; // _2 = move _3 as usize (Misc); // ... // _1 = move _2 as *const fn() (Misc); diff --git a/src/test/mir-opt/const_prop/slice_len.rs b/src/test/mir-opt/const_prop/slice_len.rs index 5babeb195a826..05595ce147c96 100644 --- a/src/test/mir-opt/const_prop/slice_len.rs +++ b/src/test/mir-opt/const_prop/slice_len.rs @@ -34,7 +34,7 @@ fn main() { // assert(const true, "index out of bounds: the len is move _7 but the index is _6") -> bb1; // } // bb1: { -// _1 = (*_2)[_6]; +// _1 = const 2u32; // ... // return; // } diff --git a/src/test/mir-opt/generator-storage-dead-unwind.rs b/src/test/mir-opt/generator-storage-dead-unwind.rs index bcdb937542716..109304d6d22cc 100644 --- a/src/test/mir-opt/generator-storage-dead-unwind.rs +++ b/src/test/mir-opt/generator-storage-dead-unwind.rs @@ -57,7 +57,7 @@ fn main() { // StorageLive(_6); // StorageLive(_7); // _7 = move _2; -// _6 = const take::(move _7) -> [return: bb9, unwind: bb8]; +// _6 = const take::(move _7) -> [return: bb7, unwind: bb9]; // } // bb3 (cleanup): { // StorageDead(_2); @@ -75,17 +75,7 @@ fn main() { // bb6: { // generator_drop; // } -// bb7 (cleanup): { -// StorageDead(_3); -// StorageDead(_2); -// drop(_1) -> bb1; -// } -// bb8 (cleanup): { -// StorageDead(_7); -// StorageDead(_6); -// goto -> bb7; -// } -// bb9: { +// bb7: { // StorageDead(_7); // StorageDead(_6); // StorageLive(_8); @@ -93,6 +83,16 @@ fn main() { // _9 = move _3; // _8 = const take::(move _9) -> [return: bb10, unwind: bb11]; // } +// bb8 (cleanup): { +// StorageDead(_3); +// StorageDead(_2); +// drop(_1) -> bb1; +// } +// bb9 (cleanup): { +// StorageDead(_7); +// StorageDead(_6); +// goto -> bb8; +// } // bb10: { // StorageDead(_9); // StorageDead(_8); @@ -104,7 +104,7 @@ fn main() { // bb11 (cleanup): { // StorageDead(_9); // StorageDead(_8); -// goto -> bb7; +// goto -> bb8; // } // bb12: { // return; diff --git a/src/test/mir-opt/match-arm-scopes.rs b/src/test/mir-opt/match-arm-scopes.rs index 18e0642eb3427..c898d3a6f168c 100644 --- a/src/test/mir-opt/match-arm-scopes.rs +++ b/src/test/mir-opt/match-arm-scopes.rs @@ -8,8 +8,6 @@ // all of the bindings for that scope. // * No drop flags are used. -#![feature(nll, bind_by_move_pattern_guards)] - fn complicated_match(cond: bool, items: (bool, bool, String)) -> i32 { match items { (false, a, s) | (a, false, s) if if cond { return 3 } else { a } => 1, diff --git a/src/test/mir-opt/no-spurious-drop-after-call.rs b/src/test/mir-opt/no-spurious-drop-after-call.rs new file mode 100644 index 0000000000000..782bc31186ca5 --- /dev/null +++ b/src/test/mir-opt/no-spurious-drop-after-call.rs @@ -0,0 +1,24 @@ +// ignore-wasm32-bare compiled with panic=abort by default + +// Test that after the call to `std::mem::drop` we do not generate a +// MIR drop of the argument. (We used to have a `DROP(_2)` in the code +// below, as part of bb3.) + +fn main() { + std::mem::drop("".to_string()); +} + +// END RUST SOURCE +// START rustc.main.ElaborateDrops.before.mir +// bb2: { +// StorageDead(_3); +// _1 = const std::mem::drop::(move _2) -> [return: bb3, unwind: bb4]; +// } +// bb3: { +// StorageDead(_2); +// StorageDead(_4); +// StorageDead(_1); +// _0 = (); +// return; +// } +// END rustc.main.ElaborateDrops.before.mir diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs index 33ee0fe61b288..db36a1fab5f21 100644 --- a/src/test/mir-opt/retag.rs +++ b/src/test/mir-opt/retag.rs @@ -1,3 +1,4 @@ +// ignore-wasm32-bare compiled with panic=abort by default // ignore-tidy-linelength // compile-flags: -Z mir-emit-retag -Z mir-opt-level=0 -Z span_free_formats @@ -11,6 +12,10 @@ impl Test { fn foo_shr<'x>(&self, x: &'x i32) -> &'x i32 { x } } +impl Drop for Test { + fn drop(&mut self) {} +} + fn main() { let mut x = 0; { @@ -60,10 +65,12 @@ fn main() { // ... // bb0: { // ... -// _3 = const Test::foo(move _4, move _6) -> bb1; +// _3 = const Test::foo(move _4, move _6) -> [return: bb2, unwind: bb3]; // } // -// bb1: { +// ... +// +// bb2: { // Retag(_3); // ... // _9 = move _3; @@ -80,25 +87,20 @@ fn main() { // _12 = move _13 as *mut i32 (Misc); // Retag([raw] _12); // ... -// _16 = move _17(move _18) -> bb2; +// _16 = move _17(move _18) -> bb5; // } // -// bb2: { +// bb5: { // Retag(_16); // ... -// _20 = const Test::foo_shr(move _21, move _23) -> bb3; -// } -// -// bb3: { -// ... -// return; +// _20 = const Test::foo_shr(move _21, move _23) -> [return: bb6, unwind: bb7]; // } // // ... // } // END rustc.main.EraseRegions.after.mir // START rustc.main-{{closure}}.EraseRegions.after.mir -// fn main::{{closure}}#0(_1: &[closure@HirId { owner: DefIndex(20), local_id: 72 }], _2: &i32) -> &i32 { +// fn main::{{closure}}#0(_1: &[closure@HirId { owner: DefIndex(22), local_id: 72 }], _2: &i32) -> &i32 { // ... // bb0: { // Retag([fn entry] _1); @@ -113,3 +115,17 @@ fn main() { // } // } // END rustc.main-{{closure}}.EraseRegions.after.mir +// START rustc.ptr-real_drop_in_place.Test.SimplifyCfg-make_shim.after.mir +// fn std::ptr::real_drop_in_place(_1: &mut Test) -> () { +// ... +// bb0: { +// Retag([raw] _1); +// _2 = &mut (*_1); +// _3 = const ::drop(move _2) -> bb1; +// } +// +// bb1: { +// return; +// } +// } +// END rustc.ptr-real_drop_in_place.Test.SimplifyCfg-make_shim.after.mir diff --git a/src/test/pretty/attr-literals.rs b/src/test/pretty/attr-literals.rs index bcd6ffaaf815b..9db7e27b16103 100644 --- a/src/test/pretty/attr-literals.rs +++ b/src/test/pretty/attr-literals.rs @@ -5,10 +5,10 @@ #![feature(rustc_attrs)] fn main() { - #![rustc_dummy("hi" , 1 , 2 , 1.012 , pi = 3.14 , bye , name ("John"))] + #![rustc_dummy("hi", 1, 2, 1.012, pi = 3.14, bye, name ("John"))] #[rustc_dummy = 8] fn f() { } - #[rustc_dummy(1 , 2 , 3)] + #[rustc_dummy(1, 2, 3)] fn g() { } } diff --git a/src/test/pretty/block-comment-wchar.pp b/src/test/pretty/block-comment-wchar.pp index f15d7cdc44ccd..9317b36ba497b 100644 --- a/src/test/pretty/block-comment-wchar.pp +++ b/src/test/pretty/block-comment-wchar.pp @@ -99,8 +99,5 @@ '\u{2004}', '\u{2005}', '\u{2006}', '\u{2007}', '\u{2008}', '\u{2009}', '\u{200A}', '\u{2028}', '\u{2029}', '\u{202F}', '\u{205F}', '\u{3000}']; - for c in &chars { - let ws = c.is_whitespace(); - println!("{} {}" , c , ws); - } + for c in &chars { let ws = c.is_whitespace(); println!("{} {}", c, ws); } } diff --git a/src/test/pretty/delimited-token-groups.rs b/src/test/pretty/delimited-token-groups.rs index 768f27ad23a8e..7bbb7dc911f93 100644 --- a/src/test/pretty/delimited-token-groups.rs +++ b/src/test/pretty/delimited-token-groups.rs @@ -5,7 +5,7 @@ macro_rules! mac { ($ ($ tt : tt) *) => () } mac! { - struct S { field1 : u8 , field2 : u16 , } impl Clone for S + struct S { field1 : u8, field2 : u16, } impl Clone for S { fn clone () -> S { diff --git a/src/test/pretty/do1.rs b/src/test/pretty/do1.rs index 7be835cb22f2d..233ccdb0098b3 100644 --- a/src/test/pretty/do1.rs +++ b/src/test/pretty/do1.rs @@ -2,4 +2,4 @@ fn f(f: F) where F: Fn(isize) { f(10) } -fn main() { f(|i| { assert_eq!(i , 10) }) } +fn main() { f(|i| { assert_eq!(i, 10) }) } diff --git a/src/test/pretty/dollar-crate.pp b/src/test/pretty/dollar-crate.pp index 3d2d949be2b2e..131cd0a67c669 100644 --- a/src/test/pretty/dollar-crate.pp +++ b/src/test/pretty/dollar-crate.pp @@ -10,9 +10,9 @@ fn main() { { - ::std::io::_print(::std::fmt::Arguments::new_v1(&["rust\n"], - &match () { - () => [], - })); + ::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"], + &match () { + () => [], + })); }; } diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index bd839d3542199..4cf2e90e635fd 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -30,7 +30,7 @@ ((::alloc::fmt::format as - for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((<::std::fmt::Arguments>::new_v1 + for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((<::core::fmt::Arguments>::new_v1 as fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments::<'_>::new_v1})((&([("test" as diff --git a/src/test/pretty/macro.rs b/src/test/pretty/macro.rs index 39677d1dc2da3..1e1e1dbfb3ea5 100644 --- a/src/test/pretty/macro.rs +++ b/src/test/pretty/macro.rs @@ -2,6 +2,6 @@ #![feature(decl_macro)] -macro mac { ($ arg : expr) => { $ arg + $ arg } } +pub(crate) macro mac { ($ arg : expr) => { $ arg + $ arg } } fn main() { } diff --git a/src/test/pretty/match-block-expr.rs b/src/test/pretty/match-block-expr.rs index 0db6574b0737f..10903e928cda8 100644 --- a/src/test/pretty/match-block-expr.rs +++ b/src/test/pretty/match-block-expr.rs @@ -2,5 +2,5 @@ fn main() { let x = match { 5 } { 1 => 5, 2 => 6, _ => 7, }; - assert_eq!(x , 7); + assert_eq!(x, 7); } diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs index 02d93238dd643..619cce685d75f 100644 --- a/src/test/pretty/stmt_expr_attributes.rs +++ b/src/test/pretty/stmt_expr_attributes.rs @@ -259,8 +259,6 @@ fn _12() { } } -///////////////// - fn foo() { } fn foo3(_: i32, _: (), _: ()) { } fn qux(_: i32) { } diff --git a/src/test/run-fail/overflowing-lsh-1.rs b/src/test/run-fail/overflowing-lsh-1.rs index c69da0f49adf1..37fbf01e487dc 100644 --- a/src/test/run-fail/overflowing-lsh-1.rs +++ b/src/test/run-fail/overflowing-lsh-1.rs @@ -2,6 +2,7 @@ // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { let _x = 1_i32 << 32; diff --git a/src/test/run-fail/overflowing-lsh-2.rs b/src/test/run-fail/overflowing-lsh-2.rs index 21659bd52393a..7b0b37dfed043 100644 --- a/src/test/run-fail/overflowing-lsh-2.rs +++ b/src/test/run-fail/overflowing-lsh-2.rs @@ -2,6 +2,7 @@ // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { let _x = 1 << -1; diff --git a/src/test/run-fail/overflowing-lsh-3.rs b/src/test/run-fail/overflowing-lsh-3.rs index 8f06cd1153354..1768a8e6d3138 100644 --- a/src/test/run-fail/overflowing-lsh-3.rs +++ b/src/test/run-fail/overflowing-lsh-3.rs @@ -2,6 +2,7 @@ // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { let _x = 1_u64 << 64; diff --git a/src/test/run-fail/overflowing-lsh-4.rs b/src/test/run-fail/overflowing-lsh-4.rs index 084c147094dee..ec304b4144e0f 100644 --- a/src/test/run-fail/overflowing-lsh-4.rs +++ b/src/test/run-fail/overflowing-lsh-4.rs @@ -5,6 +5,7 @@ // sidestep the overflow checking. #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { // this signals overflow when checking is on diff --git a/src/test/run-fail/overflowing-rsh-1.rs b/src/test/run-fail/overflowing-rsh-1.rs index 24a77da896d9e..14514540c06e1 100644 --- a/src/test/run-fail/overflowing-rsh-1.rs +++ b/src/test/run-fail/overflowing-rsh-1.rs @@ -2,6 +2,7 @@ // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { let _x = -1_i32 >> 32; diff --git a/src/test/run-fail/overflowing-rsh-2.rs b/src/test/run-fail/overflowing-rsh-2.rs index b5615cacc2055..83dcbd13d2ad8 100644 --- a/src/test/run-fail/overflowing-rsh-2.rs +++ b/src/test/run-fail/overflowing-rsh-2.rs @@ -2,6 +2,7 @@ // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { let _x = -1_i32 >> -1; diff --git a/src/test/run-fail/overflowing-rsh-3.rs b/src/test/run-fail/overflowing-rsh-3.rs index 7598e026d8139..3521c0506591c 100644 --- a/src/test/run-fail/overflowing-rsh-3.rs +++ b/src/test/run-fail/overflowing-rsh-3.rs @@ -2,6 +2,7 @@ // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { let _x = -1_i64 >> 64; diff --git a/src/test/run-fail/overflowing-rsh-4.rs b/src/test/run-fail/overflowing-rsh-4.rs index a8d3b69392a97..ed1191849e57c 100644 --- a/src/test/run-fail/overflowing-rsh-4.rs +++ b/src/test/run-fail/overflowing-rsh-4.rs @@ -5,6 +5,7 @@ // truncation does not sidestep the overflow checking. #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { // this signals overflow when checking is on diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs index ec1868f32d487..1566a153ec03c 100644 --- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs +++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs @@ -41,7 +41,7 @@ impl MetadataLoader for NoLlvmMetadataLoader { struct TheBackend; impl CodegenBackend for TheBackend { - fn metadata_loader(&self) -> Box { + fn metadata_loader(&self) -> Box { Box::new(NoLlvmMetadataLoader) } @@ -64,8 +64,7 @@ impl CodegenBackend for TheBackend { tcx: TyCtxt<'tcx>, _metadata: EncodedMetadata, _need_metadata_module: bool, - _rx: mpsc::Receiver> - ) -> Box { + ) -> Box { use rustc::hir::def_id::LOCAL_CRATE; Box::new(tcx.crate_name(LOCAL_CRATE) as Symbol) @@ -73,7 +72,7 @@ impl CodegenBackend for TheBackend { fn join_codegen_and_link( &self, - ongoing_codegen: Box, + ongoing_codegen: Box, sess: &Session, _dep_graph: &DepGraph, outputs: &OutputFilenames, @@ -98,6 +97,6 @@ impl CodegenBackend for TheBackend { /// This is the entrypoint for a hot plugged rustc_codegen_llvm #[no_mangle] -pub fn __rustc_codegen_backend() -> Box { +pub fn __rustc_codegen_backend() -> Box { Box::new(TheBackend) } diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs index afc92638fda97..e290f7fa6b13a 100644 --- a/src/test/run-make-fulldeps/issue-19371/foo.rs +++ b/src/test/run-make-fulldeps/issue-19371/foo.rs @@ -62,6 +62,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { }; interface::run_compiler(config, |compiler| { - compiler.compile().ok(); + // This runs all the passes prior to linking, too. + compiler.link().ok(); }); } diff --git a/src/test/run-make-fulldeps/issue-64319/Makefile b/src/test/run-make-fulldeps/issue-64319/Makefile new file mode 100644 index 0000000000000..b2c6b8b3cbbf2 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-64319/Makefile @@ -0,0 +1,39 @@ +-include ../tools.mk + +# Different optimization levels imply different values for `-Zshare-generics`, +# so try out a whole bunch of combinations to make sure everything is compatible +all: + # First up, try some defaults + $(RUSTC) --crate-type rlib foo.rs + $(RUSTC) --crate-type dylib bar.rs -C opt-level=3 + + # Next try mixing up some things explicitly + $(RUSTC) --crate-type rlib foo.rs -Z share-generics=no + $(RUSTC) --crate-type dylib bar.rs -Z share-generics=no + $(RUSTC) --crate-type rlib foo.rs -Z share-generics=no + $(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes + $(RUSTC) --crate-type rlib foo.rs -Z share-generics=yes + $(RUSTC) --crate-type dylib bar.rs -Z share-generics=no + $(RUSTC) --crate-type rlib foo.rs -Z share-generics=yes + $(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes + + # Now combine a whole bunch of options together + $(RUSTC) --crate-type rlib foo.rs + $(RUSTC) --crate-type dylib bar.rs + $(RUSTC) --crate-type dylib bar.rs -Z share-generics=no + $(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes + $(RUSTC) --crate-type dylib bar.rs -C opt-level=1 + $(RUSTC) --crate-type dylib bar.rs -C opt-level=1 -Z share-generics=no + $(RUSTC) --crate-type dylib bar.rs -C opt-level=1 -Z share-generics=yes + $(RUSTC) --crate-type dylib bar.rs -C opt-level=2 + $(RUSTC) --crate-type dylib bar.rs -C opt-level=2 -Z share-generics=no + $(RUSTC) --crate-type dylib bar.rs -C opt-level=2 -Z share-generics=yes + $(RUSTC) --crate-type dylib bar.rs -C opt-level=3 + $(RUSTC) --crate-type dylib bar.rs -C opt-level=3 -Z share-generics=no + $(RUSTC) --crate-type dylib bar.rs -C opt-level=3 -Z share-generics=yes + $(RUSTC) --crate-type dylib bar.rs -C opt-level=s + $(RUSTC) --crate-type dylib bar.rs -C opt-level=s -Z share-generics=no + $(RUSTC) --crate-type dylib bar.rs -C opt-level=s -Z share-generics=yes + $(RUSTC) --crate-type dylib bar.rs -C opt-level=z + $(RUSTC) --crate-type dylib bar.rs -C opt-level=z -Z share-generics=no + $(RUSTC) --crate-type dylib bar.rs -C opt-level=z -Z share-generics=yes diff --git a/src/test/run-make-fulldeps/issue-64319/bar.rs b/src/test/run-make-fulldeps/issue-64319/bar.rs new file mode 100644 index 0000000000000..3895c0b6cdbb3 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-64319/bar.rs @@ -0,0 +1,5 @@ +extern crate foo; + +pub fn bar() { + foo::foo(); +} diff --git a/src/test/run-make-fulldeps/issue-64319/foo.rs b/src/test/run-make-fulldeps/issue-64319/foo.rs new file mode 100644 index 0000000000000..c54a238e9add7 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-64319/foo.rs @@ -0,0 +1,9 @@ +pub fn foo() { + bar::(); +} + +pub fn bar() { + baz(); +} + +fn baz() {} diff --git a/src/test/run-make-fulldeps/libtest-json/Makefile b/src/test/run-make-fulldeps/libtest-json/Makefile index a0bc8cf6688bc..8339e230bbe92 100644 --- a/src/test/run-make-fulldeps/libtest-json/Makefile +++ b/src/test/run-make-fulldeps/libtest-json/Makefile @@ -2,13 +2,17 @@ # Test expected libtest's JSON output -OUTPUT_FILE := $(TMPDIR)/libtest-json-output.json +OUTPUT_FILE_DEFAULT := $(TMPDIR)/libtest-json-output-default.json +OUTPUT_FILE_STDOUT_SUCCESS := $(TMPDIR)/libtest-json-output-stdout-success.json all: $(RUSTC) --test f.rs - RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=json > $(OUTPUT_FILE) || true + RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=json > $(OUTPUT_FILE_DEFAULT) || true + RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=json --show-output > $(OUTPUT_FILE_STDOUT_SUCCESS) || true - cat $(OUTPUT_FILE) | "$(PYTHON)" validate_json.py + cat $(OUTPUT_FILE_DEFAULT) | "$(PYTHON)" validate_json.py + cat $(OUTPUT_FILE_STDOUT_SUCCESS) | "$(PYTHON)" validate_json.py # Compare to output file - diff output.json $(OUTPUT_FILE) + diff output-default.json $(OUTPUT_FILE_DEFAULT) + diff output-stdout-success.json $(OUTPUT_FILE_STDOUT_SUCCESS) diff --git a/src/test/run-make-fulldeps/libtest-json/f.rs b/src/test/run-make-fulldeps/libtest-json/f.rs index f5e44c2c24407..95ff36bd764ec 100644 --- a/src/test/run-make-fulldeps/libtest-json/f.rs +++ b/src/test/run-make-fulldeps/libtest-json/f.rs @@ -1,11 +1,12 @@ #[test] fn a() { + println!("print from successful test"); // Should pass } #[test] fn b() { - assert!(false) + assert!(false); } #[test] diff --git a/src/test/run-make-fulldeps/libtest-json/output.json b/src/test/run-make-fulldeps/libtest-json/output-default.json similarity index 91% rename from src/test/run-make-fulldeps/libtest-json/output.json rename to src/test/run-make-fulldeps/libtest-json/output-default.json index 0caf268aa007f..8046d72221703 100644 --- a/src/test/run-make-fulldeps/libtest-json/output.json +++ b/src/test/run-make-fulldeps/libtest-json/output-default.json @@ -2,7 +2,7 @@ { "type": "test", "event": "started", "name": "a" } { "type": "test", "name": "a", "event": "ok" } { "type": "test", "event": "started", "name": "b" } -{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:8:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.\n" } +{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:9:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.\n" } { "type": "test", "event": "started", "name": "c" } { "type": "test", "name": "c", "event": "ok" } { "type": "test", "event": "started", "name": "d" } diff --git a/src/test/run-make-fulldeps/libtest-json/output-stdout-success.json b/src/test/run-make-fulldeps/libtest-json/output-stdout-success.json new file mode 100644 index 0000000000000..303316278d8ab --- /dev/null +++ b/src/test/run-make-fulldeps/libtest-json/output-stdout-success.json @@ -0,0 +1,10 @@ +{ "type": "suite", "event": "started", "test_count": 4 } +{ "type": "test", "event": "started", "name": "a" } +{ "type": "test", "name": "a", "event": "ok", "stdout": "print from successful test\n" } +{ "type": "test", "event": "started", "name": "b" } +{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:9:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.\n" } +{ "type": "test", "event": "started", "name": "c" } +{ "type": "test", "name": "c", "event": "ok", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:15:5\n" } +{ "type": "test", "event": "started", "name": "d" } +{ "type": "test", "name": "d", "event": "ignored" } +{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "allowed_fail": 0, "ignored": 1, "measured": 0, "filtered_out": 0 } diff --git a/src/test/run-make-fulldeps/linker-output-non-utf8/Makefile b/src/test/run-make-fulldeps/linker-output-non-utf8/Makefile deleted file mode 100644 index b47ce17ec8baa..0000000000000 --- a/src/test/run-make-fulldeps/linker-output-non-utf8/Makefile +++ /dev/null @@ -1,23 +0,0 @@ --include ../tools.mk - -# Make sure we don't ICE if the linker prints a non-UTF-8 error message. - -# ignore-windows -# -# This does not work in its current form on windows, possibly due to -# gcc bugs or something about valid Windows paths. See issue #29151 -# for more information. - -# ignore-macos -# -# This also does not work on Apple APFS due to the filesystem requiring -# valid UTF-8 paths. - -# The zzz it to allow humans to tab complete or glob this thing. -bad_dir := $(TMPDIR)/zzz$$'\xff' - -all: - $(RUSTC) library.rs - mkdir $(bad_dir) - mv $(TMPDIR)/liblibrary.a $(bad_dir) - $(RUSTC) -L $(bad_dir) exec.rs 2>&1 | $(CGREP) this_symbol_not_defined diff --git a/src/test/run-make-fulldeps/linker-output-non-utf8/exec.rs b/src/test/run-make-fulldeps/linker-output-non-utf8/exec.rs deleted file mode 100644 index 6864018d64e97..0000000000000 --- a/src/test/run-make-fulldeps/linker-output-non-utf8/exec.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[link(name="library")] -extern "C" { - fn foo(); -} - -fn main() { unsafe { foo(); } } diff --git a/src/test/run-make-fulldeps/linker-output-non-utf8/library.rs b/src/test/run-make-fulldeps/linker-output-non-utf8/library.rs deleted file mode 100644 index 6689a82fa2c49..0000000000000 --- a/src/test/run-make-fulldeps/linker-output-non-utf8/library.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![crate_type = "staticlib"] - -extern "C" { - fn this_symbol_not_defined(); -} - -#[no_mangle] -pub extern "C" fn foo() { - unsafe { this_symbol_not_defined(); } -} diff --git a/src/test/run-make-fulldeps/lto-empty/Makefile b/src/test/run-make-fulldeps/lto-empty/Makefile new file mode 100644 index 0000000000000..345d10bc4b9ea --- /dev/null +++ b/src/test/run-make-fulldeps/lto-empty/Makefile @@ -0,0 +1,12 @@ +-include ../tools.mk + +all: cdylib-fat cdylib-thin + +cdylib-fat: + $(RUSTC) lib.rs -C lto=fat -C opt-level=3 -C incremental=$(TMPDIR)/inc-fat + $(RUSTC) lib.rs -C lto=fat -C opt-level=3 -C incremental=$(TMPDIR)/inc-fat + +cdylib-thin: + $(RUSTC) lib.rs -C lto=thin -C opt-level=3 -C incremental=$(TMPDIR)/inc-thin + $(RUSTC) lib.rs -C lto=thin -C opt-level=3 -C incremental=$(TMPDIR)/inc-thin + diff --git a/src/test/run-make-fulldeps/lto-empty/lib.rs b/src/test/run-make-fulldeps/lto-empty/lib.rs new file mode 100644 index 0000000000000..e3663c79078f4 --- /dev/null +++ b/src/test/run-make-fulldeps/lto-empty/lib.rs @@ -0,0 +1 @@ +#![crate_type = "cdylib"] diff --git a/src/test/run-make-fulldeps/reproducible-build-2/Makefile b/src/test/run-make-fulldeps/reproducible-build-2/Makefile new file mode 100644 index 0000000000000..45c9a7427230b --- /dev/null +++ b/src/test/run-make-fulldeps/reproducible-build-2/Makefile @@ -0,0 +1,26 @@ +-include ../tools.mk + +# ignore-musl +# ignore-windows +# Objects are reproducible but their path is not. + +all: \ + fat_lto \ + sysroot + +fat_lto: + rm -rf $(TMPDIR) && mkdir $(TMPDIR) + $(RUSTC) reproducible-build-aux.rs + $(RUSTC) reproducible-build.rs -C lto=fat + cp $(TMPDIR)/reproducible-build $(TMPDIR)/reproducible-build-a + $(RUSTC) reproducible-build.rs -C lto=fat + cmp "$(TMPDIR)/reproducible-build-a" "$(TMPDIR)/reproducible-build" || exit 1 + +sysroot: + rm -rf $(TMPDIR) && mkdir $(TMPDIR) + $(RUSTC) reproducible-build-aux.rs + $(RUSTC) reproducible-build.rs --crate-type rlib --sysroot $(shell $(RUSTC) --print sysroot) --remap-path-prefix=$(shell $(RUSTC) --print sysroot)=/sysroot + cp -r $(shell $(RUSTC) --print sysroot) $(TMPDIR)/sysroot + cp $(TMPDIR)/libreproducible_build.rlib $(TMPDIR)/libfoo.rlib + $(RUSTC) reproducible-build.rs --crate-type rlib --sysroot $(TMPDIR)/sysroot --remap-path-prefix=$(TMPDIR)/sysroot=/sysroot + cmp "$(TMPDIR)/libreproducible_build.rlib" "$(TMPDIR)/libfoo.rlib" || exit 1 diff --git a/src/test/run-make-fulldeps/reproducible-build-2/linker.rs b/src/test/run-make-fulldeps/reproducible-build-2/linker.rs new file mode 100644 index 0000000000000..998d1f328596c --- /dev/null +++ b/src/test/run-make-fulldeps/reproducible-build-2/linker.rs @@ -0,0 +1,44 @@ +use std::env; +use std::path::Path; +use std::fs::File; +use std::io::{Read, Write}; + +fn main() { + let mut dst = env::current_exe().unwrap(); + dst.pop(); + dst.push("linker-arguments1"); + if dst.exists() { + dst.pop(); + dst.push("linker-arguments2"); + assert!(!dst.exists()); + } + + let mut out = String::new(); + for arg in env::args().skip(1) { + let path = Path::new(&arg); + if !path.is_file() { + out.push_str(&arg); + out.push_str("\n"); + continue + } + + let mut contents = Vec::new(); + File::open(path).unwrap().read_to_end(&mut contents).unwrap(); + + out.push_str(&format!("{}: {}\n", arg, hash(&contents))); + } + + File::create(dst).unwrap().write_all(out.as_bytes()).unwrap(); +} + +// fnv hash for now +fn hash(contents: &[u8]) -> u64 { + let mut hash = 0xcbf29ce484222325; + + for byte in contents { + hash = hash ^ (*byte as u64); + hash = hash.wrapping_mul(0x100000001b3); + } + + hash +} diff --git a/src/test/run-make-fulldeps/reproducible-build-2/reproducible-build-aux.rs b/src/test/run-make-fulldeps/reproducible-build-2/reproducible-build-aux.rs new file mode 100644 index 0000000000000..8105b3d2bda3d --- /dev/null +++ b/src/test/run-make-fulldeps/reproducible-build-2/reproducible-build-aux.rs @@ -0,0 +1,28 @@ +#![crate_type="lib"] + +pub static STATIC: i32 = 1234; + +pub struct Struct { + _t1: std::marker::PhantomData, + _t2: std::marker::PhantomData, +} + +pub fn regular_fn(_: i32) {} + +pub fn generic_fn() {} + +impl Drop for Struct { + fn drop(&mut self) {} +} + +pub enum Enum { + Variant1, + Variant2(u32), + Variant3 { x: u32 } +} + +pub struct TupleStruct(pub i8, pub i16, pub i32, pub i64); + +pub trait Trait { + fn foo(&self); +} diff --git a/src/test/run-make-fulldeps/reproducible-build-2/reproducible-build.rs b/src/test/run-make-fulldeps/reproducible-build-2/reproducible-build.rs new file mode 100644 index 0000000000000..a6c04774c869a --- /dev/null +++ b/src/test/run-make-fulldeps/reproducible-build-2/reproducible-build.rs @@ -0,0 +1,116 @@ +// This test case makes sure that two identical invocations of the compiler +// (i.e., same code base, same compile-flags, same compiler-versions, etc.) +// produce the same output. In the past, symbol names of monomorphized functions +// were not deterministic (which we want to avoid). +// +// The test tries to exercise as many different paths into symbol name +// generation as possible: +// +// - regular functions +// - generic functions +// - methods +// - statics +// - closures +// - enum variant constructors +// - tuple struct constructors +// - drop glue +// - FnOnce adapters +// - Trait object shims +// - Fn Pointer shims + +#![allow(dead_code, warnings)] + +extern crate reproducible_build_aux; + +static STATIC: i32 = 1234; + +pub struct Struct { + x: T1, + y: T2, +} + +fn regular_fn(_: i32) {} + +fn generic_fn() {} + +impl Drop for Struct { + fn drop(&mut self) {} +} + +pub enum Enum { + Variant1, + Variant2(u32), + Variant3 { x: u32 } +} + +struct TupleStruct(i8, i16, i32, i64); + +impl TupleStruct { + pub fn bar(&self) {} +} + +trait Trait { + fn foo(&self); +} + +impl Trait for u64 { + fn foo(&self) {} +} + +impl reproducible_build_aux::Trait for TupleStruct { + fn foo(&self) {} +} + +fn main() { + regular_fn(STATIC); + generic_fn::(); + generic_fn::>(); + generic_fn::, reproducible_build_aux::Struct>(); + + let dropped = Struct { + x: "", + y: 'a', + }; + + let _ = Enum::Variant1; + let _ = Enum::Variant2(0); + let _ = Enum::Variant3 { x: 0 }; + let _ = TupleStruct(1, 2, 3, 4); + + let closure = |x| { + x + 1i32 + }; + + fn inner i32>(f: F) -> i32 { + f(STATIC) + } + + println!("{}", inner(closure)); + + let object_shim: &Trait = &0u64; + object_shim.foo(); + + fn with_fn_once_adapter(f: F) { + f(0); + } + + with_fn_once_adapter(|_:i32| { }); + + reproducible_build_aux::regular_fn(STATIC); + reproducible_build_aux::generic_fn::(); + reproducible_build_aux::generic_fn::>(); + reproducible_build_aux::generic_fn::, + reproducible_build_aux::Struct>(); + + let _ = reproducible_build_aux::Enum::Variant1; + let _ = reproducible_build_aux::Enum::Variant2(0); + let _ = reproducible_build_aux::Enum::Variant3 { x: 0 }; + let _ = reproducible_build_aux::TupleStruct(1, 2, 3, 4); + + let object_shim: &reproducible_build_aux::Trait = &TupleStruct(0, 1, 2, 3); + object_shim.foo(); + + let pointer_shim: &Fn(i32) = ®ular_fn; + + TupleStruct(1, 2, 3, 4).bar(); +} diff --git a/src/test/run-make-fulldeps/symbol-visibility/Makefile b/src/test/run-make-fulldeps/symbol-visibility/Makefile index 7901866015bf2..840fe801a953c 100644 --- a/src/test/run-make-fulldeps/symbol-visibility/Makefile +++ b/src/test/run-make-fulldeps/symbol-visibility/Makefile @@ -79,12 +79,12 @@ all: # Check that a Rust dylib exports its monomorphic functions, including generics this time [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rust_dylib)" -eq "1" ] [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rust_dylib)" -eq "1" ] - [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rust_dylib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rust_dylib)" -eq "0" ] # Check that a Rust dylib exports the monomorphic functions from its dependencies [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rlib)" -eq "1" ] - [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rlib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rlib)" -eq "0" ] # Check that an executable does not export any dynamic symbols [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ] diff --git a/src/test/run-make-fulldeps/tools.mk b/src/test/run-make-fulldeps/tools.mk index 3b4df73cdfd6d..9a113b7fa6370 100644 --- a/src/test/run-make-fulldeps/tools.mk +++ b/src/test/run-make-fulldeps/tools.mk @@ -12,7 +12,7 @@ RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) $(RUSTFLAGS) RUSTDOC := $(BARE_RUSTDOC) -L $(TARGET_RPATH_DIR) ifdef RUSTC_LINKER RUSTC := $(RUSTC) -Clinker=$(RUSTC_LINKER) -RUSTDOC := $(RUSTDOC) --linker $(RUSTC_LINKER) -Z unstable-options +RUSTDOC := $(RUSTDOC) -Clinker=$(RUSTC_LINKER) endif #CC := $(CC) -L $(TMPDIR) HTMLDOCCK := $(PYTHON) $(S)/src/etc/htmldocck.py diff --git a/src/test/run-pass-valgrind/cast-enum-with-dtor.rs b/src/test/run-pass-valgrind/cast-enum-with-dtor.rs index 42445b9056f9d..93c47d32f92a1 100644 --- a/src/test/run-pass-valgrind/cast-enum-with-dtor.rs +++ b/src/test/run-pass-valgrind/cast-enum-with-dtor.rs @@ -1,5 +1,3 @@ -// no-prefer-dynamic - #![allow(dead_code)] // check dtor calling order when casting enums. diff --git a/src/test/run-pass-valgrind/cleanup-auto-borrow-obj.rs b/src/test/run-pass-valgrind/cleanup-auto-borrow-obj.rs index 925ffe75fe785..fb2b4d476355e 100644 --- a/src/test/run-pass-valgrind/cleanup-auto-borrow-obj.rs +++ b/src/test/run-pass-valgrind/cleanup-auto-borrow-obj.rs @@ -1,5 +1,3 @@ -// no-prefer-dynamic - // This would previously leak the Box because we wouldn't // schedule cleanups when auto borrowing trait objects. // This program should be valgrind clean. diff --git a/src/test/run-pass-valgrind/cleanup-stdin.rs b/src/test/run-pass-valgrind/cleanup-stdin.rs index 3505074293264..cf8f81cf5aa7c 100644 --- a/src/test/run-pass-valgrind/cleanup-stdin.rs +++ b/src/test/run-pass-valgrind/cleanup-stdin.rs @@ -1,5 +1,3 @@ -// no-prefer-dynamic - fn main() { let _ = std::io::stdin(); let _ = std::io::stdout(); diff --git a/src/test/run-pass-valgrind/down-with-thread-dtors.rs b/src/test/run-pass-valgrind/down-with-thread-dtors.rs index c3567a9b20097..8531b8d832604 100644 --- a/src/test/run-pass-valgrind/down-with-thread-dtors.rs +++ b/src/test/run-pass-valgrind/down-with-thread-dtors.rs @@ -1,4 +1,3 @@ -// no-prefer-dynamic // ignore-emscripten thread_local!(static FOO: Foo = Foo); diff --git a/src/test/run-pass-valgrind/dst-dtor-1.rs b/src/test/run-pass-valgrind/dst-dtor-1.rs index 7533a7bd2353b..5b8433f614567 100644 --- a/src/test/run-pass-valgrind/dst-dtor-1.rs +++ b/src/test/run-pass-valgrind/dst-dtor-1.rs @@ -1,5 +1,3 @@ -// no-prefer-dynamic - static mut DROP_RAN: bool = false; struct Foo; diff --git a/src/test/run-pass-valgrind/dst-dtor-2.rs b/src/test/run-pass-valgrind/dst-dtor-2.rs index ebf0c17fecb56..991fe00950bba 100644 --- a/src/test/run-pass-valgrind/dst-dtor-2.rs +++ b/src/test/run-pass-valgrind/dst-dtor-2.rs @@ -1,5 +1,3 @@ -// no-prefer-dynamic - static mut DROP_RAN: isize = 0; struct Foo; diff --git a/src/test/run-pass-valgrind/dst-dtor-3.rs b/src/test/run-pass-valgrind/dst-dtor-3.rs index e15908dfcc31f..f0c2dda5ab05b 100644 --- a/src/test/run-pass-valgrind/dst-dtor-3.rs +++ b/src/test/run-pass-valgrind/dst-dtor-3.rs @@ -1,5 +1,3 @@ -// no-prefer-dynamic - #![feature(unsized_tuple_coercion)] static mut DROP_RAN: bool = false; diff --git a/src/test/run-pass-valgrind/dst-dtor-4.rs b/src/test/run-pass-valgrind/dst-dtor-4.rs index 52bf0c364b24d..ad6d46f7c0886 100644 --- a/src/test/run-pass-valgrind/dst-dtor-4.rs +++ b/src/test/run-pass-valgrind/dst-dtor-4.rs @@ -1,5 +1,3 @@ -// no-prefer-dynamic - #![feature(unsized_tuple_coercion)] static mut DROP_RAN: isize = 0; diff --git a/src/test/run-pass-valgrind/exit-flushes.rs b/src/test/run-pass-valgrind/exit-flushes.rs index cd5edb84bdfe4..a68c6f3355644 100644 --- a/src/test/run-pass-valgrind/exit-flushes.rs +++ b/src/test/run-pass-valgrind/exit-flushes.rs @@ -1,4 +1,3 @@ -// no-prefer-dynamic // ignore-cloudabi // ignore-emscripten // ignore-sgx no processes diff --git a/src/test/run-pass-valgrind/osx-frameworks.rs b/src/test/run-pass-valgrind/osx-frameworks.rs index 4ea804a184474..ea1403645a515 100644 --- a/src/test/run-pass-valgrind/osx-frameworks.rs +++ b/src/test/run-pass-valgrind/osx-frameworks.rs @@ -1,4 +1,3 @@ -// no-prefer-dynamic // pretty-expanded FIXME #23616 #![feature(rustc_private)] diff --git a/src/test/rustdoc-js-std/vec-new.js b/src/test/rustdoc-js-std/vec-new.js index e4daa5065d233..e1a3256876bde 100644 --- a/src/test/rustdoc-js-std/vec-new.js +++ b/src/test/rustdoc-js-std/vec-new.js @@ -4,5 +4,6 @@ const EXPECTED = { 'others': [ { 'path': 'std::vec::Vec', 'name': 'new' }, { 'path': 'std::vec::Vec', 'name': 'ne' }, + { 'path': 'std::rc::Rc', 'name': 'ne' }, ], }; diff --git a/src/test/rustdoc-js/exact-match.js b/src/test/rustdoc-js/exact-match.js new file mode 100644 index 0000000000000..b0a411bee5829 --- /dev/null +++ b/src/test/rustdoc-js/exact-match.js @@ -0,0 +1,9 @@ +const QUERY = 'si::pc'; + +const EXPECTED = { + 'others': [ + { 'path': 'exact_match::Si', 'name': 'pc' }, + { 'path': 'exact_match::Psi', 'name': 'pc' }, + { 'path': 'exact_match::Si', 'name': 'pa' }, + ], +}; diff --git a/src/test/rustdoc-js/exact-match.rs b/src/test/rustdoc-js/exact-match.rs new file mode 100644 index 0000000000000..2eacc0a358284 --- /dev/null +++ b/src/test/rustdoc-js/exact-match.rs @@ -0,0 +1,68 @@ +macro_rules! imp { + ($name:ident) => { + pub struct $name { + pub op: usize, + } + impl $name { + pub fn op() {} + pub fn cmp() {} + pub fn map() {} + pub fn pop() {} + pub fn ptr() {} + pub fn rpo() {} + pub fn drop() {} + pub fn copy() {} + pub fn zip() {} + pub fn sup() {} + pub fn pa() {} + pub fn pb() {} + pub fn pc() {} + pub fn pd() {} + pub fn pe() {} + pub fn pf() {} + pub fn pg() {} + pub fn ph() {} + pub fn pi() {} + pub fn pj() {} + pub fn pk() {} + pub fn pl() {} + pub fn pm() {} + pub fn pn() {} + pub fn po() {} + } + }; + ($name:ident, $($names:ident),*) => { + imp!($name); + imp!($($names),*); + }; +} +macro_rules! en { + ($name:ident) => { + pub enum $name { + Ptr, + Rp, + Rpo, + Pt, + Drop, + Dr, + Dro, + Sup, + Op, + Cmp, + Map, + Mp, + } + }; + ($name:ident, $($names:ident),*) => { + en!($name); + en!($($names),*); + }; +} + +imp!(Ot, Foo, Cmp, Map, Loc, Lac, Toc, Si, Sig, Sip, Psy, Psi, Py, Pi, Pa, Pb, Pc, Pd); +imp!(Pe, Pf, Pg, Ph, Pj, Pk, Pl, Pm, Pn, Po, Pq, Pr, Ps, Pt, Pu, Pv, Pw, Px, Pz, Ap, Bp, Cp); +imp!(Dp, Ep, Fp, Gp, Hp, Ip, Jp, Kp, Lp, Mp, Np, Op, Pp, Qp, Rp, Sp, Tp, Up, Vp, Wp, Xp, Yp, Zp); + +en!(Place, Plac, Plae, Plce, Pace, Scalar, Scalr, Scaar, Sclar, Salar); + +pub struct P; diff --git a/src/test/rustdoc-js/module-substring.js b/src/test/rustdoc-js/module-substring.js new file mode 100644 index 0000000000000..a446c39ebad57 --- /dev/null +++ b/src/test/rustdoc-js/module-substring.js @@ -0,0 +1,9 @@ +const QUERY = 'ig::pc'; + +const EXPECTED = { + 'others': [ + { 'path': 'module_substring::Sig', 'name': 'pc' }, + { 'path': 'module_substring::Si', 'name': 'pc' }, + { 'path': 'module_substring::Si', 'name': 'pa' }, + ], +}; diff --git a/src/test/rustdoc-js/module-substring.rs b/src/test/rustdoc-js/module-substring.rs new file mode 100644 index 0000000000000..2eacc0a358284 --- /dev/null +++ b/src/test/rustdoc-js/module-substring.rs @@ -0,0 +1,68 @@ +macro_rules! imp { + ($name:ident) => { + pub struct $name { + pub op: usize, + } + impl $name { + pub fn op() {} + pub fn cmp() {} + pub fn map() {} + pub fn pop() {} + pub fn ptr() {} + pub fn rpo() {} + pub fn drop() {} + pub fn copy() {} + pub fn zip() {} + pub fn sup() {} + pub fn pa() {} + pub fn pb() {} + pub fn pc() {} + pub fn pd() {} + pub fn pe() {} + pub fn pf() {} + pub fn pg() {} + pub fn ph() {} + pub fn pi() {} + pub fn pj() {} + pub fn pk() {} + pub fn pl() {} + pub fn pm() {} + pub fn pn() {} + pub fn po() {} + } + }; + ($name:ident, $($names:ident),*) => { + imp!($name); + imp!($($names),*); + }; +} +macro_rules! en { + ($name:ident) => { + pub enum $name { + Ptr, + Rp, + Rpo, + Pt, + Drop, + Dr, + Dro, + Sup, + Op, + Cmp, + Map, + Mp, + } + }; + ($name:ident, $($names:ident),*) => { + en!($name); + en!($($names),*); + }; +} + +imp!(Ot, Foo, Cmp, Map, Loc, Lac, Toc, Si, Sig, Sip, Psy, Psi, Py, Pi, Pa, Pb, Pc, Pd); +imp!(Pe, Pf, Pg, Ph, Pj, Pk, Pl, Pm, Pn, Po, Pq, Pr, Ps, Pt, Pu, Pv, Pw, Px, Pz, Ap, Bp, Cp); +imp!(Dp, Ep, Fp, Gp, Hp, Ip, Jp, Kp, Lp, Mp, Np, Op, Pp, Qp, Rp, Sp, Tp, Up, Vp, Wp, Xp, Yp, Zp); + +en!(Place, Plac, Plae, Plce, Pace, Scalar, Scalr, Scaar, Sclar, Salar); + +pub struct P; diff --git a/src/test/rustdoc-js/search-short-types.js b/src/test/rustdoc-js/search-short-types.js index 0ebf4860cfa58..d14672af71fd6 100644 --- a/src/test/rustdoc-js/search-short-types.js +++ b/src/test/rustdoc-js/search-short-types.js @@ -3,6 +3,8 @@ const QUERY = 'P'; const EXPECTED = { 'others': [ { 'path': 'search_short_types', 'name': 'P' }, + { 'path': 'search_short_types::VeryLongTypeName', 'name': 'p' }, { 'path': 'search_short_types', 'name': 'Ap' }, + { 'path': 'search_short_types::VeryLongTypeName', 'name': 'ap' }, ], }; diff --git a/src/test/rustdoc-js/search-short-types.rs b/src/test/rustdoc-js/search-short-types.rs index 2eacc0a358284..a4083f9a76401 100644 --- a/src/test/rustdoc-js/search-short-types.rs +++ b/src/test/rustdoc-js/search-short-types.rs @@ -66,3 +66,9 @@ imp!(Dp, Ep, Fp, Gp, Hp, Ip, Jp, Kp, Lp, Mp, Np, Op, Pp, Qp, Rp, Sp, Tp, Up, Vp, en!(Place, Plac, Plae, Plce, Pace, Scalar, Scalr, Scaar, Sclar, Salar); pub struct P; + +pub struct VeryLongTypeName; +impl VeryLongTypeName { + pub fn p() {} + pub fn ap() {} +} diff --git a/src/test/rustdoc-ui/doc-test-doctest-feature.rs b/src/test/rustdoc-ui/doc-test-doctest-feature.rs new file mode 100644 index 0000000000000..984d49b43efd0 --- /dev/null +++ b/src/test/rustdoc-ui/doc-test-doctest-feature.rs @@ -0,0 +1,15 @@ +// build-pass +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" + +#![feature(cfg_doctest)] + +// Make sure `cfg(doctest)` is set when finding doctests but not inside +// the doctests. + +/// ``` +/// #![feature(cfg_doctest)] +/// assert!(!cfg!(doctest)); +/// ``` +#[cfg(doctest)] +pub struct Foo; diff --git a/src/test/rustdoc-ui/doc-test-doctest-feature.stdout b/src/test/rustdoc-ui/doc-test-doctest-feature.stdout new file mode 100644 index 0000000000000..75d29fab17d0d --- /dev/null +++ b/src/test/rustdoc-ui/doc-test-doctest-feature.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/doc-test-doctest-feature.rs - Foo (line 10) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + diff --git a/src/test/rustdoc-ui/doc-test-rustdoc-feature.rs b/src/test/rustdoc-ui/doc-test-rustdoc-feature.rs new file mode 100644 index 0000000000000..d0ead4136575f --- /dev/null +++ b/src/test/rustdoc-ui/doc-test-rustdoc-feature.rs @@ -0,0 +1,14 @@ +// build-pass +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" + +#![feature(doc_cfg)] + +// Make sure `cfg(rustdoc)` is set when finding doctests but not inside the doctests. + +/// ``` +/// #![feature(doc_cfg)] +/// assert!(!cfg!(rustdoc)); +/// ``` +#[cfg(rustdoc)] +pub struct Foo; diff --git a/src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout b/src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout new file mode 100644 index 0000000000000..f2525c2dbec21 --- /dev/null +++ b/src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/doc-test-rustdoc-feature.rs - Foo (line 9) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + diff --git a/src/test/rustdoc-ui/failed-doctest-output.rs b/src/test/rustdoc-ui/failed-doctest-output.rs index d2cdeb8f8f50e..fcbd7cabc6900 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.rs +++ b/src/test/rustdoc-ui/failed-doctest-output.rs @@ -3,6 +3,7 @@ // adapted to use that, and that normalize line can go away // compile-flags:--test +// rustc-env:RUST_BACKTRACE=0 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" // failure-status: 101 diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout index e362ecf349e45..ef1b419f52895 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.stdout +++ b/src/test/rustdoc-ui/failed-doctest-output.stdout @@ -1,13 +1,13 @@ running 2 tests -test $DIR/failed-doctest-output.rs - OtherStruct (line 20) ... FAILED -test $DIR/failed-doctest-output.rs - SomeStruct (line 10) ... FAILED +test $DIR/failed-doctest-output.rs - OtherStruct (line 21) ... FAILED +test $DIR/failed-doctest-output.rs - SomeStruct (line 11) ... FAILED failures: ----- $DIR/failed-doctest-output.rs - OtherStruct (line 20) stdout ---- +---- $DIR/failed-doctest-output.rs - OtherStruct (line 21) stdout ---- error[E0425]: cannot find value `no` in this scope - --> $DIR/failed-doctest-output.rs:21:1 + --> $DIR/failed-doctest-output.rs:22:1 | 3 | no | ^^ not found in this scope @@ -16,7 +16,7 @@ error: aborting due to previous error For more information about this error, try `rustc --explain E0425`. Couldn't compile the test. ----- $DIR/failed-doctest-output.rs - SomeStruct (line 10) stdout ---- +---- $DIR/failed-doctest-output.rs - SomeStruct (line 11) stdout ---- Test executable failed (exit code 101). stdout: @@ -32,8 +32,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. failures: - $DIR/failed-doctest-output.rs - OtherStruct (line 20) - $DIR/failed-doctest-output.rs - SomeStruct (line 10) + $DIR/failed-doctest-output.rs - OtherStruct (line 21) + $DIR/failed-doctest-output.rs - SomeStruct (line 11) test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/src/test/rustdoc-ui/invalid-syntax.rs b/src/test/rustdoc-ui/invalid-syntax.rs index 2b02d47d4b851..97a0f4aaec1eb 100644 --- a/src/test/rustdoc-ui/invalid-syntax.rs +++ b/src/test/rustdoc-ui/invalid-syntax.rs @@ -64,3 +64,21 @@ pub fn blargh() {} /// \_ #[doc = "```"] pub fn crazy_attrs() {} + +/// ```rust +/// ``` +pub fn empty_rust() {} + +/// ``` +/// +/// +/// ``` +pub fn empty_rust_with_whitespace() {} + +/// ``` +/// let x = 1; +/// ``` +/// +/// \____/ +/// +pub fn indent_after_fenced() {} diff --git a/src/test/rustdoc-ui/invalid-syntax.stderr b/src/test/rustdoc-ui/invalid-syntax.stderr index 3bebbecb9dfcf..6f50edae65034 100644 --- a/src/test/rustdoc-ui/invalid-syntax.stderr +++ b/src/test/rustdoc-ui/invalid-syntax.stderr @@ -179,6 +179,46 @@ LL | | #[doc = "```"] | = help: mark blocks that do not contain Rust code as text: ```text +warning: Rust code block is empty + --> $DIR/invalid-syntax.rs:68:5 + | +LL | /// ```rust + | _____^ +LL | | /// ``` + | |_______^ + +warning: Rust code block is empty + --> $DIR/invalid-syntax.rs:72:5 + | +LL | /// ``` + | _____^ +LL | | /// +LL | | /// +LL | | /// ``` + | |_______^ +help: mark blocks that do not contain Rust code as text + | +LL | /// ```text + | ^^^^^^^ + +error: unknown start of token: \ + --> :1:1 + | +1 | \____/ + | ^ + +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:82:9 + | +LL | /// \____/ + | ^^^^^^ + +error: unknown start of token: \ + --> :1:1 + | +1 | \____/ + | ^ + error: unknown start of token: \ --> :1:1 | diff --git a/src/test/rustdoc/assoc-consts.rs b/src/test/rustdoc/assoc-consts.rs index ee622e74a08dc..bb6af7995a0ad 100644 --- a/src/test/rustdoc/assoc-consts.rs +++ b/src/test/rustdoc/assoc-consts.rs @@ -95,5 +95,5 @@ impl Qux for Bar { /// Docs for QUX_DEFAULT1 in impl. const QUX_DEFAULT1: i16 = 7; // @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32' - // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait." + // @has - '//*[@class="docblock hidden"]' "Docs for QUX_DEFAULT2 in trait." } diff --git a/src/test/rustdoc/async-fn.rs b/src/test/rustdoc/async-fn.rs index 7384f7027d185..5f9708a39722a 100644 --- a/src/test/rustdoc/async-fn.rs +++ b/src/test/rustdoc/async-fn.rs @@ -1,7 +1,5 @@ // edition:2018 -#![feature(async_await)] - // @has async_fn/fn.foo.html '//pre[@class="rust fn"]' 'pub async fn foo() -> Option' pub async fn foo() -> Option { None diff --git a/src/test/rustdoc/async-move-doctest.rs b/src/test/rustdoc/async-move-doctest.rs index 42723132782ca..2ba61388c9e3b 100644 --- a/src/test/rustdoc/async-move-doctest.rs +++ b/src/test/rustdoc/async-move-doctest.rs @@ -1,13 +1,11 @@ // compile-flags:--test // edition:2018 -// prior to setting the default edition for the doctest pre-parser, this doctest would fail due to -// a fatal parsing error +// Prior to setting the default edition for the doctest pre-parser, +// this doctest would fail due to a fatal parsing error. // see https://github.com/rust-lang/rust/issues/59313 //! ``` -//! #![feature(async_await)] -//! //! fn foo() { //! drop(async move {}); //! } diff --git a/src/test/rustdoc/auxiliary/issue-57180.rs b/src/test/rustdoc/auxiliary/issue-57180.rs new file mode 100644 index 0000000000000..4e2f4b87c020e --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-57180.rs @@ -0,0 +1,16 @@ +// compile-flags: -Cmetadata=aux + +pub trait Trait { +} + +pub struct Struct +{ + _p: ::std::marker::PhantomData, +} + +impl u32> +Trait for Struct + where + F: Fn() -> u32, +{ +} diff --git a/src/test/rustdoc/auxiliary/through-proc-macro-aux.rs b/src/test/rustdoc/auxiliary/through-proc-macro-aux.rs new file mode 100644 index 0000000000000..5c4a01ee3a74a --- /dev/null +++ b/src/test/rustdoc/auxiliary/through-proc-macro-aux.rs @@ -0,0 +1,20 @@ +// force-host +// no-prefer-dynamic +#![crate_type = "proc-macro"] +#![crate_name="some_macros"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn first(_attr: TokenStream, item: TokenStream) -> TokenStream { + item // This doesn't erase the spans. +} + +#[proc_macro_attribute] +pub fn second(_attr: TokenStream, item: TokenStream) -> TokenStream { + // Make a new `TokenStream` to erase the spans: + let mut out: TokenStream = TokenStream::new(); + out.extend(item); + out +} diff --git a/src/test/rustdoc/edition-flag.rs b/src/test/rustdoc/edition-flag.rs index 5571245f28ddb..ddbc2be651d90 100644 --- a/src/test/rustdoc/edition-flag.rs +++ b/src/test/rustdoc/edition-flag.rs @@ -1,10 +1,7 @@ // compile-flags:--test -Z unstable-options // edition:2018 -#![feature(async_await)] - /// ```rust -/// #![feature(async_await)] /// fn main() { /// let _ = async { }; /// } diff --git a/src/test/rustdoc/inline_cross/assoc-items.rs b/src/test/rustdoc/inline_cross/assoc-items.rs index d4f05bab5cabf..7eb3e43cb114e 100644 --- a/src/test/rustdoc/inline_cross/assoc-items.rs +++ b/src/test/rustdoc/inline_cross/assoc-items.rs @@ -16,15 +16,15 @@ extern crate assoc_items; // @has - '//*[@id="associatedconstant.ConstNoDefault"]' 'const ConstNoDefault: i16' // @has - '//*[@class="docblock"]' 'dox for ConstNoDefault' // @has - '//*[@id="associatedconstant.ConstWithDefault"]' 'const ConstWithDefault: u16' -// @has - '//*[@class="docblock"]' 'docs for ConstWithDefault' +// @has - '//*[@class="docblock hidden"]' 'docs for ConstWithDefault' // @has - '//*[@id="associatedtype.TypeNoDefault"]' 'type TypeNoDefault = i32' // @has - '//*[@class="docblock"]' 'dox for TypeNoDefault' // @has - '//*[@id="associatedtype.TypeWithDefault"]' 'type TypeWithDefault = u32' -// @has - '//*[@class="docblock"]' 'docs for TypeWithDefault' +// @has - '//*[@class="docblock hidden"]' 'docs for TypeWithDefault' // @has - '//*[@id="method.method_no_default"]' 'fn method_no_default()' // @has - '//*[@class="docblock"]' 'dox for method_no_default' // @has - '//*[@id="method.method_with_default"]' 'fn method_with_default()' -// @has - '//*[@class="docblock"]' 'docs for method_with_default' +// @has - '//*[@class="docblock hidden"]' 'docs for method_with_default' pub use assoc_items::MyStruct; // @has foo/trait.MyTrait.html diff --git a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs new file mode 100644 index 0000000000000..913ba8f2a1649 --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs @@ -0,0 +1,28 @@ +// edition:2018 + +use std::ops::Deref; + +pub fn func<'a>(_x: impl Clone + Into> + 'a) {} + +pub fn func2( + _x: impl Deref> + Iterator, + _y: impl Iterator, +) {} + +pub fn func3(_x: impl Iterator> + Clone) {} + +pub fn func4>(_x: T) {} + +pub async fn async_fn() {} + +pub struct Foo; + +impl Foo { + pub fn method<'a>(_x: impl Clone + Into> + 'a) {} +} + +pub struct Bar; + +impl Bar { + pub async fn async_foo(&self) {} +} diff --git a/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs b/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs index c99ef74433358..37465ccf1c27e 100644 --- a/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs +++ b/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs @@ -1,5 +1,6 @@ // force-host // no-prefer-dynamic +// compile-flags: --crate-type proc-macro #![crate_type="proc-macro"] #![crate_name="some_macros"] @@ -25,3 +26,9 @@ pub fn some_proc_attr(_attr: TokenStream, item: TokenStream) -> TokenStream { pub fn some_derive(_item: TokenStream) -> TokenStream { TokenStream::new() } + +/// Doc comment from the original crate +#[proc_macro] +pub fn reexported_macro(_input: TokenStream) -> TokenStream { + TokenStream::new() +} diff --git a/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs b/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs index cadeccb60c817..4591bb526ae77 100644 --- a/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs +++ b/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs @@ -8,5 +8,5 @@ extern crate impl_inline_without_trait; // @has 'foo/struct.MyStruct.html' // @has - '//*[@id="method.my_trait_method"]' 'fn my_trait_method()' -// @has - '//*[@class="docblock"]' 'docs for my_trait_method' +// @has - '//*[@class="docblock hidden"]' 'docs for my_trait_method' pub use impl_inline_without_trait::MyStruct; diff --git a/src/test/rustdoc/inline_cross/impl_trait.rs b/src/test/rustdoc/inline_cross/impl_trait.rs new file mode 100644 index 0000000000000..6f4a48c83c05b --- /dev/null +++ b/src/test/rustdoc/inline_cross/impl_trait.rs @@ -0,0 +1,40 @@ +// aux-build:impl_trait_aux.rs +// edition:2018 + +extern crate impl_trait_aux; + +// @has impl_trait/fn.func.html +// @has - '//pre[@class="rust fn"]' "pub fn func<'a>(_x: impl Clone + Into> + 'a)" +// @!has - '//pre[@class="rust fn"]' 'where' +pub use impl_trait_aux::func; + +// @has impl_trait/fn.func2.html +// @has - '//pre[@class="rust fn"]' "func2(" +// @has - '//pre[@class="rust fn"]' "_x: impl Deref> + Iterator," +// @has - '//pre[@class="rust fn"]' "_y: impl Iterator)" +// @!has - '//pre[@class="rust fn"]' 'where' +pub use impl_trait_aux::func2; + +// @has impl_trait/fn.func3.html +// @has - '//pre[@class="rust fn"]' "func3(" +// @has - '//pre[@class="rust fn"]' "_x: impl Clone + Iterator>)" +// @!has - '//pre[@class="rust fn"]' 'where' +pub use impl_trait_aux::func3; + +// @has impl_trait/fn.func4.html +// @has - '//pre[@class="rust fn"]' "func4(" +// @has - '//pre[@class="rust fn"]' "T: Iterator," +pub use impl_trait_aux::func4; + +// @has impl_trait/fn.async_fn.html +// @has - '//pre[@class="rust fn"]' "pub async fn async_fn()" +pub use impl_trait_aux::async_fn; + +// @has impl_trait/struct.Foo.html +// @has - '//code[@id="method.v"]' "pub fn method<'a>(_x: impl Clone + Into> + 'a)" +// @!has - '//code[@id="method.v"]' 'where' +pub use impl_trait_aux::Foo; + +// @has impl_trait/struct.Bar.html +// @has - '//*[@id="method.async_foo"]' "pub async fn async_foo(" +pub use impl_trait_aux::Bar; diff --git a/src/test/rustdoc/inline_cross/proc_macro.rs b/src/test/rustdoc/inline_cross/proc_macro.rs index e1cdcf4940244..3dc8de3fe579d 100644 --- a/src/test/rustdoc/inline_cross/proc_macro.rs +++ b/src/test/rustdoc/inline_cross/proc_macro.rs @@ -1,16 +1,28 @@ // aux-build:proc_macro.rs // build-aux-docs -// FIXME: if/when proc-macros start exporting their doc attributes across crates, we can turn on -// cross-crate inlining for them - extern crate some_macros; // @has proc_macro/index.html -// @has - '//a/@href' '../some_macros/macro.some_proc_macro.html' -// @has - '//a/@href' '../some_macros/attr.some_proc_attr.html' -// @has - '//a/@href' '../some_macros/derive.SomeDerive.html' -// @!has proc_macro/macro.some_proc_macro.html -// @!has proc_macro/attr.some_proc_attr.html -// @!has proc_macro/derive.SomeDerive.html -pub use some_macros::{some_proc_macro, some_proc_attr, SomeDerive}; +// @has - '//a/@href' 'macro.some_proc_macro.html' +// @has - '//a/@href' 'attr.some_proc_attr.html' +// @has - '//a/@href' 'derive.SomeDerive.html' +// @has proc_macro/macro.some_proc_macro.html +// @has proc_macro/attr.some_proc_attr.html +// @has proc_macro/derive.SomeDerive.html + +// @has proc_macro/macro.some_proc_macro.html +// @has - 'a proc-macro that swallows its input and does nothing.' +pub use some_macros::some_proc_macro; + +// @has proc_macro/macro.reexported_macro.html +// @has - 'Doc comment from the original crate' +pub use some_macros::reexported_macro; + +// @has proc_macro/attr.some_proc_attr.html +// @has - 'a proc-macro attribute that passes its item through verbatim.' +pub use some_macros::some_proc_attr; + +// @has proc_macro/derive.SomeDerive.html +// @has - 'a derive attribute that adds nothing to its input.' +pub use some_macros::SomeDerive; diff --git a/src/test/rustdoc/issue-57180.rs b/src/test/rustdoc/issue-57180.rs new file mode 100644 index 0000000000000..14bd2b0fec0d5 --- /dev/null +++ b/src/test/rustdoc/issue-57180.rs @@ -0,0 +1,7 @@ +// aux-build:issue-57180.rs + +extern crate issue_57180; +use issue_57180::Trait; + +fn main() { +} diff --git a/src/test/rustdoc/manual_impl.rs b/src/test/rustdoc/manual_impl.rs index c9e4f4e0d3037..11ddab5f7ff26 100644 --- a/src/test/rustdoc/manual_impl.rs +++ b/src/test/rustdoc/manual_impl.rs @@ -24,10 +24,10 @@ pub trait T { // @has - '//*[@class="docblock"]' 'Docs associated with the S1 trait implementation.' // @has - '//*[@class="docblock"]' 'Docs associated with the S1 trait a_method implementation.' // @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.' -// @has - '//*[@class="docblock"]' 'Docs associated with the trait b_method definition.' -// @has - '//*[@class="docblock"]' 'Docs associated with the trait c_method definition.' +// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait b_method definition.' +// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait c_method definition.' // @!has - '//*[@class="docblock"]' 'There is another line' -// @has - '//*[@class="docblock"]' 'Read more' +// @has - '//*[@class="docblock hidden"]' 'Read more' pub struct S1(usize); /// Docs associated with the S1 trait implementation. @@ -44,7 +44,7 @@ impl T for S1 { // @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait c_method implementation.' // @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.' // @!has - '//*[@class="docblock"]' 'Docs associated with the trait c_method definition.' -// @has - '//*[@class="docblock"]' 'Docs associated with the trait b_method definition.' +// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait b_method definition.' pub struct S2(usize); /// Docs associated with the S2 trait implementation. diff --git a/src/test/rustdoc/proc-macro.rs b/src/test/rustdoc/proc-macro.rs index 4bd0b092b55a7..82196e413e94b 100644 --- a/src/test/rustdoc/proc-macro.rs +++ b/src/test/rustdoc/proc-macro.rs @@ -1,5 +1,6 @@ // force-host // no-prefer-dynamic +// compile-flags: --crate-type proc-macro --document-private-items #![crate_type="proc-macro"] #![crate_name="some_macros"] @@ -58,7 +59,7 @@ pub fn some_derive(_item: TokenStream) -> TokenStream { } // @has some_macros/foo/index.html -pub mod foo { +mod foo { // @has - '//code' 'pub use some_proc_macro;' // @has - '//a/@href' '../../some_macros/macro.some_proc_macro.html' pub use some_proc_macro; diff --git a/src/test/rustdoc/rustc-macro-crate.rs b/src/test/rustdoc/rustc-macro-crate.rs index 2f6308b20c2ee..dd5edc984dafa 100644 --- a/src/test/rustdoc/rustc-macro-crate.rs +++ b/src/test/rustdoc/rustc-macro-crate.rs @@ -1,5 +1,6 @@ // force-host // no-prefer-dynamic +// compile-flags: --crate-type proc-macro #![crate_type = "proc-macro"] diff --git a/src/test/rustdoc/through-proc-macro.rs b/src/test/rustdoc/through-proc-macro.rs new file mode 100644 index 0000000000000..348c9eea2dcbf --- /dev/null +++ b/src/test/rustdoc/through-proc-macro.rs @@ -0,0 +1,12 @@ +// aux-build:through-proc-macro-aux.rs +// build-aux-docs +#![warn(intra_doc_link_resolution_failure)] +extern crate some_macros; + +#[some_macros::second] +pub enum Boom { + /// [Oooops] + Bam, +} + +fn main() {} diff --git a/src/test/rustdoc/variadic.rs b/src/test/rustdoc/variadic.rs index 5af2aea21fcac..bd8f1775b3d04 100644 --- a/src/test/rustdoc/variadic.rs +++ b/src/test/rustdoc/variadic.rs @@ -1,4 +1,4 @@ extern "C" { - // @has variadic/fn.foo.html //pre 'pub unsafe extern "C" fn foo(x: i32, _: ...)' + // @has variadic/fn.foo.html //pre 'pub unsafe extern "C" fn foo(x: i32, ...)' pub fn foo(x: i32, ...); } diff --git a/src/test/ui-fulldeps/ast_stmt_expr_attr.rs b/src/test/ui-fulldeps/ast_stmt_expr_attr.rs index c90fe0014326e..6c5f539b87185 100644 --- a/src/test/ui-fulldeps/ast_stmt_expr_attr.rs +++ b/src/test/ui-fulldeps/ast_stmt_expr_attr.rs @@ -83,7 +83,7 @@ fn check_expr_attrs(es: &str, expected: &[&str]) { fn check_stmt_attrs(es: &str, expected: &[&str]) { let ps = ParseSess::new(FilePathMapping::empty()); let e = stmt(es, &ps).expect("parse error"); - let actual = e.node.attrs(); + let actual = e.kind.attrs(); str_compare(es, &expected.iter().map(|r| attr(r, &ps).unwrap()).collect::>(), actual, diff --git a/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs index c2685c7f74c30..c053c71524876 100644 --- a/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs +++ b/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs @@ -4,10 +4,9 @@ #![feature(rustc_private)] extern crate rustc_driver; -extern crate rustc_plugin; extern crate syntax; -use rustc_plugin::Registry; +use rustc_driver::plugin::Registry; use syntax::ext::base::SyntaxExtension; use syntax::feature_gate::AttributeType; use syntax::symbol::Symbol; diff --git a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs index ad42ee1d1ec1e..6fb99b2c98361 100644 --- a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs +++ b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs @@ -3,11 +3,10 @@ #[macro_use] extern crate rustc; -extern crate rustc_plugin; extern crate rustc_driver; extern crate syntax; -use rustc_plugin::Registry; +use rustc_driver::plugin::Registry; use syntax::attr; use syntax::ext::base::*; use syntax::feature_gate::AttributeType::Whitelisted; diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs index 2826ae75bee2a..17386d7e1aa5f 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs @@ -4,12 +4,11 @@ #![feature(box_syntax)] #[macro_use] extern crate rustc; -extern crate rustc_plugin; extern crate rustc_driver; extern crate syntax; use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray}; -use rustc_plugin::Registry; +use rustc_driver::plugin::Registry; use rustc::hir; use syntax::attr; use syntax::symbol::Symbol; diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs index a811edd37c67d..000e10392e827 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs @@ -4,12 +4,11 @@ #![feature(box_syntax)] #[macro_use] extern crate rustc; -extern crate rustc_plugin; extern crate rustc_driver; extern crate syntax; use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray}; -use rustc_plugin::Registry; +use rustc_driver::plugin::Registry; use rustc::hir; use syntax::attr; use syntax::symbol::Symbol; diff --git a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs index 3206ddee62475..a377b07bd3dd2 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs @@ -6,12 +6,11 @@ // Load rustc as a plugin to get macros. #[macro_use] extern crate rustc; -extern crate rustc_plugin; extern crate rustc_driver; use rustc::hir; use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray}; -use rustc_plugin::Registry; +use rustc_driver::plugin::Registry; declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); diff --git a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs index 4d57be49ca061..02675191f785e 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs @@ -8,12 +8,11 @@ extern crate syntax; // Load rustc as a plugin to get macros #[macro_use] extern crate rustc; -extern crate rustc_plugin; extern crate rustc_driver; use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, EarlyLintPassObject, LintArray}; -use rustc_plugin::Registry; +use rustc_driver::plugin::Registry; use syntax::ast; declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); diff --git a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs index ea7c75fbbe5d5..40f8d490ac87c 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs @@ -6,11 +6,10 @@ extern crate syntax; // Load rustc as a plugin to get macros #[macro_use] extern crate rustc; -extern crate rustc_plugin; extern crate rustc_driver; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; -use rustc_plugin::Registry; +use rustc_driver::plugin::Registry; use syntax::ast; declare_tool_lint!(pub clippy::TEST_LINT, Warn, "Warn about stuff"); declare_tool_lint!( diff --git a/src/test/ui-fulldeps/auxiliary/llvm-pass-plugin.rs b/src/test/ui-fulldeps/auxiliary/llvm-pass-plugin.rs index 1832fee434717..2ff1c2e363d50 100644 --- a/src/test/ui-fulldeps/auxiliary/llvm-pass-plugin.rs +++ b/src/test/ui-fulldeps/auxiliary/llvm-pass-plugin.rs @@ -4,10 +4,9 @@ #![feature(rustc_private)] extern crate rustc; -extern crate rustc_plugin; extern crate rustc_driver; -use rustc_plugin::Registry; +use rustc_driver::plugin::Registry; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { diff --git a/src/test/ui-fulldeps/auxiliary/lto-syntax-extension-plugin.rs b/src/test/ui-fulldeps/auxiliary/lto-syntax-extension-plugin.rs index 6e446241d5579..89bc9a2b9dbf4 100644 --- a/src/test/ui-fulldeps/auxiliary/lto-syntax-extension-plugin.rs +++ b/src/test/ui-fulldeps/auxiliary/lto-syntax-extension-plugin.rs @@ -4,10 +4,9 @@ #![feature(rustc_private)] extern crate rustc; -extern crate rustc_plugin; extern crate rustc_driver; -use rustc_plugin::Registry; +use rustc_driver::plugin::Registry; #[plugin_registrar] pub fn plugin_registrar(_reg: &mut Registry) {} diff --git a/src/test/ui-fulldeps/auxiliary/macro-crate-test.rs b/src/test/ui-fulldeps/auxiliary/macro-crate-test.rs index d9b2740e47638..ee82c0adc8604 100644 --- a/src/test/ui-fulldeps/auxiliary/macro-crate-test.rs +++ b/src/test/ui-fulldeps/auxiliary/macro-crate-test.rs @@ -6,7 +6,6 @@ extern crate syntax; extern crate rustc; -extern crate rustc_plugin; extern crate rustc_driver; extern crate syntax_pos; extern crate proc_macro; diff --git a/src/test/ui-fulldeps/auxiliary/outlive-expansion-phase.rs b/src/test/ui-fulldeps/auxiliary/outlive-expansion-phase.rs index c22605afd0c8d..e5c4f5b8f7a66 100644 --- a/src/test/ui-fulldeps/auxiliary/outlive-expansion-phase.rs +++ b/src/test/ui-fulldeps/auxiliary/outlive-expansion-phase.rs @@ -4,12 +4,11 @@ #![feature(box_syntax, rustc_private)] extern crate rustc; -extern crate rustc_plugin; extern crate rustc_driver; use std::any::Any; use std::cell::RefCell; -use rustc_plugin::Registry; +use rustc_driver::plugin::Registry; struct Foo { foo: isize diff --git a/src/test/ui-fulldeps/auxiliary/plugin-args.rs b/src/test/ui-fulldeps/auxiliary/plugin-args.rs index f3cd2397b28fe..5ff24cff23c55 100644 --- a/src/test/ui-fulldeps/auxiliary/plugin-args.rs +++ b/src/test/ui-fulldeps/auxiliary/plugin-args.rs @@ -6,7 +6,6 @@ extern crate syntax; extern crate syntax_pos; extern crate rustc; -extern crate rustc_plugin; extern crate rustc_driver; use std::borrow::ToOwned; @@ -17,7 +16,7 @@ use syntax::print::pprust; use syntax::symbol::Symbol; use syntax_pos::Span; use syntax::tokenstream::TokenStream; -use rustc_plugin::Registry; +use rustc_driver::plugin::Registry; struct Expander { args: Vec, diff --git a/src/test/ui-fulldeps/auxiliary/rlib-crate-test.rs b/src/test/ui-fulldeps/auxiliary/rlib-crate-test.rs index 7a91b54bf6d81..1c0de98da56f2 100644 --- a/src/test/ui-fulldeps/auxiliary/rlib-crate-test.rs +++ b/src/test/ui-fulldeps/auxiliary/rlib-crate-test.rs @@ -4,10 +4,9 @@ #![feature(plugin_registrar, rustc_private)] extern crate rustc; -extern crate rustc_plugin; extern crate rustc_driver; -use rustc_plugin::Registry; +use rustc_driver::plugin::Registry; #[plugin_registrar] pub fn plugin_registrar(_: &mut Registry) {} diff --git a/src/test/ui-fulldeps/auxiliary/roman-numerals.rs b/src/test/ui-fulldeps/auxiliary/roman-numerals.rs index 77fa5c2cd7898..2b57e9289b525 100644 --- a/src/test/ui-fulldeps/auxiliary/roman-numerals.rs +++ b/src/test/ui-fulldeps/auxiliary/roman-numerals.rs @@ -12,16 +12,15 @@ extern crate syntax; extern crate syntax_pos; extern crate rustc; -extern crate rustc_plugin; extern crate rustc_driver; use syntax::parse::token::{self, Token}; -use syntax::tokenstream::TokenTree; +use syntax::tokenstream::{TokenTree, TokenStream}; use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; use syntax_pos::Span; -use rustc_plugin::Registry; +use rustc_driver::plugin::Registry; -fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) +fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: TokenStream) -> Box { static NUMERALS: &'static [(&'static str, usize)] = &[ @@ -37,7 +36,7 @@ fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) return DummyResult::any(sp); } - let text = match args[0] { + let text = match args.into_trees().next().unwrap() { TokenTree::Token(Token { kind: token::Ident(s, _), .. }) => s.to_string(), _ => { cx.span_err(sp, "argument should be a single identifier"); diff --git a/src/test/ui-fulldeps/compiler-calls.rs b/src/test/ui-fulldeps/compiler-calls.rs index ea24f5809d52a..bd9113c7079ea 100644 --- a/src/test/ui-fulldeps/compiler-calls.rs +++ b/src/test/ui-fulldeps/compiler-calls.rs @@ -24,7 +24,7 @@ impl rustc_driver::Callbacks for TestCalls<'_> { fn main() { let mut count = 1; let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()]; - rustc_driver::report_ices_to_stderr_if_any(|| { + rustc_driver::catch_fatal_errors(|| { rustc_driver::run_compiler(&args, &mut TestCalls { count: &mut count }, None, None).ok(); }).ok(); assert_eq!(count, 2); diff --git a/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs b/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs index 877fb57a25132..29c1b8fb0da97 100644 --- a/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs +++ b/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs @@ -5,11 +5,10 @@ #![feature(box_syntax)] #![feature(rustc_private)] -extern crate serialize; -use serialize as rustc_serialize; +extern crate serialize as rustc_serialize; -use serialize::{Encodable, Decodable}; -use serialize::json; +use rustc_serialize::{Encodable, Decodable}; +use rustc_serialize::json; #[derive(RustcEncodable, RustcDecodable)] struct A { diff --git a/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs b/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs index a35b681641a4b..fe608890bbd4d 100644 --- a/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs +++ b/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs @@ -7,12 +7,11 @@ #![feature(rustc_private)] -extern crate serialize; -use serialize as rustc_serialize; +extern crate serialize as rustc_serialize; use std::cell::{Cell, RefCell}; -use serialize::{Encodable, Decodable}; -use serialize::json; +use rustc_serialize::{Encodable, Decodable}; +use rustc_serialize::json; #[derive(RustcEncodable, RustcDecodable)] struct A { diff --git a/src/test/ui-fulldeps/deriving-global.rs b/src/test/ui-fulldeps/deriving-global.rs index b59d55ff213ce..d7cc98fed2595 100644 --- a/src/test/ui-fulldeps/deriving-global.rs +++ b/src/test/ui-fulldeps/deriving-global.rs @@ -2,8 +2,7 @@ #![feature(rustc_private)] -extern crate serialize; -use serialize as rustc_serialize; +extern crate serialize as rustc_serialize; mod submod { // if any of these are implemented without global calls for any diff --git a/src/test/ui-fulldeps/deriving-hygiene.rs b/src/test/ui-fulldeps/deriving-hygiene.rs index 0d7439ef87246..b1bdfaceb887d 100644 --- a/src/test/ui-fulldeps/deriving-hygiene.rs +++ b/src/test/ui-fulldeps/deriving-hygiene.rs @@ -2,8 +2,7 @@ #![allow(non_upper_case_globals)] #![feature(rustc_private)] -extern crate serialize; -use serialize as rustc_serialize; +extern crate serialize as rustc_serialize; pub const other: u8 = 1; pub const f: u8 = 1; diff --git a/src/test/ui-fulldeps/gated-plugin.rs b/src/test/ui-fulldeps/gated-plugin.rs index be1ec0614803b..0522c6d69a82f 100644 --- a/src/test/ui-fulldeps/gated-plugin.rs +++ b/src/test/ui-fulldeps/gated-plugin.rs @@ -1,6 +1,7 @@ // aux-build:attr-plugin-test.rs #![plugin(attr_plugin_test)] -//~^ ERROR compiler plugins are experimental and possibly buggy +//~^ ERROR compiler plugins are deprecated +//~| WARN use of deprecated attribute `plugin`: compiler plugins are deprecated fn main() {} diff --git a/src/test/ui-fulldeps/gated-plugin.stderr b/src/test/ui-fulldeps/gated-plugin.stderr index c5c1326c4f336..aa031fb7a63d2 100644 --- a/src/test/ui-fulldeps/gated-plugin.stderr +++ b/src/test/ui-fulldeps/gated-plugin.stderr @@ -1,4 +1,4 @@ -error[E0658]: compiler plugins are experimental and possibly buggy +error[E0658]: compiler plugins are deprecated --> $DIR/gated-plugin.rs:3:1 | LL | #![plugin(attr_plugin_test)] @@ -7,6 +7,14 @@ LL | #![plugin(attr_plugin_test)] = note: for more information, see https://github.com/rust-lang/rust/issues/29597 = help: add `#![feature(plugin)]` to the crate attributes to enable +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/gated-plugin.rs:3:1 + | +LL | #![plugin(attr_plugin_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + error: aborting due to previous error For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui-fulldeps/hash-stable-is-unstable.rs b/src/test/ui-fulldeps/hash-stable-is-unstable.rs index 9f67f642df1ce..d79ef62c31207 100644 --- a/src/test/ui-fulldeps/hash-stable-is-unstable.rs +++ b/src/test/ui-fulldeps/hash-stable-is-unstable.rs @@ -13,3 +13,5 @@ use rustc_macros::HashStable; #[derive(HashStable)] //~^ use of unstable library feature 'rustc_private' struct Test; + +fn main() {} diff --git a/src/test/ui-fulldeps/hash-stable-is-unstable.stderr b/src/test/ui-fulldeps/hash-stable-is-unstable.stderr index 02056d30eae9c..e2dc0c3be725f 100644 --- a/src/test/ui-fulldeps/hash-stable-is-unstable.stderr +++ b/src/test/ui-fulldeps/hash-stable-is-unstable.stderr @@ -1,7 +1,3 @@ -error[E0601]: `main` function not found in crate `hash_stable_is_unstable` - | - = note: consider adding a `main` function to `$DIR/hash-stable-is-unstable.rs` - error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? --> $DIR/hash-stable-is-unstable.rs:3:1 | @@ -47,7 +43,6 @@ LL | #[derive(HashStable)] = note: for more information, see https://github.com/rust-lang/rust/issues/27812 = help: add `#![feature(rustc_private)]` to the crate attributes to enable -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0601, E0658. -For more information about an error, try `rustc --explain E0601`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs index c6bd122f4e548..f716a78a031f2 100644 --- a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs +++ b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs @@ -8,9 +8,9 @@ use rustc::ty::{self, Ty, TyKind}; #[deny(rustc::usage_of_ty_tykind)] fn main() { - let sty = TyKind::Bool; //~ ERROR usage of `ty::TyKind::` + let kind = TyKind::Bool; //~ ERROR usage of `ty::TyKind::` - match sty { + match kind { TyKind::Bool => (), //~ ERROR usage of `ty::TyKind::` TyKind::Char => (), //~ ERROR usage of `ty::TyKind::` TyKind::Int(..) => (), //~ ERROR usage of `ty::TyKind::` @@ -41,9 +41,9 @@ fn main() { TyKind::Error => (), //~ ERROR usage of `ty::TyKind::` } - if let ty::Int(int_ty) = sty {} + if let ty::Int(int_ty) = kind {} - if let TyKind::Int(int_ty) = sty {} //~ ERROR usage of `ty::TyKind::` + if let TyKind::Int(int_ty) = kind {} //~ ERROR usage of `ty::TyKind::` fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {} //~ ERROR usage of `ty::TyKind` } diff --git a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr index 8add4252c4103..28c837adac3a1 100644 --- a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr +++ b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr @@ -1,8 +1,8 @@ error: usage of `ty::TyKind::` - --> $DIR/ty_tykind_usage.rs:11:15 + --> $DIR/ty_tykind_usage.rs:11:16 | -LL | let sty = TyKind::Bool; - | ^^^^^^ help: try using ty:: directly: `ty` +LL | let kind = TyKind::Bool; + | ^^^^^^ help: try using ty:: directly: `ty` | note: lint level defined here --> $DIR/ty_tykind_usage.rs:9:8 @@ -181,7 +181,7 @@ LL | TyKind::Error => (), error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:46:12 | -LL | if let TyKind::Int(int_ty) = sty {} +LL | if let TyKind::Int(int_ty) = kind {} | ^^^^^^ help: try using ty:: directly: `ty` error: usage of `ty::TyKind` diff --git a/src/test/ui-fulldeps/issue-11881.rs b/src/test/ui-fulldeps/issue-11881.rs index c8893e629418a..bd046a6cdee5f 100644 --- a/src/test/ui-fulldeps/issue-11881.rs +++ b/src/test/ui-fulldeps/issue-11881.rs @@ -6,17 +6,16 @@ #![feature(rustc_private)] -extern crate serialize; -use serialize as rustc_serialize; +extern crate serialize as rustc_serialize; use std::io::Cursor; use std::io::prelude::*; use std::fmt; use std::slice; -use serialize::{Encodable, Encoder}; -use serialize::json; -use serialize::opaque; +use rustc_serialize::{Encodable, Encoder}; +use rustc_serialize::json; +use rustc_serialize::opaque; #[derive(RustcEncodable)] struct Foo { diff --git a/src/test/ui-fulldeps/issue-15778-fail.rs b/src/test/ui-fulldeps/issue-15778-fail.rs index 75c52fdb4bd28..beecaadf95554 100644 --- a/src/test/ui-fulldeps/issue-15778-fail.rs +++ b/src/test/ui-fulldeps/issue-15778-fail.rs @@ -4,5 +4,6 @@ #![feature(plugin)] //~ ERROR crate is not marked with #![crate_okay] #![plugin(lint_for_crate)] +//~^ WARN use of deprecated attribute `plugin` pub fn main() { } diff --git a/src/test/ui-fulldeps/issue-15778-fail.stderr b/src/test/ui-fulldeps/issue-15778-fail.stderr index d689286177644..3afdb1fbf807d 100644 --- a/src/test/ui-fulldeps/issue-15778-fail.stderr +++ b/src/test/ui-fulldeps/issue-15778-fail.stderr @@ -1,9 +1,18 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/issue-15778-fail.rs:6:1 + | +LL | #![plugin(lint_for_crate)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + error: crate is not marked with #![crate_okay] --> $DIR/issue-15778-fail.rs:5:1 | LL | / #![feature(plugin)] LL | | #![plugin(lint_for_crate)] LL | | +LL | | LL | | pub fn main() { } | |_________________^ | diff --git a/src/test/ui-fulldeps/issue-15778-pass.stderr b/src/test/ui-fulldeps/issue-15778-pass.stderr new file mode 100644 index 0000000000000..f81c314c23a2d --- /dev/null +++ b/src/test/ui-fulldeps/issue-15778-pass.stderr @@ -0,0 +1,8 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/issue-15778-pass.rs:8:1 + | +LL | #![plugin(lint_for_crate_rpass)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + diff --git a/src/test/ui-fulldeps/issue-40001.stderr b/src/test/ui-fulldeps/issue-40001.stderr new file mode 100644 index 0000000000000..186721e2bb9e6 --- /dev/null +++ b/src/test/ui-fulldeps/issue-40001.stderr @@ -0,0 +1,8 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/issue-40001.rs:6:1 + | +LL | #![plugin(issue_40001_plugin)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + diff --git a/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.rs b/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.rs index c9d8654a90974..9f8a879608c1f 100644 --- a/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.rs +++ b/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.rs @@ -3,7 +3,9 @@ // compile-flags: -D lint-me #![feature(plugin)] + #![plugin(lint_group_plugin_test)] +//~^ WARN use of deprecated attribute `plugin` fn lintme() { } //~ ERROR item is named 'lintme' diff --git a/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.stderr b/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.stderr index cd0bff92bf112..28065bf3946c0 100644 --- a/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.stderr +++ b/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.stderr @@ -1,5 +1,13 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/lint-group-plugin-deny-cmdline.rs:7:1 + | +LL | #![plugin(lint_group_plugin_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + error: item is named 'lintme' - --> $DIR/lint-group-plugin-deny-cmdline.rs:8:1 + --> $DIR/lint-group-plugin-deny-cmdline.rs:10:1 | LL | fn lintme() { } | ^^^^^^^^^^^^^^^ @@ -7,7 +15,7 @@ LL | fn lintme() { } = note: `-D test-lint` implied by `-D lint-me` error: item is named 'pleaselintme' - --> $DIR/lint-group-plugin-deny-cmdline.rs:10:1 + --> $DIR/lint-group-plugin-deny-cmdline.rs:12:1 | LL | fn pleaselintme() { } | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui-fulldeps/lint-group-plugin.stderr b/src/test/ui-fulldeps/lint-group-plugin.stderr index 1af34b306e3a3..a93cae1a2b1ec 100644 --- a/src/test/ui-fulldeps/lint-group-plugin.stderr +++ b/src/test/ui-fulldeps/lint-group-plugin.stderr @@ -1,3 +1,11 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/lint-group-plugin.rs:6:1 + | +LL | #![plugin(lint_group_plugin_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + warning: item is named 'lintme' --> $DIR/lint-group-plugin.rs:9:1 | diff --git a/src/test/ui-fulldeps/lint-plugin-cmdline-allow.stderr b/src/test/ui-fulldeps/lint-plugin-cmdline-allow.stderr index c731796d4824d..2185929e893b7 100644 --- a/src/test/ui-fulldeps/lint-plugin-cmdline-allow.stderr +++ b/src/test/ui-fulldeps/lint-plugin-cmdline-allow.stderr @@ -1,3 +1,11 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/lint-plugin-cmdline-allow.rs:8:1 + | +LL | #![plugin(lint_plugin_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + warning: function is never used: `lintme` --> $DIR/lint-plugin-cmdline-allow.rs:10:1 | diff --git a/src/test/ui-fulldeps/lint-plugin-deny-attr.rs b/src/test/ui-fulldeps/lint-plugin-deny-attr.rs index 2d424af870707..04230a8e883b1 100644 --- a/src/test/ui-fulldeps/lint-plugin-deny-attr.rs +++ b/src/test/ui-fulldeps/lint-plugin-deny-attr.rs @@ -3,6 +3,7 @@ #![feature(plugin)] #![plugin(lint_plugin_test)] +//~^ WARN use of deprecated attribute `plugin` #![deny(test_lint)] fn lintme() { } //~ ERROR item is named 'lintme' diff --git a/src/test/ui-fulldeps/lint-plugin-deny-attr.stderr b/src/test/ui-fulldeps/lint-plugin-deny-attr.stderr index 5bfde8551ed37..a0cd9687f5bc0 100644 --- a/src/test/ui-fulldeps/lint-plugin-deny-attr.stderr +++ b/src/test/ui-fulldeps/lint-plugin-deny-attr.stderr @@ -1,11 +1,19 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/lint-plugin-deny-attr.rs:5:1 + | +LL | #![plugin(lint_plugin_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + error: item is named 'lintme' - --> $DIR/lint-plugin-deny-attr.rs:8:1 + --> $DIR/lint-plugin-deny-attr.rs:9:1 | LL | fn lintme() { } | ^^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/lint-plugin-deny-attr.rs:6:9 + --> $DIR/lint-plugin-deny-attr.rs:7:9 | LL | #![deny(test_lint)] | ^^^^^^^^^ diff --git a/src/test/ui-fulldeps/lint-plugin-deny-cmdline.rs b/src/test/ui-fulldeps/lint-plugin-deny-cmdline.rs index 87324e85b3be7..c460cfd5f9451 100644 --- a/src/test/ui-fulldeps/lint-plugin-deny-cmdline.rs +++ b/src/test/ui-fulldeps/lint-plugin-deny-cmdline.rs @@ -4,6 +4,7 @@ #![feature(plugin)] #![plugin(lint_plugin_test)] +//~^ WARN use of deprecated attribute `plugin` fn lintme() { } //~ ERROR item is named 'lintme' diff --git a/src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr b/src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr index e4257dfde6f90..3c64025e5eb23 100644 --- a/src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr +++ b/src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr @@ -1,5 +1,13 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/lint-plugin-deny-cmdline.rs:6:1 + | +LL | #![plugin(lint_plugin_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + error: item is named 'lintme' - --> $DIR/lint-plugin-deny-cmdline.rs:8:1 + --> $DIR/lint-plugin-deny-cmdline.rs:9:1 | LL | fn lintme() { } | ^^^^^^^^^^^^^^^ diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs index c7f7f2be99ed5..569f04d18ffd1 100644 --- a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs +++ b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs @@ -3,6 +3,7 @@ #![feature(plugin)] #![plugin(lint_plugin_test)] +//~^ WARN use of deprecated attribute `plugin` #![forbid(test_lint)] fn lintme() { } //~ ERROR item is named 'lintme' diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr index 092d0eb7a81a4..c0c43855c92a1 100644 --- a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr +++ b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr @@ -1,5 +1,5 @@ error[E0453]: allow(test_lint) overruled by outer forbid(test_lint) - --> $DIR/lint-plugin-forbid-attrs.rs:10:9 + --> $DIR/lint-plugin-forbid-attrs.rs:11:9 | LL | #![forbid(test_lint)] | --------- `forbid` level set here @@ -7,14 +7,22 @@ LL | #![forbid(test_lint)] LL | #[allow(test_lint)] | ^^^^^^^^^ overruled by previous forbid +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/lint-plugin-forbid-attrs.rs:5:1 + | +LL | #![plugin(lint_plugin_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + error: item is named 'lintme' - --> $DIR/lint-plugin-forbid-attrs.rs:8:1 + --> $DIR/lint-plugin-forbid-attrs.rs:9:1 | LL | fn lintme() { } | ^^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/lint-plugin-forbid-attrs.rs:6:11 + --> $DIR/lint-plugin-forbid-attrs.rs:7:11 | LL | #![forbid(test_lint)] | ^^^^^^^^^ diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs index 91fe3b65be6fc..82313f6912067 100644 --- a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs +++ b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs @@ -4,7 +4,7 @@ #![feature(plugin)] #![plugin(lint_plugin_test)] - +//~^ WARN use of deprecated attribute `plugin` fn lintme() { } //~ ERROR item is named 'lintme' #[allow(test_lint)] //~ ERROR allow(test_lint) overruled by outer forbid(test_lint) diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr index fc2906da5f5fc..99d013921911b 100644 --- a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr +++ b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr @@ -6,6 +6,14 @@ LL | #[allow(test_lint)] | = note: `forbid` lint level was set on command line +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/lint-plugin-forbid-cmdline.rs:6:1 + | +LL | #![plugin(lint_plugin_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + error: item is named 'lintme' --> $DIR/lint-plugin-forbid-cmdline.rs:8:1 | diff --git a/src/test/ui-fulldeps/lint-plugin.stderr b/src/test/ui-fulldeps/lint-plugin.stderr index beea00ba45367..2ca5eefe4376c 100644 --- a/src/test/ui-fulldeps/lint-plugin.stderr +++ b/src/test/ui-fulldeps/lint-plugin.stderr @@ -1,3 +1,11 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/lint-plugin.rs:5:1 + | +LL | #![plugin(lint_plugin_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + warning: item is named 'lintme' --> $DIR/lint-plugin.rs:8:1 | diff --git a/src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr b/src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr index b4919bc339d28..71c3dc929b2e5 100644 --- a/src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr +++ b/src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr @@ -2,6 +2,14 @@ warning: lint name `test_lint` is deprecated and does not have an effect anymore | = note: requested on the command line with `-A test_lint` +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/lint-tool-cmdline-allow.rs:8:1 + | +LL | #![plugin(lint_tool_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + warning: item is named 'lintme' --> $DIR/lint-tool-cmdline-allow.rs:10:1 | diff --git a/src/test/ui-fulldeps/lint-tool-test.rs b/src/test/ui-fulldeps/lint-tool-test.rs index 8bd06d1f1e34f..216a8cb95e31e 100644 --- a/src/test/ui-fulldeps/lint-tool-test.rs +++ b/src/test/ui-fulldeps/lint-tool-test.rs @@ -4,6 +4,7 @@ #![feature(plugin)] #![plugin(lint_tool_test)] +//~^ WARN use of deprecated attribute `plugin` #![allow(dead_code)] #![cfg_attr(foo, warn(test_lint))] //~^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future diff --git a/src/test/ui-fulldeps/lint-tool-test.stderr b/src/test/ui-fulldeps/lint-tool-test.stderr index 16fe6f6613b3f..c727cfc701541 100644 --- a/src/test/ui-fulldeps/lint-tool-test.stderr +++ b/src/test/ui-fulldeps/lint-tool-test.stderr @@ -1,5 +1,5 @@ warning: lint name `test_lint` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore - --> $DIR/lint-tool-test.rs:8:23 + --> $DIR/lint-tool-test.rs:9:23 | LL | #![cfg_attr(foo, warn(test_lint))] | ^^^^^^^^^ help: change it to: `clippy::test_lint` @@ -7,19 +7,19 @@ LL | #![cfg_attr(foo, warn(test_lint))] = note: `#[warn(renamed_and_removed_lints)]` on by default warning: lint name `clippy_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore - --> $DIR/lint-tool-test.rs:11:9 + --> $DIR/lint-tool-test.rs:12:9 | LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ help: change it to: `clippy::group` warning: lint name `test_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore - --> $DIR/lint-tool-test.rs:25:9 + --> $DIR/lint-tool-test.rs:26:9 | LL | #[allow(test_group)] | ^^^^^^^^^^ help: change it to: `clippy::test_group` warning: unknown lint: `this_lint_does_not_exist` - --> $DIR/lint-tool-test.rs:27:8 + --> $DIR/lint-tool-test.rs:28:8 | LL | #[deny(this_lint_does_not_exist)] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,32 +27,40 @@ LL | #[deny(this_lint_does_not_exist)] = note: `#[warn(unknown_lints)]` on by default warning: lint name `test_lint` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore - --> $DIR/lint-tool-test.rs:8:23 + --> $DIR/lint-tool-test.rs:9:23 | LL | #![cfg_attr(foo, warn(test_lint))] | ^^^^^^^^^ help: change it to: `clippy::test_lint` +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/lint-tool-test.rs:6:1 + | +LL | #![plugin(lint_tool_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + error: item is named 'lintme' - --> $DIR/lint-tool-test.rs:14:1 + --> $DIR/lint-tool-test.rs:15:1 | LL | fn lintme() { } | ^^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/lint-tool-test.rs:11:9 + --> $DIR/lint-tool-test.rs:12:9 | LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ = note: `#[deny(clippy::test_lint)]` implied by `#[deny(clippy::group)]` error: item is named 'lintmetoo' - --> $DIR/lint-tool-test.rs:22:5 + --> $DIR/lint-tool-test.rs:23:5 | LL | fn lintmetoo() { } | ^^^^^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/lint-tool-test.rs:11:9 + --> $DIR/lint-tool-test.rs:12:9 | LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ diff --git a/src/test/ui-fulldeps/llvm-pass-plugin.stderr b/src/test/ui-fulldeps/llvm-pass-plugin.stderr new file mode 100644 index 0000000000000..ebc092671a77c --- /dev/null +++ b/src/test/ui-fulldeps/llvm-pass-plugin.stderr @@ -0,0 +1,8 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/llvm-pass-plugin.rs:6:1 + | +LL | #![plugin(llvm_pass_plugin)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + diff --git a/src/test/ui-fulldeps/lto-syntax-extension.stderr b/src/test/ui-fulldeps/lto-syntax-extension.stderr new file mode 100644 index 0000000000000..509331ceb218f --- /dev/null +++ b/src/test/ui-fulldeps/lto-syntax-extension.stderr @@ -0,0 +1,8 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/lto-syntax-extension.rs:9:1 + | +LL | #![plugin(lto_syntax_extension_plugin)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + diff --git a/src/test/ui-fulldeps/macro-crate-rlib.rs b/src/test/ui-fulldeps/macro-crate-rlib.rs index 2962bb51fc418..b5038a58249d2 100644 --- a/src/test/ui-fulldeps/macro-crate-rlib.rs +++ b/src/test/ui-fulldeps/macro-crate-rlib.rs @@ -5,5 +5,6 @@ #![feature(plugin)] #![plugin(rlib_crate_test)] //~^ ERROR: plugin `rlib_crate_test` only found in rlib format, but must be available in dylib format +//~| WARN use of deprecated attribute `plugin`: compiler plugins are deprecated fn main() {} diff --git a/src/test/ui-fulldeps/macro-crate-rlib.stderr b/src/test/ui-fulldeps/macro-crate-rlib.stderr index a5a5456a316d1..47d5ecb3742a8 100644 --- a/src/test/ui-fulldeps/macro-crate-rlib.stderr +++ b/src/test/ui-fulldeps/macro-crate-rlib.stderr @@ -4,5 +4,13 @@ error[E0457]: plugin `rlib_crate_test` only found in rlib format, but must be av LL | #![plugin(rlib_crate_test)] | ^^^^^^^^^^^^^^^ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/macro-crate-rlib.rs:6:1 + | +LL | #![plugin(rlib_crate_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + error: aborting due to previous error diff --git a/src/test/ui-fulldeps/newtype_index.rs b/src/test/ui-fulldeps/newtype_index.rs index 336b584768fad..fe68b394e5a5c 100644 --- a/src/test/ui-fulldeps/newtype_index.rs +++ b/src/test/ui-fulldeps/newtype_index.rs @@ -2,10 +2,10 @@ #![feature(rustc_private)] -extern crate rustc_data_structures; +extern crate rustc_index; extern crate serialize as rustc_serialize; -use rustc_data_structures::{newtype_index, indexed_vec::Idx}; +use rustc_index::{newtype_index, vec::Idx}; newtype_index!(struct MyIdx { MAX = 0xFFFF_FFFA }); diff --git a/src/test/ui-fulldeps/outlive-expansion-phase.stderr b/src/test/ui-fulldeps/outlive-expansion-phase.stderr new file mode 100644 index 0000000000000..68e143d86eeb2 --- /dev/null +++ b/src/test/ui-fulldeps/outlive-expansion-phase.stderr @@ -0,0 +1,8 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/outlive-expansion-phase.rs:6:1 + | +LL | #![plugin(outlive_expansion_phase)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + diff --git a/src/test/ui-fulldeps/plugin-args-1.stderr b/src/test/ui-fulldeps/plugin-args-1.stderr new file mode 100644 index 0000000000000..0d01a859df8ef --- /dev/null +++ b/src/test/ui-fulldeps/plugin-args-1.stderr @@ -0,0 +1,8 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/plugin-args-1.rs:6:1 + | +LL | #![plugin(plugin_args)] + | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + diff --git a/src/test/ui-fulldeps/plugin-args-2.stderr b/src/test/ui-fulldeps/plugin-args-2.stderr new file mode 100644 index 0000000000000..2bbabd2013817 --- /dev/null +++ b/src/test/ui-fulldeps/plugin-args-2.stderr @@ -0,0 +1,8 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/plugin-args-2.rs:6:1 + | +LL | #![plugin(plugin_args())] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + diff --git a/src/test/ui-fulldeps/plugin-args-3.stderr b/src/test/ui-fulldeps/plugin-args-3.stderr new file mode 100644 index 0000000000000..bf4108bd7f8df --- /dev/null +++ b/src/test/ui-fulldeps/plugin-args-3.stderr @@ -0,0 +1,8 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/plugin-args-3.rs:6:1 + | +LL | #![plugin(plugin_args(hello(there), how(are="you")))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + diff --git a/src/test/ui-fulldeps/plugin-attr-register-deny.rs b/src/test/ui-fulldeps/plugin-attr-register-deny.rs index 8be73e330abf7..dd7c009388e2c 100644 --- a/src/test/ui-fulldeps/plugin-attr-register-deny.rs +++ b/src/test/ui-fulldeps/plugin-attr-register-deny.rs @@ -3,6 +3,7 @@ #![feature(plugin)] #![plugin(attr_plugin_test)] +//~^ WARN use of deprecated attribute `plugin` #![deny(unused_attributes)] #[baz] diff --git a/src/test/ui-fulldeps/plugin-attr-register-deny.stderr b/src/test/ui-fulldeps/plugin-attr-register-deny.stderr index 64a67f6e16036..a045782a95f77 100644 --- a/src/test/ui-fulldeps/plugin-attr-register-deny.stderr +++ b/src/test/ui-fulldeps/plugin-attr-register-deny.stderr @@ -1,23 +1,31 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/plugin-attr-register-deny.rs:5:1 + | +LL | #![plugin(attr_plugin_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + error: unused attribute - --> $DIR/plugin-attr-register-deny.rs:14:5 + --> $DIR/plugin-attr-register-deny.rs:15:5 | LL | #[bar] | ^^^^^^ | note: lint level defined here - --> $DIR/plugin-attr-register-deny.rs:6:9 + --> $DIR/plugin-attr-register-deny.rs:7:9 | LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/plugin-attr-register-deny.rs:14:5 + --> $DIR/plugin-attr-register-deny.rs:15:5 | LL | #[bar] | ^^^^^^ error: unused attribute - --> $DIR/plugin-attr-register-deny.rs:11:1 + --> $DIR/plugin-attr-register-deny.rs:12:1 | LL | #[foo] | ^^^^^^ diff --git a/src/test/ui-fulldeps/plugin-reexport.rs b/src/test/ui-fulldeps/plugin-reexport.rs index 4d8ede1680830..e92b020c0b413 100644 --- a/src/test/ui-fulldeps/plugin-reexport.rs +++ b/src/test/ui-fulldeps/plugin-reexport.rs @@ -4,6 +4,7 @@ #![feature(plugin)] #![plugin(attr_plugin_test)] +//~^ WARN use of deprecated attribute `plugin` pub use mac as reexport; //~ ERROR `mac` is private, and cannot be re-exported diff --git a/src/test/ui-fulldeps/plugin-reexport.stderr b/src/test/ui-fulldeps/plugin-reexport.stderr index 4ac64b8d04b87..52d27c32897a5 100644 --- a/src/test/ui-fulldeps/plugin-reexport.stderr +++ b/src/test/ui-fulldeps/plugin-reexport.stderr @@ -1,15 +1,23 @@ error[E0364]: `mac` is private, and cannot be re-exported - --> $DIR/plugin-reexport.rs:8:9 + --> $DIR/plugin-reexport.rs:9:9 | LL | pub use mac as reexport; | ^^^^^^^^^^^^^^^ | note: consider marking `mac` as `pub` in the imported module - --> $DIR/plugin-reexport.rs:8:9 + --> $DIR/plugin-reexport.rs:9:9 | LL | pub use mac as reexport; | ^^^^^^^^^^^^^^^ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/plugin-reexport.rs:6:1 + | +LL | #![plugin(attr_plugin_test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + error: aborting due to previous error For more information about this error, try `rustc --explain E0364`. diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index 09f58521e5d5c..d4aff73590734 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -32,13 +32,15 @@ use syntax::print::pprust; use syntax::ptr::P; -fn parse_expr(ps: &ParseSess, src: &str) -> P { +fn parse_expr(ps: &ParseSess, src: &str) -> Option> { let src_as_string = src.to_string(); - let mut p = parse::new_parser_from_source_str(ps, - FileName::Custom(src_as_string.clone()), - src_as_string); - p.parse_expr().unwrap() + let mut p = parse::new_parser_from_source_str( + ps, + FileName::Custom(src_as_string.clone()), + src_as_string, + ); + p.parse_expr().map_err(|mut e| e.cancel()).ok() } @@ -46,7 +48,7 @@ fn parse_expr(ps: &ParseSess, src: &str) -> P { fn expr(kind: ExprKind) -> P { P(Expr { id: DUMMY_NODE_ID, - node: kind, + kind, span: DUMMY_SP, attrs: ThinVec::new(), }) @@ -112,7 +114,6 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P)) { let decl = P(FnDecl { inputs: vec![], output: FunctionRetTy::Default(DUMMY_SP), - c_variadic: false, }); iter_exprs(depth - 1, &mut |e| g( ExprKind::Closure(CaptureBy::Value, @@ -150,12 +151,12 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P)) { iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e))); }, 19 => { - let ps = vec![P(Pat { + let pat = P(Pat { id: DUMMY_NODE_ID, - node: PatKind::Wild, + kind: PatKind::Wild, span: DUMMY_SP, - })]; - iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(ps.clone(), e))) + }); + iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(pat.clone(), e))) }, _ => panic!("bad counter value in iter_exprs"), } @@ -170,7 +171,7 @@ struct RemoveParens; impl MutVisitor for RemoveParens { fn visit_expr(&mut self, e: &mut P) { - match e.node.clone() { + match e.kind.clone() { ExprKind::Paren(inner) => *e = inner, _ => {} }; @@ -188,7 +189,7 @@ impl MutVisitor for AddParens { visit_clobber(e, |e| { P(Expr { id: DUMMY_NODE_ID, - node: ExprKind::Paren(e), + kind: ExprKind::Paren(e), span: DUMMY_SP, attrs: ThinVec::new(), }) @@ -209,22 +210,23 @@ fn run() { let printed = pprust::expr_to_string(&e); println!("printed: {}", printed); - let mut parsed = parse_expr(&ps, &printed); - - // We want to know if `parsed` is structurally identical to `e`, ignoring trivial - // differences like placement of `Paren`s or the exact ranges of node spans. - // Unfortunately, there is no easy way to make this comparison. Instead, we add `Paren`s - // everywhere we can, then pretty-print. This should give an unambiguous representation of - // each `Expr`, and it bypasses nearly all of the parenthesization logic, so we aren't - // relying on the correctness of the very thing we're testing. - RemoveParens.visit_expr(&mut e); - AddParens.visit_expr(&mut e); - let text1 = pprust::expr_to_string(&e); - RemoveParens.visit_expr(&mut parsed); - AddParens.visit_expr(&mut parsed); - let text2 = pprust::expr_to_string(&parsed); - assert!(text1 == text2, - "exprs are not equal:\n e = {:?}\n parsed = {:?}", - text1, text2); + // Ignore expressions with chained comparisons that fail to parse + if let Some(mut parsed) = parse_expr(&ps, &printed) { + // We want to know if `parsed` is structurally identical to `e`, ignoring trivial + // differences like placement of `Paren`s or the exact ranges of node spans. + // Unfortunately, there is no easy way to make this comparison. Instead, we add `Paren`s + // everywhere we can, then pretty-print. This should give an unambiguous representation + // of each `Expr`, and it bypasses nearly all of the parenthesization logic, so we + // aren't relying on the correctness of the very thing we're testing. + RemoveParens.visit_expr(&mut e); + AddParens.visit_expr(&mut e); + let text1 = pprust::expr_to_string(&e); + RemoveParens.visit_expr(&mut parsed); + AddParens.visit_expr(&mut parsed); + let text2 = pprust::expr_to_string(&parsed); + assert!(text1 == text2, + "exprs are not equal:\n e = {:?}\n parsed = {:?}", + text1, text2); + } }); } diff --git a/src/test/ui-fulldeps/roman-numerals-macro.stderr b/src/test/ui-fulldeps/roman-numerals-macro.stderr new file mode 100644 index 0000000000000..7ac619185a1e0 --- /dev/null +++ b/src/test/ui-fulldeps/roman-numerals-macro.stderr @@ -0,0 +1,8 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/roman-numerals-macro.rs:6:1 + | +LL | #![plugin(roman_numerals)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + diff --git a/src/test/ui/.gitattributes b/src/test/ui/.gitattributes index b62ade73aa993..489dc8ad1118c 100644 --- a/src/test/ui/.gitattributes +++ b/src/test/ui/.gitattributes @@ -1,2 +1,3 @@ lexer-crlf-line-endings-string-literal-doc-comment.rs -text trailing-carriage-return-in-string.rs -text +*.bin -text diff --git a/src/test/ui/abi-sysv64-arg-passing.rs b/src/test/ui/abi/abi-sysv64-arg-passing.rs similarity index 100% rename from src/test/ui/abi-sysv64-arg-passing.rs rename to src/test/ui/abi/abi-sysv64-arg-passing.rs diff --git a/src/test/ui/abi-sysv64-register-usage.rs b/src/test/ui/abi/abi-sysv64-register-usage.rs similarity index 100% rename from src/test/ui/abi-sysv64-register-usage.rs rename to src/test/ui/abi/abi-sysv64-register-usage.rs diff --git a/src/test/ui/abort-on-c-abi.rs b/src/test/ui/abi/abort-on-c-abi.rs similarity index 93% rename from src/test/ui/abort-on-c-abi.rs rename to src/test/ui/abi/abort-on-c-abi.rs index cd7dd1b6a452f..2f08730ec6132 100644 --- a/src/test/ui/abort-on-c-abi.rs +++ b/src/test/ui/abi/abort-on-c-abi.rs @@ -1,6 +1,7 @@ // run-pass #![allow(unused_must_use)] +#![feature(unwind_attributes)] // Since we mark some ABIs as "nounwind" to LLVM, we must make sure that // we never unwind through them. @@ -13,6 +14,7 @@ use std::io::prelude::*; use std::io; use std::process::{Command, Stdio}; +#[unwind(aborts)] // FIXME(#58794) extern "C" fn panic_in_ffi() { panic!("Test"); } diff --git a/src/test/ui/anon-extern-mod.rs b/src/test/ui/abi/anon-extern-mod.rs similarity index 100% rename from src/test/ui/anon-extern-mod.rs rename to src/test/ui/abi/anon-extern-mod.rs diff --git a/src/test/ui/auxiliary/anon-extern-mod-cross-crate-1.rs b/src/test/ui/abi/auxiliary/anon-extern-mod-cross-crate-1.rs similarity index 100% rename from src/test/ui/auxiliary/anon-extern-mod-cross-crate-1.rs rename to src/test/ui/abi/auxiliary/anon-extern-mod-cross-crate-1.rs diff --git a/src/test/ui/auxiliary/foreign_lib.rs b/src/test/ui/abi/auxiliary/foreign_lib.rs similarity index 100% rename from src/test/ui/auxiliary/foreign_lib.rs rename to src/test/ui/abi/auxiliary/foreign_lib.rs diff --git a/src/test/ui/c-stack-as-value.rs b/src/test/ui/abi/c-stack-as-value.rs similarity index 100% rename from src/test/ui/c-stack-as-value.rs rename to src/test/ui/abi/c-stack-as-value.rs diff --git a/src/test/ui/cabi-int-widening.rs b/src/test/ui/abi/cabi-int-widening.rs similarity index 100% rename from src/test/ui/cabi-int-widening.rs rename to src/test/ui/abi/cabi-int-widening.rs diff --git a/src/test/ui/consts/auxiliary/anon-extern-mod-cross-crate-1.rs b/src/test/ui/abi/consts/auxiliary/anon-extern-mod-cross-crate-1.rs similarity index 100% rename from src/test/ui/consts/auxiliary/anon-extern-mod-cross-crate-1.rs rename to src/test/ui/abi/consts/auxiliary/anon-extern-mod-cross-crate-1.rs diff --git a/src/test/ui/cross-crate/anon-extern-mod-cross-crate-2.rs b/src/test/ui/abi/cross-crate/anon-extern-mod-cross-crate-2.rs similarity index 100% rename from src/test/ui/cross-crate/anon-extern-mod-cross-crate-2.rs rename to src/test/ui/abi/cross-crate/anon-extern-mod-cross-crate-2.rs diff --git a/src/test/ui/cross-crate/auxiliary/anon-extern-mod-cross-crate-1.rs b/src/test/ui/abi/cross-crate/auxiliary/anon-extern-mod-cross-crate-1.rs similarity index 100% rename from src/test/ui/cross-crate/auxiliary/anon-extern-mod-cross-crate-1.rs rename to src/test/ui/abi/cross-crate/auxiliary/anon-extern-mod-cross-crate-1.rs diff --git a/src/test/ui/duplicated-external-mods.rs b/src/test/ui/abi/duplicated-external-mods.rs similarity index 100% rename from src/test/ui/duplicated-external-mods.rs rename to src/test/ui/abi/duplicated-external-mods.rs diff --git a/src/test/ui/extern/auxiliary/extern-crosscrate-source.rs b/src/test/ui/abi/extern/auxiliary/extern-crosscrate-source.rs similarity index 100% rename from src/test/ui/extern/auxiliary/extern-crosscrate-source.rs rename to src/test/ui/abi/extern/auxiliary/extern-crosscrate-source.rs diff --git a/src/test/ui/extern/extern-call-deep.rs b/src/test/ui/abi/extern/extern-call-deep.rs similarity index 100% rename from src/test/ui/extern/extern-call-deep.rs rename to src/test/ui/abi/extern/extern-call-deep.rs diff --git a/src/test/ui/extern/extern-call-deep2.rs b/src/test/ui/abi/extern/extern-call-deep2.rs similarity index 100% rename from src/test/ui/extern/extern-call-deep2.rs rename to src/test/ui/abi/extern/extern-call-deep2.rs diff --git a/src/test/ui/extern/extern-call-direct.rs b/src/test/ui/abi/extern/extern-call-direct.rs similarity index 100% rename from src/test/ui/extern/extern-call-direct.rs rename to src/test/ui/abi/extern/extern-call-direct.rs diff --git a/src/test/ui/extern/extern-call-indirect.rs b/src/test/ui/abi/extern/extern-call-indirect.rs similarity index 100% rename from src/test/ui/extern/extern-call-indirect.rs rename to src/test/ui/abi/extern/extern-call-indirect.rs diff --git a/src/test/ui/extern/extern-call-scrub.rs b/src/test/ui/abi/extern/extern-call-scrub.rs similarity index 100% rename from src/test/ui/extern/extern-call-scrub.rs rename to src/test/ui/abi/extern/extern-call-scrub.rs diff --git a/src/test/ui/extern/extern-crosscrate.rs b/src/test/ui/abi/extern/extern-crosscrate.rs similarity index 100% rename from src/test/ui/extern/extern-crosscrate.rs rename to src/test/ui/abi/extern/extern-crosscrate.rs diff --git a/src/test/ui/extern/extern-pass-TwoU16s.rs b/src/test/ui/abi/extern/extern-pass-TwoU16s.rs similarity index 100% rename from src/test/ui/extern/extern-pass-TwoU16s.rs rename to src/test/ui/abi/extern/extern-pass-TwoU16s.rs diff --git a/src/test/ui/extern/extern-pass-TwoU32s.rs b/src/test/ui/abi/extern/extern-pass-TwoU32s.rs similarity index 100% rename from src/test/ui/extern/extern-pass-TwoU32s.rs rename to src/test/ui/abi/extern/extern-pass-TwoU32s.rs diff --git a/src/test/ui/extern/extern-pass-TwoU64s.rs b/src/test/ui/abi/extern/extern-pass-TwoU64s.rs similarity index 100% rename from src/test/ui/extern/extern-pass-TwoU64s.rs rename to src/test/ui/abi/extern/extern-pass-TwoU64s.rs diff --git a/src/test/ui/extern/extern-pass-TwoU8s.rs b/src/test/ui/abi/extern/extern-pass-TwoU8s.rs similarity index 100% rename from src/test/ui/extern/extern-pass-TwoU8s.rs rename to src/test/ui/abi/extern/extern-pass-TwoU8s.rs diff --git a/src/test/ui/extern/extern-pass-char.rs b/src/test/ui/abi/extern/extern-pass-char.rs similarity index 100% rename from src/test/ui/extern/extern-pass-char.rs rename to src/test/ui/abi/extern/extern-pass-char.rs diff --git a/src/test/ui/extern/extern-pass-double.rs b/src/test/ui/abi/extern/extern-pass-double.rs similarity index 100% rename from src/test/ui/extern/extern-pass-double.rs rename to src/test/ui/abi/extern/extern-pass-double.rs diff --git a/src/test/ui/extern/extern-pass-empty.rs b/src/test/ui/abi/extern/extern-pass-empty.rs similarity index 100% rename from src/test/ui/extern/extern-pass-empty.rs rename to src/test/ui/abi/extern/extern-pass-empty.rs diff --git a/src/test/ui/extern/extern-pass-u32.rs b/src/test/ui/abi/extern/extern-pass-u32.rs similarity index 100% rename from src/test/ui/extern/extern-pass-u32.rs rename to src/test/ui/abi/extern/extern-pass-u32.rs diff --git a/src/test/ui/extern/extern-pass-u64.rs b/src/test/ui/abi/extern/extern-pass-u64.rs similarity index 100% rename from src/test/ui/extern/extern-pass-u64.rs rename to src/test/ui/abi/extern/extern-pass-u64.rs diff --git a/src/test/ui/extern/extern-return-TwoU16s.rs b/src/test/ui/abi/extern/extern-return-TwoU16s.rs similarity index 100% rename from src/test/ui/extern/extern-return-TwoU16s.rs rename to src/test/ui/abi/extern/extern-return-TwoU16s.rs diff --git a/src/test/ui/extern/extern-return-TwoU32s.rs b/src/test/ui/abi/extern/extern-return-TwoU32s.rs similarity index 100% rename from src/test/ui/extern/extern-return-TwoU32s.rs rename to src/test/ui/abi/extern/extern-return-TwoU32s.rs diff --git a/src/test/ui/extern/extern-return-TwoU64s.rs b/src/test/ui/abi/extern/extern-return-TwoU64s.rs similarity index 100% rename from src/test/ui/extern/extern-return-TwoU64s.rs rename to src/test/ui/abi/extern/extern-return-TwoU64s.rs diff --git a/src/test/ui/extern/extern-return-TwoU8s.rs b/src/test/ui/abi/extern/extern-return-TwoU8s.rs similarity index 100% rename from src/test/ui/extern/extern-return-TwoU8s.rs rename to src/test/ui/abi/extern/extern-return-TwoU8s.rs diff --git a/src/test/ui/foreign/auxiliary/foreign_lib.rs b/src/test/ui/abi/foreign/auxiliary/foreign_lib.rs similarity index 100% rename from src/test/ui/foreign/auxiliary/foreign_lib.rs rename to src/test/ui/abi/foreign/auxiliary/foreign_lib.rs diff --git a/src/test/ui/foreign/foreign-call-no-runtime.rs b/src/test/ui/abi/foreign/foreign-call-no-runtime.rs similarity index 100% rename from src/test/ui/foreign/foreign-call-no-runtime.rs rename to src/test/ui/abi/foreign/foreign-call-no-runtime.rs diff --git a/src/test/ui/foreign/foreign-dupe.rs b/src/test/ui/abi/foreign/foreign-dupe.rs similarity index 100% rename from src/test/ui/foreign/foreign-dupe.rs rename to src/test/ui/abi/foreign/foreign-dupe.rs diff --git a/src/test/ui/foreign/foreign-fn-with-byval.rs b/src/test/ui/abi/foreign/foreign-fn-with-byval.rs similarity index 100% rename from src/test/ui/foreign/foreign-fn-with-byval.rs rename to src/test/ui/abi/foreign/foreign-fn-with-byval.rs diff --git a/src/test/ui/foreign/foreign-no-abi.rs b/src/test/ui/abi/foreign/foreign-no-abi.rs similarity index 100% rename from src/test/ui/foreign/foreign-no-abi.rs rename to src/test/ui/abi/foreign/foreign-no-abi.rs diff --git a/src/test/ui/invoke-external-foreign.rs b/src/test/ui/abi/invoke-external-foreign.rs similarity index 100% rename from src/test/ui/invoke-external-foreign.rs rename to src/test/ui/abi/invoke-external-foreign.rs diff --git a/src/test/ui/lib-defaults.rs b/src/test/ui/abi/lib-defaults.rs similarity index 100% rename from src/test/ui/lib-defaults.rs rename to src/test/ui/abi/lib-defaults.rs diff --git a/src/test/ui/mir/mir_codegen_calls_variadic.rs b/src/test/ui/abi/mir/mir_codegen_calls_variadic.rs similarity index 100% rename from src/test/ui/mir/mir_codegen_calls_variadic.rs rename to src/test/ui/abi/mir/mir_codegen_calls_variadic.rs diff --git a/src/test/ui/numbers-arithmetic/i128-ffi.rs b/src/test/ui/abi/numbers-arithmetic/i128-ffi.rs similarity index 100% rename from src/test/ui/numbers-arithmetic/i128-ffi.rs rename to src/test/ui/abi/numbers-arithmetic/i128-ffi.rs diff --git a/src/test/ui/segfault-no-out-of-stack.rs b/src/test/ui/abi/segfault-no-out-of-stack.rs similarity index 100% rename from src/test/ui/segfault-no-out-of-stack.rs rename to src/test/ui/abi/segfault-no-out-of-stack.rs diff --git a/src/test/ui/stack-probes-lto.rs b/src/test/ui/abi/stack-probes-lto.rs similarity index 100% rename from src/test/ui/stack-probes-lto.rs rename to src/test/ui/abi/stack-probes-lto.rs diff --git a/src/test/ui/stack-probes.rs b/src/test/ui/abi/stack-probes.rs similarity index 100% rename from src/test/ui/stack-probes.rs rename to src/test/ui/abi/stack-probes.rs diff --git a/src/test/ui/statics/static-mut-foreign.rs b/src/test/ui/abi/statics/static-mut-foreign.rs similarity index 100% rename from src/test/ui/statics/static-mut-foreign.rs rename to src/test/ui/abi/statics/static-mut-foreign.rs diff --git a/src/test/ui/structs-enums/struct-return.rs b/src/test/ui/abi/struct-enums/struct-return.rs similarity index 100% rename from src/test/ui/structs-enums/struct-return.rs rename to src/test/ui/abi/struct-enums/struct-return.rs diff --git a/src/test/ui/union/union-c-interop.rs b/src/test/ui/abi/union/union-c-interop.rs similarity index 100% rename from src/test/ui/union/union-c-interop.rs rename to src/test/ui/abi/union/union-c-interop.rs diff --git a/src/test/ui/variadic-ffi.rs b/src/test/ui/abi/variadic-ffi.rs similarity index 100% rename from src/test/ui/variadic-ffi.rs rename to src/test/ui/abi/variadic-ffi.rs diff --git a/src/test/ui/allocator/hygiene.rs b/src/test/ui/allocator/hygiene.rs new file mode 100644 index 0000000000000..9bd8406a27608 --- /dev/null +++ b/src/test/ui/allocator/hygiene.rs @@ -0,0 +1,31 @@ +// run-pass +// no-prefer-dynamic +// aux-build:custom.rs +// aux-build:helper.rs + +#![allow(nonstandard_style)] + +extern crate custom; +extern crate helper; + +use custom::A; +use std::sync::atomic::{AtomicUsize, Ordering}; + +#[allow(dead_code)] +struct u8; +#[allow(dead_code)] +struct usize; +#[allow(dead_code)] +static arg0: () = (); + +#[global_allocator] +pub static GLOBAL: A = A(AtomicUsize::new(0)); + +fn main() { + let n = GLOBAL.0.load(Ordering::SeqCst); + let s = Box::new(0); + helper::work_with(&s); + assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1); + drop(s); + assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); +} diff --git a/src/test/ui/anon-params-denied-2018.rs b/src/test/ui/anon-params-denied-2018.rs index abff8275064e2..5721f5d235783 100644 --- a/src/test/ui/anon-params-denied-2018.rs +++ b/src/test/ui/anon-params-denied-2018.rs @@ -3,7 +3,7 @@ // edition:2018 trait T { - fn foo(i32); //~ expected one of `:` or `@`, found `)` + fn foo(i32); //~ expected one of `:`, `@`, or `|`, found `)` fn bar_with_default_impl(String, String) {} //~^ ERROR expected one of `:` diff --git a/src/test/ui/anon-params-denied-2018.stderr b/src/test/ui/anon-params-denied-2018.stderr index 438bcf4274daa..3fcf41a9a60a2 100644 --- a/src/test/ui/anon-params-denied-2018.stderr +++ b/src/test/ui/anon-params-denied-2018.stderr @@ -1,10 +1,14 @@ -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:6:15 | LL | fn foo(i32); - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this is a `self` type, give it a parameter name + | +LL | fn foo(self: i32); + | ^^^^^^^^^ help: if this was a parameter name, give it a type | LL | fn foo(i32: TypeName); @@ -14,13 +18,17 @@ help: if this is a type, explicitly ignore the parameter name LL | fn foo(_: i32); | ^^^^^^ -error: expected one of `:` or `@`, found `,` +error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/anon-params-denied-2018.rs:8:36 | LL | fn bar_with_default_impl(String, String) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this is a `self` type, give it a parameter name + | +LL | fn bar_with_default_impl(self: String, String) {} + | ^^^^^^^^^^^^ help: if this was a parameter name, give it a type | LL | fn bar_with_default_impl(String: TypeName, String) {} @@ -30,11 +38,11 @@ help: if this is a type, explicitly ignore the parameter name LL | fn bar_with_default_impl(_: String, String) {} | ^^^^^^^^^ -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:8:44 | LL | fn bar_with_default_impl(String, String) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -46,11 +54,11 @@ help: if this is a type, explicitly ignore the parameter name LL | fn bar_with_default_impl(String, _: String) {} | ^^^^^^^^^ -error: expected one of `:` or `@`, found `,` +error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/anon-params-denied-2018.rs:13:22 | LL | fn baz(a:usize, b, c: usize) -> usize { - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.rs b/src/test/ui/anonymous-higher-ranked-lifetime.rs index 8a1744ed5f8ae..898fe22fa234f 100644 --- a/src/test/ui/anonymous-higher-ranked-lifetime.rs +++ b/src/test/ui/anonymous-higher-ranked-lifetime.rs @@ -1,26 +1,15 @@ fn main() { f1(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch f2(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch f3(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch f4(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch f5(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch g1(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch g2(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch g3(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch g4(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch h1(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch h2(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch } // Basic diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.stderr b/src/test/ui/anonymous-higher-ranked-lifetime.stderr index 0ca3ca8437463..9be44c7f44807 100644 --- a/src/test/ui/anonymous-higher-ranked-lifetime.stderr +++ b/src/test/ui/anonymous-higher-ranked-lifetime.stderr @@ -5,306 +5,119 @@ LL | f1(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'r, 's> fn(&'r (), &'s ()) -> _` - | -note: required by `f1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:27:1 - | +... LL | fn f1(_: F) where F: Fn(&(), &()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -- ------------ required by this bound in `f1` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:2:5 - | -LL | f1(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&(), &()) -> _` - | -note: required by `f1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:27:1 - | -LL | fn f1(_: F) where F: Fn(&(), &()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:3:5 | LL | f2(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'a, 'r> fn(&'a (), &'r ()) -> _` - | -note: required by `f2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:28:1 - | +... LL | fn f2(_: F) where F: for<'a> Fn(&'a (), &()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -- ----------------------- required by this bound in `f2` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5 | -LL | f2(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&'a (), &()) -> _` - | -note: required by `f2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:28:1 - | -LL | fn f2(_: F) where F: for<'a> Fn(&'a (), &()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5 - | LL | f3(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'r> fn(&(), &'r ()) -> _` - | -note: required by `f3` - --> $DIR/anonymous-higher-ranked-lifetime.rs:29:1 - | -LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5 - | -LL | f3(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&(), &()) -> _` - | -note: required by `f3` - --> $DIR/anonymous-higher-ranked-lifetime.rs:29:1 - | +... LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -- --------------- required by this bound in `f3` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:5:5 | LL | f4(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'s, 'r> fn(&'s (), &'r ()) -> _` - | -note: required by `f4` - --> $DIR/anonymous-higher-ranked-lifetime.rs:30:1 - | +... LL | fn f4(_: F) where F: for<'r> Fn(&(), &'r ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -- ----------------------- required by this bound in `f4` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5 - | -LL | f4(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&(), &'r ()) -> _` - | -note: required by `f4` - --> $DIR/anonymous-higher-ranked-lifetime.rs:30:1 - | -LL | fn f4(_: F) where F: for<'r> Fn(&(), &'r ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5 | LL | f5(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'r> fn(&'r (), &'r ()) -> _` - | -note: required by `f5` - --> $DIR/anonymous-higher-ranked-lifetime.rs:31:1 - | +... LL | fn f5(_: F) where F: for<'r> Fn(&'r (), &'r ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -- -------------------------- required by this bound in `f5` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5 - | -LL | f5(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&'r (), &'r ()) -> _` - | -note: required by `f5` - --> $DIR/anonymous-higher-ranked-lifetime.rs:31:1 - | -LL | fn f5(_: F) where F: for<'r> Fn(&'r (), &'r ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:7:5 | LL | g1(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'r> fn(&'r (), std::boxed::Box<(dyn for<'s> std::ops::Fn(&'s ()) + 'static)>) -> _` - | -note: required by `g1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:34:1 - | +... LL | fn g1(_: F) where F: Fn(&(), Box) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -- ------------------------- required by this bound in `g1` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 - | -LL | g1(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _` - | -note: required by `g1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:34:1 - | -LL | fn g1(_: F) where F: Fn(&(), Box) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5 | LL | g2(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'r> fn(&'r (), for<'s> fn(&'s ())) -> _` - | -note: required by `g2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:35:1 - | -LL | fn g2(_: F) where F: Fn(&(), fn(&())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5 - | -LL | g2(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&(), for<'r> fn(&'r ())) -> _` - | -note: required by `g2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:35:1 - | +... LL | fn g2(_: F) where F: Fn(&(), fn(&())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -- ---------------- required by this bound in `g2` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:9:5 | LL | g3(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'s> fn(&'s (), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _` - | -note: required by `g3` - --> $DIR/anonymous-higher-ranked-lifetime.rs:36:1 - | +... LL | fn g3(_: F) where F: for<'s> Fn(&'s (), Box) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -- ------------------------------------ required by this bound in `g3` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5 - | -LL | g3(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&'s (), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _` - | -note: required by `g3` - --> $DIR/anonymous-higher-ranked-lifetime.rs:36:1 - | -LL | fn g3(_: F) where F: for<'s> Fn(&'s (), Box) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5 | LL | g4(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'s> fn(&'s (), for<'r> fn(&'r ())) -> _` - | -note: required by `g4` - --> $DIR/anonymous-higher-ranked-lifetime.rs:37:1 - | +... LL | fn g4(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -- --------------------------- required by this bound in `g4` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5 - | -LL | g4(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&(), for<'r> fn(&'r ())) -> _` - | -note: required by `g4` - --> $DIR/anonymous-higher-ranked-lifetime.rs:37:1 - | -LL | fn g4(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:11:5 | LL | h1(|_: (), _: (), _: (), _: ()| {}); | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` | | | expected signature of `for<'r, 's> fn(&'r (), std::boxed::Box<(dyn for<'t0> std::ops::Fn(&'t0 ()) + 'static)>, &'s (), for<'t0, 't1> fn(&'t0 (), &'t1 ())) -> _` - | -note: required by `h1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:40:1 - | +... LL | fn h1(_: F) where F: Fn(&(), Box, &(), fn(&(), &())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -- -------------------------------------------- required by this bound in `h1` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5 - | -LL | h1(|_: (), _: (), _: (), _: ()| {}); - | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` - | | - | expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>, &(), for<'r, 's> fn(&'r (), &'s ())) -> _` - | -note: required by `h1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:40:1 - | -LL | fn h1(_: F) where F: Fn(&(), Box, &(), fn(&(), &())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 | LL | h2(|_: (), _: (), _: (), _: ()| {}); | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` | | | expected signature of `for<'r, 't0> fn(&'r (), std::boxed::Box<(dyn for<'s> std::ops::Fn(&'s ()) + 'static)>, &'t0 (), for<'s, 't1> fn(&'s (), &'t1 ())) -> _` - | -note: required by `h2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:41:1 - | -LL | fn h2(_: F) where F: for<'t0> Fn(&(), Box, &'t0 (), fn(&(), &())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5 - | -LL | h2(|_: (), _: (), _: (), _: ()| {}); - | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` - | | - | expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>, &'t0 (), for<'r, 's> fn(&'r (), &'s ())) -> _` - | -note: required by `h2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:41:1 - | +... LL | fn h2(_: F) where F: for<'t0> Fn(&(), Box, &'t0 (), fn(&(), &())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -- --------------------------------------------------------- required by this bound in `h2` -error: aborting due to 22 previous errors +error: aborting due to 11 previous errors diff --git a/src/test/ui/array-break-length.rs b/src/test/ui/array-break-length.rs index 2696aea5e8993..959f4a2babbf8 100644 --- a/src/test/ui/array-break-length.rs +++ b/src/test/ui/array-break-length.rs @@ -1,11 +1,11 @@ fn main() { loop { - |_: [_; break]| {} //~ ERROR: `break` outside of loop + |_: [_; break]| {} //~ ERROR: `break` outside of a loop //~^ ERROR mismatched types } loop { - |_: [_; continue]| {} //~ ERROR: `continue` outside of loop + |_: [_; continue]| {} //~ ERROR: `continue` outside of a loop //~^ ERROR mismatched types } } diff --git a/src/test/ui/array-break-length.stderr b/src/test/ui/array-break-length.stderr index 0e0dc8f623e68..45f529bafe728 100644 --- a/src/test/ui/array-break-length.stderr +++ b/src/test/ui/array-break-length.stderr @@ -1,14 +1,14 @@ -error[E0268]: `break` outside of loop +error[E0268]: `break` outside of a loop --> $DIR/array-break-length.rs:3:17 | LL | |_: [_; break]| {} - | ^^^^^ cannot break outside of a loop + | ^^^^^ cannot `break` outside of a loop -error[E0268]: `continue` outside of loop +error[E0268]: `continue` outside of a loop --> $DIR/array-break-length.rs:8:17 | LL | |_: [_; continue]| {} - | ^^^^^^^^ cannot break outside of a loop + | ^^^^^^^^ cannot `continue` outside of a loop error[E0308]: mismatched types --> $DIR/array-break-length.rs:3:9 diff --git a/src/test/ui/asm/asm-out-read-uninit.rs b/src/test/ui/asm/asm-out-read-uninit.rs index 003f1fc5bb62b..78458ff60d4aa 100644 --- a/src/test/ui/asm/asm-out-read-uninit.rs +++ b/src/test/ui/asm/asm-out-read-uninit.rs @@ -20,7 +20,7 @@ pub fn main() { let x: isize; unsafe { asm!("mov $1, $0" : "=r"(x) : "r"(x)); - //~^ ERROR use of possibly uninitialized variable: `x` + //~^ ERROR use of possibly-uninitialized variable: `x` } foo(x); } diff --git a/src/test/ui/asm/asm-out-read-uninit.stderr b/src/test/ui/asm/asm-out-read-uninit.stderr index 6d0445d4b7a61..71aeda2ad4d2e 100644 --- a/src/test/ui/asm/asm-out-read-uninit.stderr +++ b/src/test/ui/asm/asm-out-read-uninit.stderr @@ -1,8 +1,8 @@ -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/asm-out-read-uninit.rs:22:43 | LL | asm!("mov $1, $0" : "=r"(x) : "r"(x)); - | ^ use of possibly uninitialized `x` + | ^ use of possibly-uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/associated-const/associated-const-array-len.stderr b/src/test/ui/associated-const/associated-const-array-len.stderr index ff56d112c8184..2fdfa3da3086c 100644 --- a/src/test/ui/associated-const/associated-const-array-len.stderr +++ b/src/test/ui/associated-const/associated-const-array-len.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/associated-const-array-len.rs:5:16 | +LL | const ID: usize; + | ---------------- required by `Foo::ID` +... LL | const X: [i32; ::ID] = [0, 1, 2]; | ^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32` - | -note: required by `Foo::ID` - --> $DIR/associated-const-array-len.rs:2:5 - | -LL | const ID: usize; - | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-const/associated-const-generic-obligations.stderr b/src/test/ui/associated-const/associated-const-generic-obligations.stderr index eeee26a75671f..ca6118cb3ba98 100644 --- a/src/test/ui/associated-const/associated-const-generic-obligations.stderr +++ b/src/test/ui/associated-const/associated-const-generic-obligations.stderr @@ -9,6 +9,8 @@ LL | const FROM: &'static str = "foo"; | = note: expected type `::Out` found type `&'static str` + = note: consider constraining the associated type `::Out` to `&'static str` or calling a method that returns `::Out` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error: aborting due to previous error diff --git a/src/test/ui/associated-const/associated-const-in-trait.stderr b/src/test/ui/associated-const/associated-const-in-trait.stderr index dff268a55c909..a5d7fc5b70246 100644 --- a/src/test/ui/associated-const/associated-const-in-trait.stderr +++ b/src/test/ui/associated-const/associated-const-in-trait.stderr @@ -1,10 +1,11 @@ error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/associated-const-in-trait.rs:9:6 | +LL | const N: usize; + | - the trait cannot contain associated consts like `N` +... LL | impl dyn Trait { | ^^^^^^^^^ the trait `Trait` cannot be made into an object - | - = note: the trait cannot contain associated consts like `N` error: aborting due to previous error diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr b/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr index 573b8ed39bcaa..30b6b4f3909b2 100644 --- a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr +++ b/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `A: Foo` is not satisfied --> $DIR/associated-const-type-parameter-arrays-2.rs:16:22 | +LL | const Y: usize; + | --------------- required by `Foo::Y` +... LL | let _array = [4; ::Y]; | ^^^^^^^^^^^^^ the trait `Foo` is not implemented for `A` | = help: consider adding a `where A: Foo` bound -note: required by `Foo::Y` - --> $DIR/associated-const-type-parameter-arrays-2.rs:2:5 - | -LL | const Y: usize; - | ^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr b/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr index bf1ee38571404..30fa9891a13e1 100644 --- a/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr +++ b/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `A: Foo` is not satisfied --> $DIR/associated-const-type-parameter-arrays.rs:16:23 | +LL | const Y: usize; + | --------------- required by `Foo::Y` +... LL | let _array: [u32; ::Y]; | ^^^^^^^^^^^^^ the trait `Foo` is not implemented for `A` | = help: consider adding a `where A: Foo` bound -note: required by `Foo::Y` - --> $DIR/associated-const-type-parameter-arrays.rs:2:5 - | -LL | const Y: usize; - | ^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs new file mode 100644 index 0000000000000..a58cec5342142 --- /dev/null +++ b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs @@ -0,0 +1,32 @@ +// This test documents that `type Out = Box>;` +// is allowed and will correctly reject an opaque `type Out` which +// does not satisfy the bound `::Assoc: Copy`. +// +// FIXME(rust-lang/lang): I think this behavior is logical if we want to allow +// `dyn Trait` but we should decide if we want that. // Centril +// +// Additionally, as reported in https://github.com/rust-lang/rust/issues/63594, +// we check that the spans for the error message are sane here. + +#![feature(associated_type_bounds)] + +fn main() {} + +trait Bar { type Assoc; } + +trait Thing { + type Out; + fn func() -> Self::Out; +} + +struct AssocNoCopy; +impl Bar for AssocNoCopy { type Assoc = String; } + +impl Thing for AssocNoCopy { + type Out = Box>; + //~^ ERROR the trait bound `std::string::String: std::marker::Copy` is not satisfied + + fn func() -> Self::Out { + Box::new(AssocNoCopy) + } +} diff --git a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr new file mode 100644 index 0000000000000..b6b49c2e90350 --- /dev/null +++ b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr @@ -0,0 +1,11 @@ +error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied + --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:26:28 + | +LL | type Out = Box>; + | ^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` + | + = note: the return type of a function must have a statically known size + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr index aebf29cc332ab..06e8230aa1589 100644 --- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr +++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr @@ -24,6 +24,9 @@ LL | | } error[E0277]: `<::C as std::iter::Iterator>::Item` cannot be sent between threads safely --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1 | +LL | trait Case1 { + | ----------- required by `Case1` +... LL | / fn assume_case1() { LL | | LL | | @@ -35,15 +38,13 @@ LL | | } | = help: the trait `std::marker::Send` is not implemented for `<::C as std::iter::Iterator>::Item` = help: consider adding a `where <::C as std::iter::Iterator>::Item: std::marker::Send` bound -note: required by `Case1` - --> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1 - | -LL | trait Case1 { - | ^^^^^^^^^^^ error[E0277]: `<::C as std::iter::Iterator>::Item` cannot be shared between threads safely --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1 | +LL | trait Case1 { + | ----------- required by `Case1` +... LL | / fn assume_case1() { LL | | LL | | @@ -55,15 +56,13 @@ LL | | } | = help: the trait `std::marker::Sync` is not implemented for `<::C as std::iter::Iterator>::Item` = help: consider adding a `where <::C as std::iter::Iterator>::Item: std::marker::Sync` bound -note: required by `Case1` - --> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1 - | -LL | trait Case1 { - | ^^^^^^^^^^^ error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug` --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1 | +LL | trait Case1 { + | ----------- required by `Case1` +... LL | / fn assume_case1() { LL | | LL | | @@ -74,11 +73,6 @@ LL | | } | |_^ `<_ as Lam<&'a u8>>::App` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | = help: the trait `for<'a> std::fmt::Debug` is not implemented for `<_ as Lam<&'a u8>>::App` -note: required by `Case1` - --> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1 - | -LL | trait Case1 { - | ^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs b/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs index 9db5233e21e57..ceca54b7cd75f 100644 --- a/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs +++ b/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![feature(associated_type_bounds)] diff --git a/src/test/ui/associated-type-bounds/duplicate.rs b/src/test/ui/associated-type-bounds/duplicate.rs index 1f2d755ed71ab..a89fd9807da8f 100644 --- a/src/test/ui/associated-type-bounds/duplicate.rs +++ b/src/test/ui/associated-type-bounds/duplicate.rs @@ -1,161 +1,184 @@ // compile-fail // ignore-tidy-linelength -// error-pattern:could not find defining uses #![feature(associated_type_bounds)] #![feature(type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] +#![feature(impl_trait_in_bindings)] //~ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash [incomplete_features] #![feature(untagged_unions)] use std::iter; struct SI1> { f: T } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] struct SI2> { f: T } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] struct SI3> { f: T } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] struct SW1 where T: Iterator { f: T } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] struct SW2 where T: Iterator { f: T } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] struct SW3 where T: Iterator { f: T } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] enum EI1> { V(T) } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] enum EI2> { V(T) } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] enum EI3> { V(T) } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] enum EW1 where T: Iterator { V(T) } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] enum EW2 where T: Iterator { V(T) } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] enum EW3 where T: Iterator { V(T) } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] union UI1> { f: T } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] union UI2> { f: T } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] union UI3> { f: T } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] union UW1 where T: Iterator { f: T } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] union UW2 where T: Iterator { f: T } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] union UW3 where T: Iterator { f: T } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] fn FI1>() {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] fn FI2>() {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] fn FI3>() {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] fn FW1() where T: Iterator {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] fn FW2() where T: Iterator {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] fn FW3() where T: Iterator {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] fn FRPIT1() -> impl Iterator { iter::empty() } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] fn FRPIT2() -> impl Iterator { iter::empty() } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] fn FRPIT3() -> impl Iterator { iter::empty() } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] fn FAPIT1(_: impl Iterator) {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] fn FAPIT2(_: impl Iterator) {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] fn FAPIT3(_: impl Iterator) {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] const CIT1: impl Iterator = iter::empty(); -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] const CIT2: impl Iterator = iter::empty(); -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] const CIT3: impl Iterator = iter::empty(); -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] static SIT1: impl Iterator = iter::empty(); -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] static SIT2: impl Iterator = iter::empty(); -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] static SIT3: impl Iterator = iter::empty(); -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] fn lit1() { let _: impl Iterator = iter::empty(); } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] fn lit2() { let _: impl Iterator = iter::empty(); } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] fn lit3() { let _: impl Iterator = iter::empty(); } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] type TAI1> = T; -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] type TAI2> = T; -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] type TAI3> = T; -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] type TAW1 where T: Iterator = T; -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] type TAW2 where T: Iterator = T; -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] type TAW3 where T: Iterator = T; -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] type ETAI1> = impl Copy; -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~| ERROR could not find defining uses +//~| ERROR could not find defining uses +//~| ERROR could not find defining uses type ETAI2> = impl Copy; -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~| ERROR could not find defining uses +//~| ERROR could not find defining uses +//~| ERROR could not find defining uses type ETAI3> = impl Copy; -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~| ERROR could not find defining uses +//~| ERROR could not find defining uses +//~| ERROR could not find defining uses type ETAI4 = impl Iterator; -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~| ERROR could not find defining uses +//~| ERROR could not find defining uses +//~| ERROR could not find defining uses type ETAI5 = impl Iterator; -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~| ERROR could not find defining uses +//~| ERROR could not find defining uses +//~| ERROR could not find defining uses type ETAI6 = impl Iterator; -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~| ERROR could not find defining uses +//~| ERROR could not find defining uses +//~| ERROR could not find defining uses trait TRI1> {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] trait TRI2> {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] trait TRI3> {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] trait TRS1: Iterator {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] trait TRS2: Iterator {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] trait TRS3: Iterator {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] trait TRW1 where T: Iterator {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] trait TRW2 where T: Iterator {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] trait TRW3 where T: Iterator {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] trait TRSW1 where Self: Iterator {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] trait TRSW2 where Self: Iterator {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] trait TRSW3 where Self: Iterator {} -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] trait TRA1 { type A: Iterator; } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] trait TRA2 { type A: Iterator; } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] trait TRA3 { type A: Iterator; } -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] type TADyn1 = dyn Iterator; -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~| ERROR could not find defining uses +//~| ERROR could not find defining uses type TADyn2 = Box>; -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~| ERROR could not find defining uses +//~| ERROR could not find defining uses type TADyn3 = dyn Iterator; -//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~| ERROR could not find defining uses +//~| ERROR could not find defining uses fn main() {} diff --git a/src/test/ui/associated-type-bounds/duplicate.stderr b/src/test/ui/associated-type-bounds/duplicate.stderr index 7f3a65ab696d6..e5e85d6856fd3 100644 --- a/src/test/ui/associated-type-bounds/duplicate.stderr +++ b/src/test/ui/associated-type-bounds/duplicate.stderr @@ -1,5 +1,5 @@ warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash - --> $DIR/duplicate.rs:7:12 + --> $DIR/duplicate.rs:6:12 | LL | #![feature(impl_trait_in_bindings)] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #![feature(impl_trait_in_bindings)] = note: `#[warn(incomplete_features)]` on by default error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:12:36 + --> $DIR/duplicate.rs:11:36 | LL | struct SI1> { f: T } | ---------- ^^^^^^^^^^ re-bound here @@ -15,7 +15,7 @@ LL | struct SI1> { f: T } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:14:36 + --> $DIR/duplicate.rs:13:36 | LL | struct SI2> { f: T } | ---------- ^^^^^^^^^^ re-bound here @@ -23,7 +23,7 @@ LL | struct SI2> { f: T } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:16:39 + --> $DIR/duplicate.rs:15:39 | LL | struct SI3> { f: T } | ------------- ^^^^^^^^^^^^^ re-bound here @@ -31,7 +31,7 @@ LL | struct SI3> { f: T } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:18:45 + --> $DIR/duplicate.rs:17:45 | LL | struct SW1 where T: Iterator { f: T } | ---------- ^^^^^^^^^^ re-bound here @@ -39,7 +39,7 @@ LL | struct SW1 where T: Iterator { f: T } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:20:45 + --> $DIR/duplicate.rs:19:45 | LL | struct SW2 where T: Iterator { f: T } | ---------- ^^^^^^^^^^ re-bound here @@ -47,7 +47,7 @@ LL | struct SW2 where T: Iterator { f: T } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:22:48 + --> $DIR/duplicate.rs:21:48 | LL | struct SW3 where T: Iterator { f: T } | ------------- ^^^^^^^^^^^^^ re-bound here @@ -55,7 +55,7 @@ LL | struct SW3 where T: Iterator { f: T } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:25:34 + --> $DIR/duplicate.rs:24:34 | LL | enum EI1> { V(T) } | ---------- ^^^^^^^^^^ re-bound here @@ -63,7 +63,7 @@ LL | enum EI1> { V(T) } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:27:34 + --> $DIR/duplicate.rs:26:34 | LL | enum EI2> { V(T) } | ---------- ^^^^^^^^^^ re-bound here @@ -71,7 +71,7 @@ LL | enum EI2> { V(T) } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:29:37 + --> $DIR/duplicate.rs:28:37 | LL | enum EI3> { V(T) } | ------------- ^^^^^^^^^^^^^ re-bound here @@ -79,7 +79,7 @@ LL | enum EI3> { V(T) } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:31:43 + --> $DIR/duplicate.rs:30:43 | LL | enum EW1 where T: Iterator { V(T) } | ---------- ^^^^^^^^^^ re-bound here @@ -87,7 +87,7 @@ LL | enum EW1 where T: Iterator { V(T) } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:33:43 + --> $DIR/duplicate.rs:32:43 | LL | enum EW2 where T: Iterator { V(T) } | ---------- ^^^^^^^^^^ re-bound here @@ -95,7 +95,7 @@ LL | enum EW2 where T: Iterator { V(T) } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:35:46 + --> $DIR/duplicate.rs:34:46 | LL | enum EW3 where T: Iterator { V(T) } | ------------- ^^^^^^^^^^^^^ re-bound here @@ -103,7 +103,7 @@ LL | enum EW3 where T: Iterator { V(T) } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:38:35 + --> $DIR/duplicate.rs:37:35 | LL | union UI1> { f: T } | ---------- ^^^^^^^^^^ re-bound here @@ -111,7 +111,7 @@ LL | union UI1> { f: T } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:40:35 + --> $DIR/duplicate.rs:39:35 | LL | union UI2> { f: T } | ---------- ^^^^^^^^^^ re-bound here @@ -119,7 +119,7 @@ LL | union UI2> { f: T } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:42:38 + --> $DIR/duplicate.rs:41:38 | LL | union UI3> { f: T } | ------------- ^^^^^^^^^^^^^ re-bound here @@ -127,7 +127,7 @@ LL | union UI3> { f: T } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:44:44 + --> $DIR/duplicate.rs:43:44 | LL | union UW1 where T: Iterator { f: T } | ---------- ^^^^^^^^^^ re-bound here @@ -135,7 +135,7 @@ LL | union UW1 where T: Iterator { f: T } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:46:44 + --> $DIR/duplicate.rs:45:44 | LL | union UW2 where T: Iterator { f: T } | ---------- ^^^^^^^^^^ re-bound here @@ -143,7 +143,7 @@ LL | union UW2 where T: Iterator { f: T } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:48:47 + --> $DIR/duplicate.rs:47:47 | LL | union UW3 where T: Iterator { f: T } | ------------- ^^^^^^^^^^^^^ re-bound here @@ -151,7 +151,7 @@ LL | union UW3 where T: Iterator { f: T } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:51:32 + --> $DIR/duplicate.rs:50:32 | LL | fn FI1>() {} | ---------- ^^^^^^^^^^ re-bound here @@ -159,7 +159,7 @@ LL | fn FI1>() {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:53:32 + --> $DIR/duplicate.rs:52:32 | LL | fn FI2>() {} | ---------- ^^^^^^^^^^ re-bound here @@ -167,7 +167,7 @@ LL | fn FI2>() {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:55:35 + --> $DIR/duplicate.rs:54:35 | LL | fn FI3>() {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -175,7 +175,7 @@ LL | fn FI3>() {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:57:43 + --> $DIR/duplicate.rs:56:43 | LL | fn FW1() where T: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -183,7 +183,7 @@ LL | fn FW1() where T: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:59:43 + --> $DIR/duplicate.rs:58:43 | LL | fn FW2() where T: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -191,7 +191,7 @@ LL | fn FW2() where T: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:61:46 + --> $DIR/duplicate.rs:60:46 | LL | fn FW3() where T: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -199,7 +199,7 @@ LL | fn FW3() where T: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:70:40 + --> $DIR/duplicate.rs:69:40 | LL | fn FAPIT1(_: impl Iterator) {} | ---------- ^^^^^^^^^^ re-bound here @@ -207,7 +207,7 @@ LL | fn FAPIT1(_: impl Iterator) {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:72:40 + --> $DIR/duplicate.rs:71:40 | LL | fn FAPIT2(_: impl Iterator) {} | ---------- ^^^^^^^^^^ re-bound here @@ -215,7 +215,7 @@ LL | fn FAPIT2(_: impl Iterator) {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:74:43 + --> $DIR/duplicate.rs:73:43 | LL | fn FAPIT3(_: impl Iterator) {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -223,7 +223,7 @@ LL | fn FAPIT3(_: impl Iterator) {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:64:42 + --> $DIR/duplicate.rs:63:42 | LL | fn FRPIT1() -> impl Iterator { iter::empty() } | ---------- ^^^^^^^^^^ re-bound here @@ -231,7 +231,7 @@ LL | fn FRPIT1() -> impl Iterator { iter::empty() } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:66:42 + --> $DIR/duplicate.rs:65:42 | LL | fn FRPIT2() -> impl Iterator { iter::empty() } | ---------- ^^^^^^^^^^ re-bound here @@ -239,7 +239,7 @@ LL | fn FRPIT2() -> impl Iterator { iter::empty() } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:68:45 + --> $DIR/duplicate.rs:67:45 | LL | fn FRPIT3() -> impl Iterator { iter::empty() } | ------------- ^^^^^^^^^^^^^ re-bound here @@ -247,7 +247,7 @@ LL | fn FRPIT3() -> impl Iterator { iter::empty() | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:77:39 + --> $DIR/duplicate.rs:76:39 | LL | const CIT1: impl Iterator = iter::empty(); | ---------- ^^^^^^^^^^ re-bound here @@ -255,7 +255,7 @@ LL | const CIT1: impl Iterator = iter::empty(); | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:79:39 + --> $DIR/duplicate.rs:78:39 | LL | const CIT2: impl Iterator = iter::empty(); | ---------- ^^^^^^^^^^ re-bound here @@ -263,7 +263,7 @@ LL | const CIT2: impl Iterator = iter::empty(); | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:81:42 + --> $DIR/duplicate.rs:80:42 | LL | const CIT3: impl Iterator = iter::empty(); | ------------- ^^^^^^^^^^^^^ re-bound here @@ -271,7 +271,7 @@ LL | const CIT3: impl Iterator = iter::empty(); | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:83:40 + --> $DIR/duplicate.rs:82:40 | LL | static SIT1: impl Iterator = iter::empty(); | ---------- ^^^^^^^^^^ re-bound here @@ -279,7 +279,7 @@ LL | static SIT1: impl Iterator = iter::empty(); | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:85:40 + --> $DIR/duplicate.rs:84:40 | LL | static SIT2: impl Iterator = iter::empty(); | ---------- ^^^^^^^^^^ re-bound here @@ -287,7 +287,7 @@ LL | static SIT2: impl Iterator = iter::empty(); | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:87:43 + --> $DIR/duplicate.rs:86:43 | LL | static SIT3: impl Iterator = iter::empty(); | ------------- ^^^^^^^^^^^^^ re-bound here @@ -295,7 +295,7 @@ LL | static SIT3: impl Iterator = iter::empty(); | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:90:46 + --> $DIR/duplicate.rs:89:46 | LL | fn lit1() { let _: impl Iterator = iter::empty(); } | ---------- ^^^^^^^^^^ re-bound here @@ -303,7 +303,7 @@ LL | fn lit1() { let _: impl Iterator = iter::empty(); } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:92:46 + --> $DIR/duplicate.rs:91:46 | LL | fn lit2() { let _: impl Iterator = iter::empty(); } | ---------- ^^^^^^^^^^ re-bound here @@ -311,7 +311,7 @@ LL | fn lit2() { let _: impl Iterator = iter::empty(); } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:94:49 + --> $DIR/duplicate.rs:93:49 | LL | fn lit3() { let _: impl Iterator = iter::empty(); } | ------------- ^^^^^^^^^^^^^ re-bound here @@ -319,7 +319,7 @@ LL | fn lit3() { let _: impl Iterator = iter::empt | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:97:35 + --> $DIR/duplicate.rs:96:35 | LL | type TAI1> = T; | ---------- ^^^^^^^^^^ re-bound here @@ -327,7 +327,7 @@ LL | type TAI1> = T; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:99:35 + --> $DIR/duplicate.rs:98:35 | LL | type TAI2> = T; | ---------- ^^^^^^^^^^ re-bound here @@ -335,7 +335,7 @@ LL | type TAI2> = T; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:101:38 + --> $DIR/duplicate.rs:100:38 | LL | type TAI3> = T; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -343,7 +343,7 @@ LL | type TAI3> = T; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:103:44 + --> $DIR/duplicate.rs:102:44 | LL | type TAW1 where T: Iterator = T; | ---------- ^^^^^^^^^^ re-bound here @@ -351,7 +351,7 @@ LL | type TAW1 where T: Iterator = T; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:105:44 + --> $DIR/duplicate.rs:104:44 | LL | type TAW2 where T: Iterator = T; | ---------- ^^^^^^^^^^ re-bound here @@ -359,7 +359,7 @@ LL | type TAW2 where T: Iterator = T; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:107:47 + --> $DIR/duplicate.rs:106:47 | LL | type TAW3 where T: Iterator = T; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -367,13 +367,13 @@ LL | type TAW3 where T: Iterator = T; | `Item` bound here first error: could not find defining uses - --> $DIR/duplicate.rs:110:1 + --> $DIR/duplicate.rs:109:1 | LL | type ETAI1> = impl Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:110:36 + --> $DIR/duplicate.rs:109:36 | LL | type ETAI1> = impl Copy; | ---------- ^^^^^^^^^^ re-bound here @@ -381,13 +381,13 @@ LL | type ETAI1> = impl Copy; | `Item` bound here first error: could not find defining uses - --> $DIR/duplicate.rs:112:1 + --> $DIR/duplicate.rs:114:1 | LL | type ETAI2> = impl Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:112:36 + --> $DIR/duplicate.rs:114:36 | LL | type ETAI2> = impl Copy; | ---------- ^^^^^^^^^^ re-bound here @@ -395,13 +395,13 @@ LL | type ETAI2> = impl Copy; | `Item` bound here first error: could not find defining uses - --> $DIR/duplicate.rs:114:1 + --> $DIR/duplicate.rs:119:1 | LL | type ETAI3> = impl Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:114:39 + --> $DIR/duplicate.rs:119:39 | LL | type ETAI3> = impl Copy; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -409,13 +409,13 @@ LL | type ETAI3> = impl Copy; | `Item` bound here first error: could not find defining uses - --> $DIR/duplicate.rs:116:1 + --> $DIR/duplicate.rs:124:1 | LL | type ETAI4 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:116:40 + --> $DIR/duplicate.rs:124:40 | LL | type ETAI4 = impl Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -423,13 +423,13 @@ LL | type ETAI4 = impl Iterator; | `Item` bound here first error: could not find defining uses - --> $DIR/duplicate.rs:118:1 + --> $DIR/duplicate.rs:129:1 | LL | type ETAI5 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:118:40 + --> $DIR/duplicate.rs:129:40 | LL | type ETAI5 = impl Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -437,13 +437,13 @@ LL | type ETAI5 = impl Iterator; | `Item` bound here first error: could not find defining uses - --> $DIR/duplicate.rs:120:1 + --> $DIR/duplicate.rs:134:1 | LL | type ETAI6 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:120:43 + --> $DIR/duplicate.rs:134:43 | LL | type ETAI6 = impl Iterator; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -451,7 +451,7 @@ LL | type ETAI6 = impl Iterator; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:123:36 + --> $DIR/duplicate.rs:140:36 | LL | trait TRI1> {} | ---------- ^^^^^^^^^^ re-bound here @@ -459,7 +459,7 @@ LL | trait TRI1> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:125:36 + --> $DIR/duplicate.rs:142:36 | LL | trait TRI2> {} | ---------- ^^^^^^^^^^ re-bound here @@ -467,7 +467,7 @@ LL | trait TRI2> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:127:39 + --> $DIR/duplicate.rs:144:39 | LL | trait TRI3> {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -475,7 +475,7 @@ LL | trait TRI3> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:129:34 + --> $DIR/duplicate.rs:146:34 | LL | trait TRS1: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -483,7 +483,7 @@ LL | trait TRS1: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:131:34 + --> $DIR/duplicate.rs:148:34 | LL | trait TRS2: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -491,7 +491,7 @@ LL | trait TRS2: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:133:37 + --> $DIR/duplicate.rs:150:37 | LL | trait TRS3: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -499,7 +499,7 @@ LL | trait TRS3: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:135:45 + --> $DIR/duplicate.rs:152:45 | LL | trait TRW1 where T: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -507,7 +507,7 @@ LL | trait TRW1 where T: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:137:45 + --> $DIR/duplicate.rs:154:45 | LL | trait TRW2 where T: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -515,7 +515,7 @@ LL | trait TRW2 where T: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:139:48 + --> $DIR/duplicate.rs:156:48 | LL | trait TRW3 where T: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -523,7 +523,7 @@ LL | trait TRW3 where T: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:141:46 + --> $DIR/duplicate.rs:158:46 | LL | trait TRSW1 where Self: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -531,7 +531,7 @@ LL | trait TRSW1 where Self: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:143:46 + --> $DIR/duplicate.rs:160:46 | LL | trait TRSW2 where Self: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -539,7 +539,7 @@ LL | trait TRSW2 where Self: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:145:49 + --> $DIR/duplicate.rs:162:49 | LL | trait TRSW3 where Self: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -547,7 +547,7 @@ LL | trait TRSW3 where Self: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:147:43 + --> $DIR/duplicate.rs:164:43 | LL | trait TRA1 { type A: Iterator; } | ---------- ^^^^^^^^^^ re-bound here @@ -555,7 +555,7 @@ LL | trait TRA1 { type A: Iterator; } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:149:43 + --> $DIR/duplicate.rs:166:43 | LL | trait TRA2 { type A: Iterator; } | ---------- ^^^^^^^^^^ re-bound here @@ -563,7 +563,7 @@ LL | trait TRA2 { type A: Iterator; } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:151:46 + --> $DIR/duplicate.rs:168:46 | LL | trait TRA3 { type A: Iterator; } | ------------- ^^^^^^^^^^^^^ re-bound here @@ -571,7 +571,7 @@ LL | trait TRA3 { type A: Iterator; } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:154:40 + --> $DIR/duplicate.rs:171:40 | LL | type TADyn1 = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -579,7 +579,7 @@ LL | type TADyn1 = dyn Iterator; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:156:44 + --> $DIR/duplicate.rs:175:44 | LL | type TADyn2 = Box>; | ---------- ^^^^^^^^^^ re-bound here @@ -587,7 +587,7 @@ LL | type TADyn2 = Box>; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:158:43 + --> $DIR/duplicate.rs:179:43 | LL | type TADyn3 = dyn Iterator; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -595,40 +595,112 @@ LL | type TADyn3 = dyn Iterator; | `Item` bound here first error: could not find defining uses + --> $DIR/duplicate.rs:109:24 + | +LL | type ETAI1> = impl Copy; + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/duplicate.rs:109:36 + | +LL | type ETAI1> = impl Copy; + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/duplicate.rs:114:24 + | +LL | type ETAI2> = impl Copy; + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/duplicate.rs:114:36 + | +LL | type ETAI2> = impl Copy; + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/duplicate.rs:119:24 + | +LL | type ETAI3> = impl Copy; + | ^^^^^^^^^^^^^ error: could not find defining uses + --> $DIR/duplicate.rs:119:39 + | +LL | type ETAI3> = impl Copy; + | ^^^^^^^^^^^^^ error: could not find defining uses + --> $DIR/duplicate.rs:124:28 + | +LL | type ETAI4 = impl Iterator; + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/duplicate.rs:124:40 + | +LL | type ETAI4 = impl Iterator; + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/duplicate.rs:129:28 + | +LL | type ETAI5 = impl Iterator; + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/duplicate.rs:129:40 + | +LL | type ETAI5 = impl Iterator; + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/duplicate.rs:134:28 + | +LL | type ETAI6 = impl Iterator; + | ^^^^^^^^^^^^^ error: could not find defining uses + --> $DIR/duplicate.rs:134:43 + | +LL | type ETAI6 = impl Iterator; + | ^^^^^^^^^^^^^ error: could not find defining uses + --> $DIR/duplicate.rs:171:28 + | +LL | type TADyn1 = dyn Iterator; + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/duplicate.rs:171:40 + | +LL | type TADyn1 = dyn Iterator; + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/duplicate.rs:175:32 + | +LL | type TADyn2 = Box>; + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/duplicate.rs:175:44 + | +LL | type TADyn2 = Box>; + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/duplicate.rs:179:28 + | +LL | type TADyn3 = dyn Iterator; + | ^^^^^^^^^^^^^ error: could not find defining uses + --> $DIR/duplicate.rs:179:43 + | +LL | type TADyn3 = dyn Iterator; + | ^^^^^^^^^^^^^ error: aborting due to 93 previous errors diff --git a/src/test/ui/associated-type-bounds/fn-apit.rs b/src/test/ui/associated-type-bounds/fn-apit.rs index 7e208b4e70d81..3c9f511338f69 100644 --- a/src/test/ui/associated-type-bounds/fn-apit.rs +++ b/src/test/ui/associated-type-bounds/fn-apit.rs @@ -1,6 +1,7 @@ // run-pass // aux-build:fn-aux.rs +#![allow(unused)] #![feature(associated_type_bounds)] extern crate fn_aux; diff --git a/src/test/ui/associated-type-bounds/fn-dyn-apit.rs b/src/test/ui/associated-type-bounds/fn-dyn-apit.rs index 9ff4a50e1e6e4..c4e8092c211d6 100644 --- a/src/test/ui/associated-type-bounds/fn-dyn-apit.rs +++ b/src/test/ui/associated-type-bounds/fn-dyn-apit.rs @@ -1,6 +1,7 @@ // run-pass // aux-build:fn-dyn-aux.rs +#![allow(unused)] #![feature(associated_type_bounds)] extern crate fn_dyn_aux; diff --git a/src/test/ui/associated-type-bounds/fn-inline.rs b/src/test/ui/associated-type-bounds/fn-inline.rs index 7b188763b7a5e..8fa7212d6275b 100644 --- a/src/test/ui/associated-type-bounds/fn-inline.rs +++ b/src/test/ui/associated-type-bounds/fn-inline.rs @@ -1,6 +1,7 @@ // run-pass // aux-build:fn-aux.rs +#![allow(unused)] #![feature(associated_type_bounds)] extern crate fn_aux; diff --git a/src/test/ui/associated-type-bounds/fn-where.rs b/src/test/ui/associated-type-bounds/fn-where.rs index 60d7149a56f25..9c4f82ac991c8 100644 --- a/src/test/ui/associated-type-bounds/fn-where.rs +++ b/src/test/ui/associated-type-bounds/fn-where.rs @@ -1,6 +1,7 @@ // run-pass // aux-build:fn-aux.rs +#![allow(unused)] #![feature(associated_type_bounds)] extern crate fn_aux; diff --git a/src/test/ui/associated-type-bounds/fn-wrap-apit.rs b/src/test/ui/associated-type-bounds/fn-wrap-apit.rs index 23790d416e1f7..96df13e372a24 100644 --- a/src/test/ui/associated-type-bounds/fn-wrap-apit.rs +++ b/src/test/ui/associated-type-bounds/fn-wrap-apit.rs @@ -2,6 +2,7 @@ // aux-build:fn-aux.rs #![feature(associated_type_bounds)] +#![allow(dead_code)] extern crate fn_aux; diff --git a/src/test/ui/associated-type-bounds/inside-adt.rs b/src/test/ui/associated-type-bounds/inside-adt.rs index 1257dc6e94b39..59ce9496d28f0 100644 --- a/src/test/ui/associated-type-bounds/inside-adt.rs +++ b/src/test/ui/associated-type-bounds/inside-adt.rs @@ -1,36 +1,35 @@ // compile-fail -// ignore-tidy-linelength -// error-pattern:could not find defining uses - #![feature(associated_type_bounds)] #![feature(untagged_unions)] struct S1 { f: dyn Iterator } -//~^ associated type bounds are not allowed within structs, enums, or unions -//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] +//~^ ERROR associated type bounds are not allowed within structs, enums, or unions +//~| ERROR could not find defining uses struct S2 { f: Box> } -//~^ associated type bounds are not allowed within structs, enums, or unions -//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] +//~^ ERROR associated type bounds are not allowed within structs, enums, or unions +//~| ERROR could not find defining uses struct S3 { f: dyn Iterator } -//~^ associated type bounds are not allowed within structs, enums, or unions -//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] +//~^ ERROR associated type bounds are not allowed within structs, enums, or unions +//~| ERROR could not find defining uses enum E1 { V(dyn Iterator) } -//~^ associated type bounds are not allowed within structs, enums, or unions -//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] +//~^ ERROR associated type bounds are not allowed within structs, enums, or unions +//~| ERROR could not find defining uses enum E2 { V(Box>) } -//~^ associated type bounds are not allowed within structs, enums, or unions -//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] +//~^ ERROR associated type bounds are not allowed within structs, enums, or unions +//~| ERROR could not find defining uses enum E3 { V(dyn Iterator) } -//~^ associated type bounds are not allowed within structs, enums, or unions -//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] +//~^ ERROR associated type bounds are not allowed within structs, enums, or unions +//~| ERROR could not find defining uses union U1 { f: dyn Iterator } -//~^ associated type bounds are not allowed within structs, enums, or unions -//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] +//~^ ERROR associated type bounds are not allowed within structs, enums, or unions +//~| ERROR could not find defining uses union U2 { f: Box> } -//~^ associated type bounds are not allowed within structs, enums, or unions -//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] +//~^ ERROR associated type bounds are not allowed within structs, enums, or unions +//~| ERROR could not find defining uses union U3 { f: dyn Iterator } -//~^ associated type bounds are not allowed within structs, enums, or unions -//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] +//~^ ERROR associated type bounds are not allowed within structs, enums, or unions +//~| ERROR could not find defining uses + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/inside-adt.stderr b/src/test/ui/associated-type-bounds/inside-adt.stderr index 7bdd71b8296ff..9c4d03e900940 100644 --- a/src/test/ui/associated-type-bounds/inside-adt.stderr +++ b/src/test/ui/associated-type-bounds/inside-adt.stderr @@ -1,79 +1,110 @@ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:8:29 + --> $DIR/inside-adt.rs:5:29 | LL | struct S1 { f: dyn Iterator } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:11:33 + --> $DIR/inside-adt.rs:8:33 | LL | struct S2 { f: Box> } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:14:29 + --> $DIR/inside-adt.rs:11:29 | LL | struct S3 { f: dyn Iterator } | ^^^^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:18:26 + --> $DIR/inside-adt.rs:15:26 | LL | enum E1 { V(dyn Iterator) } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:21:30 + --> $DIR/inside-adt.rs:18:30 | LL | enum E2 { V(Box>) } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:24:26 + --> $DIR/inside-adt.rs:21:26 | LL | enum E3 { V(dyn Iterator) } | ^^^^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:28:28 + --> $DIR/inside-adt.rs:25:28 | LL | union U1 { f: dyn Iterator } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:31:32 + --> $DIR/inside-adt.rs:28:32 | LL | union U2 { f: Box> } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:34:28 + --> $DIR/inside-adt.rs:31:28 | LL | union U3 { f: dyn Iterator } | ^^^^^^^^^^^^^ -error[E0601]: `main` function not found in crate `inside_adt` - | - = note: consider adding a `main` function to `$DIR/inside-adt.rs` - error: could not find defining uses + --> $DIR/inside-adt.rs:5:29 + | +LL | struct S1 { f: dyn Iterator } + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/inside-adt.rs:8:33 + | +LL | struct S2 { f: Box> } + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/inside-adt.rs:11:29 + | +LL | struct S3 { f: dyn Iterator } + | ^^^^^^^^^^^^^ error: could not find defining uses + --> $DIR/inside-adt.rs:15:26 + | +LL | enum E1 { V(dyn Iterator) } + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/inside-adt.rs:18:30 + | +LL | enum E2 { V(Box>) } + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/inside-adt.rs:21:26 + | +LL | enum E3 { V(dyn Iterator) } + | ^^^^^^^^^^^^^ error: could not find defining uses + --> $DIR/inside-adt.rs:25:28 + | +LL | union U1 { f: dyn Iterator } + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/inside-adt.rs:28:32 + | +LL | union U2 { f: Box> } + | ^^^^^^^^^^ error: could not find defining uses + --> $DIR/inside-adt.rs:31:28 + | +LL | union U3 { f: dyn Iterator } + | ^^^^^^^^^^^^^ -error: aborting due to 19 previous errors +error: aborting due to 18 previous errors -For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/associated-type-bounds/struct-bounds.rs b/src/test/ui/associated-type-bounds/struct-bounds.rs index 2d189cd66724a..2c1ce1c3785ae 100644 --- a/src/test/ui/associated-type-bounds/struct-bounds.rs +++ b/src/test/ui/associated-type-bounds/struct-bounds.rs @@ -1,5 +1,6 @@ // run-pass +#![allow(unused)] #![feature(associated_type_bounds)] trait Tr1 { type As1; } diff --git a/src/test/ui/associated-type/associated-type-projection-from-supertrait.rs b/src/test/ui/associated-type/associated-type-projection-from-supertrait.rs index 06dfe490b8bd3..7e05bcd309a4f 100644 --- a/src/test/ui/associated-type/associated-type-projection-from-supertrait.rs +++ b/src/test/ui/associated-type/associated-type-projection-from-supertrait.rs @@ -12,30 +12,22 @@ pub trait Car : Vehicle { fn chip_paint(&self, c: Self::Color) { } } -/////////////////////////////////////////////////////////////////////////// - struct Black; struct ModelT; impl Vehicle for ModelT { type Color = Black; } impl Car for ModelT { } -/////////////////////////////////////////////////////////////////////////// - struct Blue; struct ModelU; impl Vehicle for ModelU { type Color = Blue; } impl Car for ModelU { } -/////////////////////////////////////////////////////////////////////////// - fn dent(c: C, color: C::Color) { c.chip_paint(color) } fn a() { dent(ModelT, Black); } fn b() { dent(ModelT, Blue); } //~ ERROR mismatched types fn c() { dent(ModelU, Black); } //~ ERROR mismatched types fn d() { dent(ModelU, Blue); } -/////////////////////////////////////////////////////////////////////////// - fn e() { ModelT.chip_paint(Black); } fn f() { ModelT.chip_paint(Blue); } //~ ERROR mismatched types fn g() { ModelU.chip_paint(Black); } //~ ERROR mismatched types diff --git a/src/test/ui/associated-type/associated-type-projection-from-supertrait.stderr b/src/test/ui/associated-type/associated-type-projection-from-supertrait.stderr index 06f1a1cc64c42..4ba4925ef1b37 100644 --- a/src/test/ui/associated-type/associated-type-projection-from-supertrait.stderr +++ b/src/test/ui/associated-type/associated-type-projection-from-supertrait.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/associated-type-projection-from-supertrait.rs:33:23 + --> $DIR/associated-type-projection-from-supertrait.rs:27:23 | LL | fn b() { dent(ModelT, Blue); } | ^^^^ expected struct `Black`, found struct `Blue` @@ -8,7 +8,7 @@ LL | fn b() { dent(ModelT, Blue); } found type `Blue` error[E0308]: mismatched types - --> $DIR/associated-type-projection-from-supertrait.rs:34:23 + --> $DIR/associated-type-projection-from-supertrait.rs:28:23 | LL | fn c() { dent(ModelU, Black); } | ^^^^^ expected struct `Blue`, found struct `Black` @@ -17,7 +17,7 @@ LL | fn c() { dent(ModelU, Black); } found type `Black` error[E0308]: mismatched types - --> $DIR/associated-type-projection-from-supertrait.rs:40:28 + --> $DIR/associated-type-projection-from-supertrait.rs:32:28 | LL | fn f() { ModelT.chip_paint(Blue); } | ^^^^ expected struct `Black`, found struct `Blue` @@ -26,7 +26,7 @@ LL | fn f() { ModelT.chip_paint(Blue); } found type `Blue` error[E0308]: mismatched types - --> $DIR/associated-type-projection-from-supertrait.rs:41:28 + --> $DIR/associated-type-projection-from-supertrait.rs:33:28 | LL | fn g() { ModelU.chip_paint(Black); } | ^^^^^ expected struct `Blue`, found struct `Black` diff --git a/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.rs b/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.rs index 653130843c8de..6b2bbbe2e4fb9 100644 --- a/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.rs +++ b/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.rs @@ -11,22 +11,16 @@ pub trait Car : Vehicle { fn honk(&self) { } } -/////////////////////////////////////////////////////////////////////////// - struct Black; struct ModelT; impl Vehicle for ModelT { type Color = Black; } impl Car for ModelT { } -/////////////////////////////////////////////////////////////////////////// - struct Blue; struct ModelU; impl Vehicle for ModelU { type Color = Blue; } impl Car for ModelU { } -/////////////////////////////////////////////////////////////////////////// - fn black_car>(c: C) { } diff --git a/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.stderr b/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.stderr index 4b548604983df..6a2135ca46445 100644 --- a/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.stderr +++ b/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.stderr @@ -1,30 +1,26 @@ error[E0271]: type mismatch resolving `::Color == Blue` - --> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:37:10 + --> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:31:10 | +LL | fn blue_car>(c: C) { + | -------- ---------- required by this bound in `blue_car` +... LL | fn b() { blue_car(ModelT); } | ^^^^^^^^ expected struct `Black`, found struct `Blue` | = note: expected type `Black` found type `Blue` -note: required by `blue_car` - --> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:33:1 - | -LL | fn blue_car>(c: C) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0271]: type mismatch resolving `::Color == Black` - --> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:38:10 + --> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:32:10 | +LL | fn black_car>(c: C) { + | --------- ----------- required by this bound in `black_car` +... LL | fn c() { black_car(ModelU); } | ^^^^^^^^^ expected struct `Blue`, found struct `Black` | = note: expected type `Blue` found type `Black` -note: required by `black_car` - --> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:30:1 - | -LL | fn black_car>(c: C) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/associated-types-bound-failure.stderr b/src/test/ui/associated-types/associated-types-bound-failure.stderr index 502fb4f1c3033..85acf134d51d5 100644 --- a/src/test/ui/associated-types/associated-types-bound-failure.stderr +++ b/src/test/ui/associated-types/associated-types-bound-failure.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `::R: ToInt` is not satisfied - --> $DIR/associated-types-bound-failure.rs:17:5 + --> $DIR/associated-types-bound-failure.rs:17:19 | +LL | fn to_int(&self) -> isize; + | -------------------------- required by `ToInt::to_int` +... LL | ToInt::to_int(&g.get()) - | ^^^^^^^^^^^^^ the trait `ToInt` is not implemented for `::R` + | ^^^^^^^^ the trait `ToInt` is not implemented for `::R` | = help: consider adding a `where ::R: ToInt` bound -note: required by `ToInt::to_int` - --> $DIR/associated-types-bound-failure.rs:4:5 - | -LL | fn to_int(&self) -> isize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-eq-3.stderr b/src/test/ui/associated-types/associated-types-eq-3.stderr index 66fa4c288ca46..83d89924944ab 100644 --- a/src/test/ui/associated-types/associated-types-eq-3.stderr +++ b/src/test/ui/associated-types/associated-types-eq-3.stderr @@ -6,20 +6,20 @@ LL | let _: Bar = x.boo(); | = note: expected type `Bar` found type `::A` + = note: consider constraining the associated type `::A` to `Bar` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0271]: type mismatch resolving `::A == Bar` --> $DIR/associated-types-eq-3.rs:38:5 | +LL | fn foo1>(x: I) { + | ---- ----- required by this bound in `foo1` +... LL | foo1(a); | ^^^^ expected usize, found struct `Bar` | = note: expected type `usize` found type `Bar` -note: required by `foo1` - --> $DIR/associated-types-eq-3.rs:18:1 - | -LL | fn foo1>(x: I) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0271]: type mismatch resolving `::A == Bar` --> $DIR/associated-types-eq-3.rs:41:9 diff --git a/src/test/ui/associated-types/associated-types-eq-hr.stderr b/src/test/ui/associated-types/associated-types-eq-hr.stderr index 353829c2f7631..45b6cc9ba5f98 100644 --- a/src/test/ui/associated-types/associated-types-eq-hr.stderr +++ b/src/test/ui/associated-types/associated-types-eq-hr.stderr @@ -1,124 +1,94 @@ error[E0271]: type mismatch resolving `for<'x> >::A == &'x isize` --> $DIR/associated-types-eq-hr.rs:82:5 | +LL | fn foo() + | --- +LL | where T : for<'x> TheTrait<&'x isize, A = &'x isize> + | ------------- required by this bound in `foo` +... LL | foo::(); | ^^^^^^^^^^^^^^^^^ expected usize, found isize | = note: expected type `&usize` found type `&isize` -note: required by `foo` - --> $DIR/associated-types-eq-hr.rs:44:1 - | -LL | / fn foo() -LL | | where T : for<'x> TheTrait<&'x isize, A = &'x isize> -LL | | { -LL | | // ok for IntStruct, but not UintStruct -LL | | } - | |_^ error[E0271]: type mismatch resolving `for<'x> >::A == &'x usize` --> $DIR/associated-types-eq-hr.rs:86:5 | +LL | fn bar() + | --- +LL | where T : for<'x> TheTrait<&'x isize, A = &'x usize> + | ------------- required by this bound in `bar` +... LL | bar::(); | ^^^^^^^^^^^^^^^^ expected isize, found usize | = note: expected type `&isize` found type `&usize` -note: required by `bar` - --> $DIR/associated-types-eq-hr.rs:50:1 - | -LL | / fn bar() -LL | | where T : for<'x> TheTrait<&'x isize, A = &'x usize> -LL | | { -LL | | // ok for UintStruct, but not IntStruct -LL | | } - | |_^ error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied - --> $DIR/associated-types-eq-hr.rs:91:5 + --> $DIR/associated-types-eq-hr.rs:91:17 | +LL | fn tuple_one() + | --------- +LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize> + | ---------------------------------------------------------- required by this bound in `tuple_one` +... LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` + | ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` | = help: the following implementations were found: > -note: required by `tuple_one` - --> $DIR/associated-types-eq-hr.rs:56:1 - | -LL | / fn tuple_one() -LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize> -LL | | { -LL | | // not ok for tuple, two lifetimes and we pick first -LL | | } - | |_^ error[E0271]: type mismatch resolving `for<'x, 'y> >::A == &'x isize` --> $DIR/associated-types-eq-hr.rs:91:5 | +LL | fn tuple_one() + | --------- +LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize> + | ------------- required by this bound in `tuple_one` +... LL | tuple_one::(); | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime - | -note: required by `tuple_one` - --> $DIR/associated-types-eq-hr.rs:56:1 - | -LL | / fn tuple_one() -LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize> -LL | | { -LL | | // not ok for tuple, two lifetimes and we pick first -LL | | } - | |_^ error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied - --> $DIR/associated-types-eq-hr.rs:97:5 + --> $DIR/associated-types-eq-hr.rs:97:17 | +LL | fn tuple_two() + | --------- +LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize> + | ---------------------------------------------------------- required by this bound in `tuple_two` +... LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` + | ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` | = help: the following implementations were found: > -note: required by `tuple_two` - --> $DIR/associated-types-eq-hr.rs:62:1 - | -LL | / fn tuple_two() -LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize> -LL | | { -LL | | // not ok for tuple, two lifetimes and we pick second -LL | | } - | |_^ error[E0271]: type mismatch resolving `for<'x, 'y> >::A == &'y isize` --> $DIR/associated-types-eq-hr.rs:97:5 | +LL | fn tuple_two() + | --------- +LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize> + | ------------- required by this bound in `tuple_two` +... LL | tuple_two::(); | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime - | -note: required by `tuple_two` - --> $DIR/associated-types-eq-hr.rs:62:1 - | -LL | / fn tuple_two() -LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize> -LL | | { -LL | | // not ok for tuple, two lifetimes and we pick second -LL | | } - | |_^ error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied - --> $DIR/associated-types-eq-hr.rs:107:5 + --> $DIR/associated-types-eq-hr.rs:107:18 | +LL | fn tuple_four() + | ---------- +LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)> + | ------------------------------------------- required by this bound in `tuple_four` +... LL | tuple_four::(); - | ^^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` + | ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` | = help: the following implementations were found: > -note: required by `tuple_four` - --> $DIR/associated-types-eq-hr.rs:74:1 - | -LL | / fn tuple_four() -LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)> -LL | | { -LL | | // not ok for tuple, two lifetimes, and lifetime matching is invariant -LL | | } - | |_^ error: aborting due to 7 previous errors diff --git a/src/test/ui/associated-types/associated-types-issue-20346.stderr b/src/test/ui/associated-types/associated-types-issue-20346.stderr index 7d5b16c6e62d0..c8f8725afc45c 100644 --- a/src/test/ui/associated-types/associated-types-issue-20346.stderr +++ b/src/test/ui/associated-types/associated-types-issue-20346.stderr @@ -1,16 +1,16 @@ error[E0271]: type mismatch resolving ` as Iterator>::Item == std::option::Option` --> $DIR/associated-types-issue-20346.rs:34:5 | +LL | fn is_iterator_of>(_: &I) {} + | -------------- ------ required by this bound in `is_iterator_of` +... LL | is_iterator_of::, _>(&adapter); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found enum `std::option::Option` | = note: expected type `T` found type `std::option::Option` -note: required by `is_iterator_of` - --> $DIR/associated-types-issue-20346.rs:15:1 - | -LL | fn is_iterator_of>(_: &I) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: type parameters must be constrained to match other types + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr b/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr index 2926bdae0525b..c7de186c1d3e0 100644 --- a/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr +++ b/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr @@ -3,28 +3,28 @@ error[E0271]: type mismatch resolving `::Y == i32` | LL | want_y(t); | ^^^^^^ expected associated type, found i32 +... +LL | fn want_y>(t: &T) { } + | ------ ----- required by this bound in `want_y` | = note: expected type `::Y` found type `i32` -note: required by `want_y` - --> $DIR/associated-types-multiple-types-one-trait.rs:44:1 - | -LL | fn want_y>(t: &T) { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: consider constraining the associated type `::Y` to `i32` or calling a method that returns `::Y` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0271]: type mismatch resolving `::X == u32` --> $DIR/associated-types-multiple-types-one-trait.rs:18:5 | LL | want_x(t); | ^^^^^^ expected associated type, found u32 +... +LL | fn want_x>(t: &T) { } + | ------ ----- required by this bound in `want_x` | = note: expected type `::X` found type `u32` -note: required by `want_x` - --> $DIR/associated-types-multiple-types-one-trait.rs:42:1 - | -LL | fn want_x>(t: &T) { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: consider constraining the associated type `::X` to `u32` or calling a method that returns `::X` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/associated-types-overridden-binding.rs b/src/test/ui/associated-types/associated-types-overridden-binding.rs index fa1889389fd5c..9a64a06c31bad 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding.rs +++ b/src/test/ui/associated-types/associated-types-overridden-binding.rs @@ -1,10 +1,10 @@ #![feature(trait_alias)] trait Foo: Iterator {} -trait Bar: Foo {} //~ ERROR type annotations required +trait Bar: Foo {} //~ ERROR type annotations needed trait I32Iterator = Iterator; -trait U32Iterator = I32Iterator; +trait U32Iterator = I32Iterator; //~ ERROR type annotations needed fn main() { let _: &dyn I32Iterator; diff --git a/src/test/ui/associated-types/associated-types-overridden-binding.stderr b/src/test/ui/associated-types/associated-types-overridden-binding.stderr index a26ee23894f6d..5ef1b23cbcd21 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding.stderr +++ b/src/test/ui/associated-types/associated-types-overridden-binding.stderr @@ -1,15 +1,18 @@ -error[E0284]: type annotations required: cannot resolve `::Item == i32` +error[E0284]: type annotations needed: cannot resolve `::Item == i32` --> $DIR/associated-types-overridden-binding.rs:4:1 | +LL | trait Foo: Iterator {} + | ------------------------------- required by `Foo` LL | trait Bar: Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0282]: type annotations needed + --> $DIR/associated-types-overridden-binding.rs:7:1 | -note: required by `Foo` - --> $DIR/associated-types-overridden-binding.rs:3:1 - | -LL | trait Foo: Iterator {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait U32Iterator = I32Iterator; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0284`. +Some errors have detailed explanations: E0282, E0284. +For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/associated-types/associated-types-path-2.stderr b/src/test/ui/associated-types/associated-types-path-2.stderr index 1405cb1b4736c..bb2e7251849d3 100644 --- a/src/test/ui/associated-types/associated-types-path-2.stderr +++ b/src/test/ui/associated-types/associated-types-path-2.stderr @@ -11,14 +11,11 @@ LL | f1(2i32, 4u32); error[E0277]: the trait bound `u32: Foo` is not satisfied --> $DIR/associated-types-path-2.rs:29:5 | +LL | pub fn f1(a: T, x: T::A) {} + | -- --- required by this bound in `f1` +... LL | f1(2u32, 4u32); | ^^ the trait `Foo` is not implemented for `u32` - | -note: required by `f1` - --> $DIR/associated-types-path-2.rs:13:1 - | -LL | pub fn f1(a: T, x: T::A) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `u32: Foo` is not satisfied --> $DIR/associated-types-path-2.rs:29:5 @@ -29,14 +26,11 @@ LL | f1(2u32, 4u32); error[E0277]: the trait bound `u32: Foo` is not satisfied --> $DIR/associated-types-path-2.rs:35:5 | +LL | pub fn f1(a: T, x: T::A) {} + | -- --- required by this bound in `f1` +... LL | f1(2u32, 4i32); | ^^ the trait `Foo` is not implemented for `u32` - | -note: required by `f1` - --> $DIR/associated-types-path-2.rs:13:1 - | -LL | pub fn f1(a: T, x: T::A) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `u32: Foo` is not satisfied --> $DIR/associated-types-path-2.rs:35:5 diff --git a/src/test/ui/associated-types/associated-types-ref-from-struct.rs b/src/test/ui/associated-types/associated-types-ref-from-struct.rs index 3ccba289e4b0a..c89f6046e6bf2 100644 --- a/src/test/ui/associated-types/associated-types-ref-from-struct.rs +++ b/src/test/ui/associated-types/associated-types-ref-from-struct.rs @@ -9,8 +9,6 @@ trait Test { fn test(&self, value: &Self::V) -> bool; } -/////////////////////////////////////////////////////////////////////////// - struct TesterPair { tester: T, value: T::V, @@ -26,8 +24,6 @@ impl TesterPair { } } -/////////////////////////////////////////////////////////////////////////// - struct EqU32(u32); impl Test for EqU32 { type V = u32; diff --git a/src/test/ui/associated-types/associated-types-unconstrained.rs b/src/test/ui/associated-types/associated-types-unconstrained.rs index 99424836ece2f..b97d4af184f92 100644 --- a/src/test/ui/associated-types/associated-types-unconstrained.rs +++ b/src/test/ui/associated-types/associated-types-unconstrained.rs @@ -12,5 +12,5 @@ impl Foo for isize { pub fn main() { let x: isize = Foo::bar(); - //~^ ERROR type annotations required + //~^ ERROR type annotations needed } diff --git a/src/test/ui/associated-types/associated-types-unconstrained.stderr b/src/test/ui/associated-types/associated-types-unconstrained.stderr index da14a69ae306a..4e9e54d368805 100644 --- a/src/test/ui/associated-types/associated-types-unconstrained.stderr +++ b/src/test/ui/associated-types/associated-types-unconstrained.stderr @@ -1,4 +1,4 @@ -error[E0284]: type annotations required: cannot resolve `<_ as Foo>::A == _` +error[E0284]: type annotations needed: cannot resolve `<_ as Foo>::A == _` --> $DIR/associated-types-unconstrained.rs:14:20 | LL | let x: isize = Foo::bar(); diff --git a/src/test/ui/associated-types/cache/chrono-scan.rs b/src/test/ui/associated-types/cache/chrono-scan.rs index 8ddd347ff3607..964ddc9b625de 100644 --- a/src/test/ui/associated-types/cache/chrono-scan.rs +++ b/src/test/ui/associated-types/cache/chrono-scan.rs @@ -1,5 +1,7 @@ // check-pass +#![allow(deprecated)] + pub type ParseResult = Result; pub enum Item<'a> { diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr index 15bebce47dd6a..4309373f123f9 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr @@ -23,3 +23,4 @@ LL | bar(foo, x) error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr index 62b4cb10911fb..b8b1a979c363a 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr @@ -19,3 +19,4 @@ LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> { error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/associated-types/higher-ranked-projection.bad.stderr b/src/test/ui/associated-types/higher-ranked-projection.bad.stderr index cc69e849fe144..74c9ad2c39e67 100644 --- a/src/test/ui/associated-types/higher-ranked-projection.bad.stderr +++ b/src/test/ui/associated-types/higher-ranked-projection.bad.stderr @@ -1,16 +1,13 @@ error[E0271]: type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _` --> $DIR/higher-ranked-projection.rs:25:5 | +LL | fn foo(_t: T) + | --- +LL | where for<'a> &'a T: Mirror + | ------- required by this bound in `foo` +... LL | foo(()); | ^^^ expected bound lifetime parameter 'a, found concrete lifetime - | -note: required by `foo` - --> $DIR/higher-ranked-projection.rs:14:1 - | -LL | / fn foo(_t: T) -LL | | where for<'a> &'a T: Mirror -LL | | {} - | |__^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/issue-64855-2.rs b/src/test/ui/associated-types/issue-64855-2.rs new file mode 100644 index 0000000000000..1d53bd5703165 --- /dev/null +++ b/src/test/ui/associated-types/issue-64855-2.rs @@ -0,0 +1,5 @@ +// check-pass + +pub struct Bar<'a>(&'a Self) where Self: ; + +fn main() {} diff --git a/src/test/ui/associated-types/issue-64855.rs b/src/test/ui/associated-types/issue-64855.rs new file mode 100644 index 0000000000000..81cf3ae6e83b6 --- /dev/null +++ b/src/test/ui/associated-types/issue-64855.rs @@ -0,0 +1,8 @@ +pub trait Foo { + type Type; +} + +pub struct Bar(::Type) where Self: ; +//~^ ERROR the trait bound `Bar: Foo` is not satisfied + +fn main() {} diff --git a/src/test/ui/associated-types/issue-64855.stderr b/src/test/ui/associated-types/issue-64855.stderr new file mode 100644 index 0000000000000..6ad795c11176d --- /dev/null +++ b/src/test/ui/associated-types/issue-64855.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `Bar: Foo` is not satisfied + --> $DIR/issue-64855.rs:5:19 + | +LL | pub struct Bar(::Type) where Self: ; + | ^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/ast-json/ast-json-ice.rs b/src/test/ui/ast-json/ast-json-ice.rs new file mode 100644 index 0000000000000..e8a622e1b8772 --- /dev/null +++ b/src/test/ui/ast-json/ast-json-ice.rs @@ -0,0 +1,41 @@ +// Test that AST json serialization doesn't ICE (#63728). + +// revisions: expand noexpand + +//[expand] compile-flags: -Zast-json +//[noexpand] compile-flags: -Zast-json-noexpand + +// check-pass +// dont-check-compiler-stdout - don't check for any AST change. + +#![feature(asm)] + +enum V { + A(i32), + B { f: [i64; 3 + 4] } +} + +trait X { + type Output; + fn read(&self) -> Self::Output; + fn write(&mut self, _: Self::Output); +} + +macro_rules! call_println { + ($y:ident) => { println!("{}", $y) } +} + +fn main() { + #[cfg(any(target_arch = "x86", + target_arch = "x86_64", + target_arch = "arm", + target_arch = "aarch64"))] + unsafe { asm!(""::::); } + + let x: (i32) = 35; + let y = x as i64<> + 5; + + call_println!(y); + + struct A; +} diff --git a/src/test/ui/ast-json/ast-json-output.rs b/src/test/ui/ast-json/ast-json-output.rs new file mode 100644 index 0000000000000..e444a07460248 --- /dev/null +++ b/src/test/ui/ast-json/ast-json-output.rs @@ -0,0 +1,9 @@ +// Check that AST json printing works. + +// check-pass +// compile-flags: -Zast-json-noexpand +// normalize-stdout-test ":\d+" -> ":0" + +// Only include a single item to reduce how often the test output needs +// updating. +extern crate core; diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout new file mode 100644 index 0000000000000..563885133a4c1 --- /dev/null +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -0,0 +1 @@ +{"module":{"inner":{"lo":0,"hi":0},"items":[{"ident":{"name":"core","span":{"lo":0,"hi":0}},"attrs":[],"id":0,"kind":{"variant":"ExternCrate","fields":[null]},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"span":{"lo":0,"hi":0},"tokens":[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]}]}],"inline":true},"attrs":[],"span":{"lo":0,"hi":0}} diff --git a/src/test/ui/async-await/argument-patterns.rs b/src/test/ui/async-await/argument-patterns.rs index 3750c2bcb701a..b9fc1a88cee13 100644 --- a/src/test/ui/async-await/argument-patterns.rs +++ b/src/test/ui/async-await/argument-patterns.rs @@ -1,9 +1,7 @@ // edition:2018 -// run-pass +// check-pass -#![allow(unused_variables)] #![deny(unused_mut)] -#![feature(async_await)] type A = Vec; diff --git a/src/test/ui/async-await/async-assoc-fn-anon-lifetimes.rs b/src/test/ui/async-await/async-assoc-fn-anon-lifetimes.rs new file mode 100644 index 0000000000000..8e08b82b9d3e3 --- /dev/null +++ b/src/test/ui/async-await/async-assoc-fn-anon-lifetimes.rs @@ -0,0 +1,23 @@ +// check-pass +// Check that the anonymous lifetimes used here aren't considered to shadow one +// another. Note that `async fn` is different to `fn` here because the lifetimes +// are numbered by HIR lowering, rather than lifetime resolution. + +// edition:2018 + +struct A<'a, 'b>(&'a &'b i32); +struct B<'a>(&'a i32); + +impl A<'_, '_> { + async fn assoc(x: &u32, y: B<'_>) { + async fn nested(x: &u32, y: A<'_, '_>) {} + } + + async fn assoc2(x: &u32, y: A<'_, '_>) { + impl A<'_, '_> { + async fn nested_assoc(x: &u32, y: B<'_>) {} + } + } +} + +fn main() {} diff --git a/src/test/ui/async-await/async-await.rs b/src/test/ui/async-await/async-await.rs index 8a15eb8c573b1..1dc7315e88c11 100644 --- a/src/test/ui/async-await/async-await.rs +++ b/src/test/ui/async-await/async-await.rs @@ -1,10 +1,10 @@ // run-pass +#![allow(unused)] + // edition:2018 // aux-build:arc_wake.rs -#![feature(async_await)] - extern crate arc_wake; use std::pin::Pin; diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs index 6a766ede0ed87..971d447633481 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs @@ -6,8 +6,6 @@ // edition:2018 // ignore-tidy-linelength -#![feature(async_await)] - fn main() {} use core::future::Future; @@ -22,7 +20,7 @@ fn return_targets_async_block_not_fn() -> u8 { } async fn return_targets_async_block_not_async_fn() -> u8 { - //~^ ERROR type mismatch resolving + //~^ ERROR mismatched types let block = async { return 0u8; }; @@ -32,15 +30,14 @@ async fn return_targets_async_block_not_async_fn() -> u8 { fn no_break_in_async_block() { async { - break 0u8; //~ ERROR `break` inside of a closure - // FIXME: This diagnostic is pretty bad. + break 0u8; //~ ERROR `break` inside of an `async` block }; } fn no_break_in_async_block_even_with_outer_loop() { loop { async { - break 0u8; //~ ERROR `break` inside of a closure + break 0u8; //~ ERROR `break` inside of an `async` block }; } } diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr index 96927ac9632d6..a9b0e7ae7795d 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -1,28 +1,36 @@ -error[E0267]: `break` inside of a closure - --> $DIR/async-block-control-flow-static-semantics.rs:35:9 +error[E0267]: `break` inside of an `async` block + --> $DIR/async-block-control-flow-static-semantics.rs:33:9 | -LL | break 0u8; - | ^^^^^^^^^ cannot break inside of a closure +LL | async { + | ___________- +LL | | break 0u8; + | | ^^^^^^^^^ cannot `break` inside of an `async` block +LL | | }; + | |_____- enclosing `async` block -error[E0267]: `break` inside of a closure - --> $DIR/async-block-control-flow-static-semantics.rs:43:13 +error[E0267]: `break` inside of an `async` block + --> $DIR/async-block-control-flow-static-semantics.rs:40:13 | -LL | break 0u8; - | ^^^^^^^^^ cannot break inside of a closure +LL | async { + | _______________- +LL | | break 0u8; + | | ^^^^^^^^^ cannot `break` inside of an `async` block +LL | | }; + | |_________- enclosing `async` block error[E0308]: mismatched types - --> $DIR/async-block-control-flow-static-semantics.rs:15:43 + --> $DIR/async-block-control-flow-static-semantics.rs:13:43 | LL | fn return_targets_async_block_not_fn() -> u8 { | --------------------------------- ^^ expected u8, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression | = note: expected type `u8` found type `()` error[E0271]: type mismatch resolving `::Output == ()` - --> $DIR/async-block-control-flow-static-semantics.rs:20:39 + --> $DIR/async-block-control-flow-static-semantics.rs:18:39 | LL | let _: &dyn Future = █ | ^^^^^^ expected u8, found () @@ -31,8 +39,24 @@ LL | let _: &dyn Future = █ found type `()` = note: required for the cast to the object type `dyn std::future::Future` +error[E0308]: mismatched types + --> $DIR/async-block-control-flow-static-semantics.rs:22:58 + | +LL | async fn return_targets_async_block_not_async_fn() -> u8 { + | __________________________________________________________^ +LL | | +LL | | let block = async { +LL | | return 0u8; +... | +LL | | +LL | | } + | |_^ expected u8, found () + | + = note: expected type `u8` + found type `()` + error[E0271]: type mismatch resolving `::Output == ()` - --> $DIR/async-block-control-flow-static-semantics.rs:29:39 + --> $DIR/async-block-control-flow-static-semantics.rs:27:39 | LL | let _: &dyn Future = █ | ^^^^^^ expected u8, found () @@ -41,34 +65,24 @@ LL | let _: &dyn Future = █ found type `()` = note: required for the cast to the object type `dyn std::future::Future` -error[E0271]: type mismatch resolving `::Output == u8` - --> $DIR/async-block-control-flow-static-semantics.rs:24:55 - | -LL | async fn return_targets_async_block_not_async_fn() -> u8 { - | ^^ expected (), found u8 - | - = note: expected type `()` - found type `u8` - = note: the return type of a function must have a statically known size - error[E0308]: mismatched types - --> $DIR/async-block-control-flow-static-semantics.rs:51:44 + --> $DIR/async-block-control-flow-static-semantics.rs:48:44 | LL | fn rethrow_targets_async_block_not_fn() -> Result { | ---------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression | = note: expected type `std::result::Result` found type `()` error[E0308]: mismatched types - --> $DIR/async-block-control-flow-static-semantics.rs:60:50 + --> $DIR/async-block-control-flow-static-semantics.rs:57:50 | LL | fn rethrow_targets_async_block_not_async_fn() -> Result { | ---------------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression | = note: expected type `std::result::Result` found type `()` diff --git a/src/test/ui/async-await/async-borrowck-escaping-block-error.fixed b/src/test/ui/async-await/async-borrowck-escaping-block-error.fixed new file mode 100644 index 0000000000000..f004b4180ddc9 --- /dev/null +++ b/src/test/ui/async-await/async-borrowck-escaping-block-error.fixed @@ -0,0 +1,12 @@ +// edition:2018 +// run-rustfix + +fn foo() -> Box> { + let x = 0u32; + Box::new(async move { x } ) + //~^ ERROR E0373 +} + +fn main() { + let _foo = foo(); +} diff --git a/src/test/ui/async-await/async-borrowck-escaping-block-error.rs b/src/test/ui/async-await/async-borrowck-escaping-block-error.rs new file mode 100644 index 0000000000000..4f35fd52ca39b --- /dev/null +++ b/src/test/ui/async-await/async-borrowck-escaping-block-error.rs @@ -0,0 +1,12 @@ +// edition:2018 +// run-rustfix + +fn foo() -> Box> { + let x = 0u32; + Box::new(async { x } ) + //~^ ERROR E0373 +} + +fn main() { + let _foo = foo(); +} diff --git a/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr b/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr new file mode 100644 index 0000000000000..0eb3971d14a38 --- /dev/null +++ b/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr @@ -0,0 +1,22 @@ +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/async-borrowck-escaping-block-error.rs:6:20 + | +LL | Box::new(async { x } ) + | ^^-^^ + | | | + | | `x` is borrowed here + | may outlive borrowed value `x` + | +note: generator is returned here + --> $DIR/async-borrowck-escaping-block-error.rs:4:13 + | +LL | fn foo() -> Box> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to force the async block to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | Box::new(async move { x } ) + | ^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/async-await/async-borrowck-escaping-closure-error.rs b/src/test/ui/async-await/async-borrowck-escaping-closure-error.rs new file mode 100644 index 0000000000000..d2fa5d0a3d0f1 --- /dev/null +++ b/src/test/ui/async-await/async-borrowck-escaping-closure-error.rs @@ -0,0 +1,10 @@ +// edition:2018 +#![feature(async_closure,async_await)] +fn foo() -> Box> { + let x = 0u32; + Box::new((async || x)()) + //~^ ERROR E0373 +} + +fn main() { +} diff --git a/src/test/ui/async-await/async-borrowck-escaping-closure-error.stderr b/src/test/ui/async-await/async-borrowck-escaping-closure-error.stderr new file mode 100644 index 0000000000000..8bcfcf989208e --- /dev/null +++ b/src/test/ui/async-await/async-borrowck-escaping-closure-error.stderr @@ -0,0 +1,21 @@ +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/async-borrowck-escaping-closure-error.rs:5:15 + | +LL | Box::new((async || x)()) + | ^^^^^^^^ - `x` is borrowed here + | | + | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/async-borrowck-escaping-closure-error.rs:5:5 + | +LL | Box::new((async || x)()) + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | Box::new((async move || x)()) + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/async-await/async-closure-matches-expr.rs b/src/test/ui/async-await/async-closure-matches-expr.rs index 1c192a4d1d882..d82fbcdc5505b 100644 --- a/src/test/ui/async-await/async-closure-matches-expr.rs +++ b/src/test/ui/async-await/async-closure-matches-expr.rs @@ -1,7 +1,7 @@ // build-pass // edition:2018 -#![feature(async_await, async_closure)] +#![feature(async_closure)] macro_rules! match_expr { ($x:expr) => {} diff --git a/src/test/ui/async-await/async-closure.rs b/src/test/ui/async-await/async-closure.rs index 925b54b398517..9a24bd8c95439 100644 --- a/src/test/ui/async-await/async-closure.rs +++ b/src/test/ui/async-await/async-closure.rs @@ -3,7 +3,7 @@ // edition:2018 // aux-build:arc_wake.rs -#![feature(async_await, async_closure)] +#![feature(async_closure)] extern crate arc_wake; diff --git a/src/test/ui/async-await/async-error-span.rs b/src/test/ui/async-await/async-error-span.rs index d362348a3fddb..28132c9789c67 100644 --- a/src/test/ui/async-await/async-error-span.rs +++ b/src/test/ui/async-await/async-error-span.rs @@ -1,7 +1,6 @@ // edition:2018 -#![feature(async_await)] -// Regression test for issue #62382 +// Regression test for issue #62382. use std::future::Future; @@ -10,7 +9,7 @@ fn get_future() -> impl Future { } async fn foo() { - let a; //~ ERROR type inside `async` object must be known in this context + let a; //~ ERROR type inside `async fn` body must be known in this context get_future().await; } diff --git a/src/test/ui/async-await/async-error-span.stderr b/src/test/ui/async-await/async-error-span.stderr index bd8966b9c7d47..b551b99587dd9 100644 --- a/src/test/ui/async-await/async-error-span.stderr +++ b/src/test/ui/async-await/async-error-span.stderr @@ -1,11 +1,11 @@ -error[E0698]: type inside `async` object must be known in this context - --> $DIR/async-error-span.rs:13:9 +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/async-error-span.rs:12:9 | LL | let a; | ^ cannot infer type | -note: the type is part of the `async` object because of this `await` - --> $DIR/async-error-span.rs:14:5 +note: the type is part of the `async fn` body because of this `await` + --> $DIR/async-error-span.rs:13:5 | LL | get_future().await; | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/async-await/async-fn-elided-impl-lifetime-parameter.rs b/src/test/ui/async-await/async-fn-elided-impl-lifetime-parameter.rs new file mode 100644 index 0000000000000..1c369fd7415db --- /dev/null +++ b/src/test/ui/async-await/async-fn-elided-impl-lifetime-parameter.rs @@ -0,0 +1,15 @@ +// Check that `async fn` inside of an impl with `'_` +// in the header compiles correctly. +// +// Regression test for #63500. +// +// check-pass +// edition:2018 + +struct Foo<'a>(&'a u8); + +impl Foo<'_> { + async fn bar() {} +} + +fn main() { } diff --git a/src/test/ui/async-await/async-fn-nonsend.rs b/src/test/ui/async-await/async-fn-nonsend.rs index 612c1e29d82bd..1f1bf4250eadf 100644 --- a/src/test/ui/async-await/async-fn-nonsend.rs +++ b/src/test/ui/async-await/async-fn-nonsend.rs @@ -2,8 +2,6 @@ // edition:2018 // compile-flags: --crate-type lib -#![feature(async_await)] - use std::{ cell::RefCell, fmt::Debug, diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr index 7776a36a28f2b..696bd5c39d283 100644 --- a/src/test/ui/async-await/async-fn-nonsend.stderr +++ b/src/test/ui/async-await/async-fn-nonsend.stderr @@ -1,44 +1,43 @@ error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely - --> $DIR/async-fn-nonsend.rs:52:5 + --> $DIR/async-fn-nonsend.rs:50:5 | +LL | fn assert_send(_: impl Send) {} + | ----------- ---- required by this bound in `assert_send` +... LL | assert_send(local_dropped_before_await()); | ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely | = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` = note: required because it appears within the type `impl std::fmt::Debug` - = note: required because it appears within the type `{impl std::fmt::Debug, impl std::future::Future, ()}` - = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:23:39: 28:2 {impl std::fmt::Debug, impl std::future::Future, ()}]` - = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:23:39: 28:2 {impl std::fmt::Debug, impl std::future::Future, ()}]>` + = note: required because it appears within the type `{impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}` + = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]` + = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]>` = note: required because it appears within the type `impl std::future::Future` = note: required because it appears within the type `impl std::future::Future` -note: required by `assert_send` - --> $DIR/async-fn-nonsend.rs:49:1 - | -LL | fn assert_send(_: impl Send) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely - --> $DIR/async-fn-nonsend.rs:54:5 + --> $DIR/async-fn-nonsend.rs:52:5 | +LL | fn assert_send(_: impl Send) {} + | ----------- ---- required by this bound in `assert_send` +... LL | assert_send(non_send_temporary_in_match()); | ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely | = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` = note: required because it appears within the type `impl std::fmt::Debug` - = note: required because it appears within the type `{fn(impl std::fmt::Debug) -> std::option::Option {std::option::Option::::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option, impl std::future::Future, ()}` - = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:30:40: 39:2 {fn(impl std::fmt::Debug) -> std::option::Option {std::option::Option::::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option, impl std::future::Future, ()}]` - = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:30:40: 39:2 {fn(impl std::fmt::Debug) -> std::option::Option {std::option::Option::::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option, impl std::future::Future, ()}]>` + = note: required because it appears within the type `{fn(impl std::fmt::Debug) -> std::option::Option {std::option::Option::::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}` + = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option {std::option::Option::::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]` + = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option {std::option::Option::::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]>` = note: required because it appears within the type `impl std::future::Future` = note: required because it appears within the type `impl std::future::Future` -note: required by `assert_send` - --> $DIR/async-fn-nonsend.rs:49:1 - | -LL | fn assert_send(_: impl Send) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `dyn std::fmt::Write` cannot be sent between threads safely - --> $DIR/async-fn-nonsend.rs:56:5 + --> $DIR/async-fn-nonsend.rs:54:5 | +LL | fn assert_send(_: impl Send) {} + | ----------- ---- required by this bound in `assert_send` +... LL | assert_send(non_sync_with_method_call()); | ^^^^^^^^^^^ `dyn std::fmt::Write` cannot be sent between threads safely | @@ -46,20 +45,18 @@ LL | assert_send(non_sync_with_method_call()); = note: required because of the requirements on the impl of `std::marker::Send` for `&mut dyn std::fmt::Write` = note: required because it appears within the type `std::fmt::Formatter<'_>` = note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>` - = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}` - = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:41:38: 47:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]` - = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:41:38: 47:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]>` + = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}` + = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]` + = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]>` = note: required because it appears within the type `impl std::future::Future` = note: required because it appears within the type `impl std::future::Future` -note: required by `assert_send` - --> $DIR/async-fn-nonsend.rs:49:1 - | -LL | fn assert_send(_: impl Send) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely - --> $DIR/async-fn-nonsend.rs:56:5 + --> $DIR/async-fn-nonsend.rs:54:5 | +LL | fn assert_send(_: impl Send) {} + | ----------- ---- required by this bound in `assert_send` +... LL | assert_send(non_sync_with_method_call()); | ^^^^^^^^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely | @@ -71,16 +68,11 @@ LL | assert_send(non_sync_with_method_call()); = note: required because of the requirements on the impl of `std::marker::Send` for `std::slice::Iter<'_, std::fmt::ArgumentV1<'_>>` = note: required because it appears within the type `std::fmt::Formatter<'_>` = note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>` - = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}` - = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:41:38: 47:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]` - = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:41:38: 47:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]>` + = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}` + = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]` + = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]>` = note: required because it appears within the type `impl std::future::Future` = note: required because it appears within the type `impl std::future::Future` -note: required by `assert_send` - --> $DIR/async-fn-nonsend.rs:49:1 - | -LL | fn assert_send(_: impl Send) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/async-await/async-fn-path-elision.rs b/src/test/ui/async-await/async-fn-path-elision.rs index 447e40dddd910..3f1f51c20ca0c 100644 --- a/src/test/ui/async-await/async-fn-path-elision.rs +++ b/src/test/ui/async-await/async-fn-path-elision.rs @@ -1,8 +1,5 @@ // edition:2018 -#![feature(async_await)] -#![allow(dead_code)] - struct HasLifetime<'a>(&'a bool); async fn error(lt: HasLifetime) { //~ ERROR implicit elided lifetime not allowed here diff --git a/src/test/ui/async-await/async-fn-path-elision.stderr b/src/test/ui/async-await/async-fn-path-elision.stderr index 3b311baba01de..9694742200ef0 100644 --- a/src/test/ui/async-await/async-fn-path-elision.stderr +++ b/src/test/ui/async-await/async-fn-path-elision.stderr @@ -1,5 +1,5 @@ error[E0726]: implicit elided lifetime not allowed here - --> $DIR/async-fn-path-elision.rs:8:20 + --> $DIR/async-fn-path-elision.rs:5:20 | LL | async fn error(lt: HasLifetime) { | ^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>` diff --git a/src/test/ui/async-await/async-fn-send-uses-nonsend.rs b/src/test/ui/async-await/async-fn-send-uses-nonsend.rs index 5e1b8c6280b81..35d9cb15540d1 100644 --- a/src/test/ui/async-await/async-fn-send-uses-nonsend.rs +++ b/src/test/ui/async-await/async-fn-send-uses-nonsend.rs @@ -2,8 +2,6 @@ // edition:2018 // compile-flags: --crate-type lib -#![feature(async_await)] - use std::{ cell::RefCell, fmt::Debug, diff --git a/src/test/ui/async-await/async-fn-size-moved-locals.rs b/src/test/ui/async-await/async-fn-size-moved-locals.rs index 30b59d037d512..c266644fd702c 100644 --- a/src/test/ui/async-await/async-fn-size-moved-locals.rs +++ b/src/test/ui/async-await/async-fn-size-moved-locals.rs @@ -12,8 +12,6 @@ // edition:2018 -#![feature(async_await)] - use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; @@ -24,7 +22,8 @@ struct BigFut([u8; BIG_FUT_SIZE]); impl BigFut { fn new() -> Self { BigFut([0; BIG_FUT_SIZE]) - } } + } +} impl Drop for BigFut { fn drop(&mut self) {} diff --git a/src/test/ui/async-await/async-fn-size-uninit-locals.rs b/src/test/ui/async-await/async-fn-size-uninit-locals.rs new file mode 100644 index 0000000000000..ad20237981c30 --- /dev/null +++ b/src/test/ui/async-await/async-fn-size-uninit-locals.rs @@ -0,0 +1,103 @@ +// Test that we don't store uninitialized locals in futures from `async fn`. +// +// The exact sizes can change by a few bytes (we'd like to know when they do). +// What we don't want to see is the wrong multiple of 1024 (the size of `Big`) +// being reflected in the size. + +// ignore-wasm32-bare (sizes don't match) +// run-pass + +// edition:2018 + +#![allow(unused_variables, unused_assignments)] + +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; + +const BIG_FUT_SIZE: usize = 1024; +struct Big([u8; BIG_FUT_SIZE]); + +impl Big { + fn new() -> Self { + Big([0; BIG_FUT_SIZE]) + } +} + +impl Drop for Big { + fn drop(&mut self) {} +} + +#[allow(dead_code)] +struct Joiner { + a: Option, + b: Option, + c: Option, +} + +impl Future for Joiner { + type Output = (); + + fn poll(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll { + Poll::Ready(()) + } +} + +fn noop() {} +async fn fut() {} + +async fn single() { + let x; + fut().await; + x = Big::new(); +} + +async fn single_with_noop() { + let x; + fut().await; + noop(); + x = Big::new(); + noop(); +} + +async fn joined() { + let joiner; + let a = Big::new(); + let b = Big::new(); + let c = Big::new(); + + fut().await; + noop(); + joiner = Joiner { a: Some(a), b: Some(b), c: Some(c) }; + noop(); +} + +async fn joined_with_noop() { + let joiner; + let a = Big::new(); + let b = Big::new(); + let c = Big::new(); + + fut().await; + noop(); + joiner = Joiner { a: Some(a), b: Some(b), c: Some(c) }; + noop(); +} + +async fn join_retval() -> Joiner { + let a = Big::new(); + let b = Big::new(); + let c = Big::new(); + + fut().await; + noop(); + Joiner { a: Some(a), b: Some(b), c: Some(c) } +} + +fn main() { + assert_eq!(8, std::mem::size_of_val(&single())); + assert_eq!(12, std::mem::size_of_val(&single_with_noop())); + assert_eq!(3084, std::mem::size_of_val(&joined())); + assert_eq!(3084, std::mem::size_of_val(&joined_with_noop())); + assert_eq!(3080, std::mem::size_of_val(&join_retval())); +} diff --git a/src/test/ui/async-await/async-fn-size.rs b/src/test/ui/async-await/async-fn-size.rs index c6b2ed13b0a8d..b313992db4ecb 100644 --- a/src/test/ui/async-await/async-fn-size.rs +++ b/src/test/ui/async-await/async-fn-size.rs @@ -2,8 +2,6 @@ // aux-build:arc_wake.rs // edition:2018 -#![feature(async_await)] - extern crate arc_wake; use std::pin::Pin; @@ -91,10 +89,10 @@ fn main() { assert_eq!(8, std::mem::size_of_val(&await1_level1())); assert_eq!(12, std::mem::size_of_val(&await2_level1())); assert_eq!(12, std::mem::size_of_val(&await3_level1())); - assert_eq!(20, std::mem::size_of_val(&await3_level2())); - assert_eq!(28, std::mem::size_of_val(&await3_level3())); - assert_eq!(36, std::mem::size_of_val(&await3_level4())); - assert_eq!(44, std::mem::size_of_val(&await3_level5())); + assert_eq!(24, std::mem::size_of_val(&await3_level2())); + assert_eq!(36, std::mem::size_of_val(&await3_level3())); + assert_eq!(48, std::mem::size_of_val(&await3_level4())); + assert_eq!(60, std::mem::size_of_val(&await3_level5())); assert_eq!(1, wait(base())); assert_eq!(1, wait(await1_level1())); diff --git a/src/test/ui/async-await/async-matches-expr.rs b/src/test/ui/async-await/async-matches-expr.rs index a6f0211e41f98..299faa0587bd5 100644 --- a/src/test/ui/async-await/async-matches-expr.rs +++ b/src/test/ui/async-await/async-matches-expr.rs @@ -1,8 +1,6 @@ // build-pass (FIXME(62277): could be check-pass?) // edition:2018 -#![feature(async_await)] - macro_rules! match_expr { ($x:expr) => {} } diff --git a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs index cb9156dcc6e58..ccc1b8553f071 100644 --- a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs +++ b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs @@ -1,7 +1,5 @@ // edition:2018 -#![feature(async_await)] - struct S; impl S { diff --git a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.stderr b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.stderr index d22413beecbcf..c95fe17348877 100644 --- a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.stderr +++ b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.stderr @@ -1,5 +1,5 @@ error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/async-unsafe-fn-call-in-safe.rs:14:5 + --> $DIR/async-unsafe-fn-call-in-safe.rs:12:5 | LL | S::f(); | ^^^^^^ call to unsafe function @@ -7,7 +7,7 @@ LL | S::f(); = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/async-unsafe-fn-call-in-safe.rs:15:5 + --> $DIR/async-unsafe-fn-call-in-safe.rs:13:5 | LL | f(); | ^^^ call to unsafe function @@ -15,7 +15,7 @@ LL | f(); = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/async-unsafe-fn-call-in-safe.rs:19:5 + --> $DIR/async-unsafe-fn-call-in-safe.rs:17:5 | LL | S::f(); | ^^^^^^ call to unsafe function @@ -23,7 +23,7 @@ LL | S::f(); = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/async-unsafe-fn-call-in-safe.rs:20:5 + --> $DIR/async-unsafe-fn-call-in-safe.rs:18:5 | LL | f(); | ^^^ call to unsafe function diff --git a/src/test/ui/async-await/async-with-closure.rs b/src/test/ui/async-await/async-with-closure.rs index f7dc874affd26..0b2255266753d 100644 --- a/src/test/ui/async-await/async-with-closure.rs +++ b/src/test/ui/async-await/async-with-closure.rs @@ -1,8 +1,6 @@ // build-pass (FIXME(62277): could be check-pass?) // edition:2018 -#![feature(async_await)] - trait MyClosure { type Args; } diff --git a/src/test/ui/async-await/await-keyword/2015-edition-error-various-positions.rs b/src/test/ui/async-await/await-keyword/2015-edition-error-various-positions.rs index 422a5a6394f8e..a3a20cb97e150 100644 --- a/src/test/ui/async-await/await-keyword/2015-edition-error-various-positions.rs +++ b/src/test/ui/async-await/await-keyword/2015-edition-error-various-positions.rs @@ -1,4 +1,3 @@ -#![feature(async_await)] #![allow(non_camel_case_types)] #![deny(keyword_idents)] diff --git a/src/test/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr b/src/test/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr index 8af0110169ebd..f1a22cda51b21 100644 --- a/src/test/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr +++ b/src/test/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr @@ -1,11 +1,11 @@ error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:6:13 + --> $DIR/2015-edition-error-various-positions.rs:5:13 | LL | pub mod await { | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` | note: lint level defined here - --> $DIR/2015-edition-error-various-positions.rs:3:9 + --> $DIR/2015-edition-error-various-positions.rs:2:9 | LL | #![deny(keyword_idents)] | ^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL | #![deny(keyword_idents)] = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:8:20 + --> $DIR/2015-edition-error-various-positions.rs:7:20 | LL | pub struct await; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -22,7 +22,7 @@ LL | pub struct await; = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:12:16 + --> $DIR/2015-edition-error-various-positions.rs:11:16 | LL | use outer_mod::await::await; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -31,7 +31,7 @@ LL | use outer_mod::await::await; = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:12:23 + --> $DIR/2015-edition-error-various-positions.rs:11:23 | LL | use outer_mod::await::await; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -40,7 +40,7 @@ LL | use outer_mod::await::await; = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:17:14 + --> $DIR/2015-edition-error-various-positions.rs:16:14 | LL | struct Foo { await: () } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -49,7 +49,7 @@ LL | struct Foo { await: () } = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:21:15 + --> $DIR/2015-edition-error-various-positions.rs:20:15 | LL | impl Foo { fn await() {} } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -58,7 +58,7 @@ LL | impl Foo { fn await() {} } = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:25:14 + --> $DIR/2015-edition-error-various-positions.rs:24:14 | LL | macro_rules! await { | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -67,7 +67,7 @@ LL | macro_rules! await { = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:32:5 + --> $DIR/2015-edition-error-various-positions.rs:31:5 | LL | await!(); | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -76,7 +76,7 @@ LL | await!(); = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:35:11 + --> $DIR/2015-edition-error-various-positions.rs:34:11 | LL | match await { await => {} } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -85,7 +85,7 @@ LL | match await { await => {} } = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:35:19 + --> $DIR/2015-edition-error-various-positions.rs:34:19 | LL | match await { await => {} } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` diff --git a/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.rs b/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.rs index 92f3210ac89a3..9e78f7c512014 100644 --- a/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.rs +++ b/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.rs @@ -1,24 +1,23 @@ // edition:2018 #![allow(non_camel_case_types)] -#![feature(async_await)] mod outer_mod { - pub mod await { //~ ERROR expected identifier, found reserved keyword `await` - pub struct await; //~ ERROR expected identifier, found reserved keyword `await` + pub mod await { //~ ERROR expected identifier, found keyword `await` + pub struct await; //~ ERROR expected identifier, found keyword `await` } } -use self::outer_mod::await::await; //~ ERROR expected identifier, found reserved keyword `await` -//~^ ERROR expected identifier, found reserved keyword `await` +use self::outer_mod::await::await; //~ ERROR expected identifier, found keyword `await` +//~^ ERROR expected identifier, found keyword `await` struct Foo { await: () } -//~^ ERROR expected identifier, found reserved keyword `await` +//~^ ERROR expected identifier, found keyword `await` impl Foo { fn await() {} } -//~^ ERROR expected identifier, found reserved keyword `await` +//~^ ERROR expected identifier, found keyword `await` macro_rules! await { -//~^ ERROR expected identifier, found reserved keyword `await` +//~^ ERROR expected identifier, found keyword `await` () => {} } diff --git a/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.stderr b/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.stderr index c4b82b29f0270..0e859466322c0 100644 --- a/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.stderr +++ b/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.stderr @@ -1,68 +1,68 @@ -error: expected identifier, found reserved keyword `await` - --> $DIR/2018-edition-error-in-non-macro-position.rs:7:13 +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:6:13 | LL | pub mod await { - | ^^^^^ expected identifier, found reserved keyword + | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | LL | pub mod r#await { | ^^^^^^^ -error: expected identifier, found reserved keyword `await` - --> $DIR/2018-edition-error-in-non-macro-position.rs:8:20 +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:7:20 | LL | pub struct await; - | ^^^^^ expected identifier, found reserved keyword + | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | LL | pub struct r#await; | ^^^^^^^ -error: expected identifier, found reserved keyword `await` - --> $DIR/2018-edition-error-in-non-macro-position.rs:11:22 +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:10:22 | LL | use self::outer_mod::await::await; - | ^^^^^ expected identifier, found reserved keyword + | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | LL | use self::outer_mod::r#await::await; | ^^^^^^^ -error: expected identifier, found reserved keyword `await` - --> $DIR/2018-edition-error-in-non-macro-position.rs:11:29 +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:10:29 | LL | use self::outer_mod::await::await; - | ^^^^^ expected identifier, found reserved keyword + | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | LL | use self::outer_mod::await::r#await; | ^^^^^^^ -error: expected identifier, found reserved keyword `await` - --> $DIR/2018-edition-error-in-non-macro-position.rs:14:14 +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:13:14 | LL | struct Foo { await: () } - | ^^^^^ expected identifier, found reserved keyword + | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | LL | struct Foo { r#await: () } | ^^^^^^^ -error: expected identifier, found reserved keyword `await` - --> $DIR/2018-edition-error-in-non-macro-position.rs:17:15 +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:16:15 | LL | impl Foo { fn await() {} } - | ^^^^^ expected identifier, found reserved keyword + | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | LL | impl Foo { fn r#await() {} } | ^^^^^^^ -error: expected identifier, found reserved keyword `await` - --> $DIR/2018-edition-error-in-non-macro-position.rs:20:14 +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:19:14 | LL | macro_rules! await { - | ^^^^^ expected identifier, found reserved keyword + | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | LL | macro_rules! r#await { diff --git a/src/test/ui/async-await/await-keyword/2018-edition-error.rs b/src/test/ui/async-await/await-keyword/2018-edition-error.rs index e620c27f9e36d..7ce52259acac3 100644 --- a/src/test/ui/async-await/await-keyword/2018-edition-error.rs +++ b/src/test/ui/async-await/await-keyword/2018-edition-error.rs @@ -7,9 +7,9 @@ mod outer_mod { } } use self::outer_mod::await::await; //~ ERROR expected identifier - //~^ ERROR expected identifier, found reserved keyword `await` + //~^ ERROR expected identifier, found keyword `await` -macro_rules! await { () => {}; } //~ ERROR expected identifier, found reserved keyword `await` +macro_rules! await { () => {}; } //~ ERROR expected identifier, found keyword `await` fn main() { await!(); //~ ERROR expected expression, found `)` diff --git a/src/test/ui/async-await/await-keyword/2018-edition-error.stderr b/src/test/ui/async-await/await-keyword/2018-edition-error.stderr index 9304928cfde5d..71f403f278eb3 100644 --- a/src/test/ui/async-await/await-keyword/2018-edition-error.stderr +++ b/src/test/ui/async-await/await-keyword/2018-edition-error.stderr @@ -1,48 +1,48 @@ -error: expected identifier, found reserved keyword `await` +error: expected identifier, found keyword `await` --> $DIR/2018-edition-error.rs:5:13 | LL | pub mod await { - | ^^^^^ expected identifier, found reserved keyword + | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | LL | pub mod r#await { | ^^^^^^^ -error: expected identifier, found reserved keyword `await` +error: expected identifier, found keyword `await` --> $DIR/2018-edition-error.rs:6:20 | LL | pub struct await; - | ^^^^^ expected identifier, found reserved keyword + | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | LL | pub struct r#await; | ^^^^^^^ -error: expected identifier, found reserved keyword `await` +error: expected identifier, found keyword `await` --> $DIR/2018-edition-error.rs:9:22 | LL | use self::outer_mod::await::await; - | ^^^^^ expected identifier, found reserved keyword + | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | LL | use self::outer_mod::r#await::await; | ^^^^^^^ -error: expected identifier, found reserved keyword `await` +error: expected identifier, found keyword `await` --> $DIR/2018-edition-error.rs:9:29 | LL | use self::outer_mod::await::await; - | ^^^^^ expected identifier, found reserved keyword + | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | LL | use self::outer_mod::await::r#await; | ^^^^^^^ -error: expected identifier, found reserved keyword `await` +error: expected identifier, found keyword `await` --> $DIR/2018-edition-error.rs:12:14 | LL | macro_rules! await { () => {}; } - | ^^^^^ expected identifier, found reserved keyword + | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | LL | macro_rules! r#await { () => {}; } diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs index 25da337c58798..22bcbb1064dd7 100644 --- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs @@ -1,7 +1,5 @@ // edition:2018 -#![feature(async_await)] - async fn bar() -> Result<(), ()> { Ok(()) } diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index db86d3d5d03ba..7caa9f26bc2f8 100644 --- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -1,119 +1,119 @@ error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:10:13 + --> $DIR/incorrect-syntax-suggestions.rs:8:13 | LL | let _ = await bar(); | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:14:13 + --> $DIR/incorrect-syntax-suggestions.rs:12:13 | LL | let _ = await? bar(); | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:18:13 + --> $DIR/incorrect-syntax-suggestions.rs:16:13 | LL | let _ = await bar()?; | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:23:13 + --> $DIR/incorrect-syntax-suggestions.rs:21:13 | LL | let _ = await { bar() }; | ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:27:13 + --> $DIR/incorrect-syntax-suggestions.rs:25:13 | LL | let _ = await(bar()); | ^^^^^^^^^^^^ help: `await` is a postfix operation: `(bar()).await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:31:13 + --> $DIR/incorrect-syntax-suggestions.rs:29:13 | LL | let _ = await { bar() }?; | ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:35:14 + --> $DIR/incorrect-syntax-suggestions.rs:33:14 | LL | let _ = (await bar())?; | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:39:24 + --> $DIR/incorrect-syntax-suggestions.rs:37:24 | LL | let _ = bar().await(); | ^^ help: `await` is not a method call, remove the parentheses error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:43:24 + --> $DIR/incorrect-syntax-suggestions.rs:41:24 | LL | let _ = bar().await()?; | ^^ help: `await` is not a method call, remove the parentheses error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:55:13 + --> $DIR/incorrect-syntax-suggestions.rs:53:13 | LL | let _ = await bar(); | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:60:13 + --> $DIR/incorrect-syntax-suggestions.rs:58:13 | LL | let _ = await? bar(); | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:65:13 + --> $DIR/incorrect-syntax-suggestions.rs:63:13 | LL | let _ = await bar()?; | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:70:14 + --> $DIR/incorrect-syntax-suggestions.rs:68:14 | LL | let _ = (await bar())?; | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:75:24 + --> $DIR/incorrect-syntax-suggestions.rs:73:24 | LL | let _ = bar().await(); | ^^ help: `await` is not a method call, remove the parentheses error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:80:24 + --> $DIR/incorrect-syntax-suggestions.rs:78:24 | LL | let _ = bar().await()?; | ^^ help: `await` is not a method call, remove the parentheses error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:108:13 + --> $DIR/incorrect-syntax-suggestions.rs:106:13 | LL | let _ = await!(bar()); | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:112:13 + --> $DIR/incorrect-syntax-suggestions.rs:110:13 | LL | let _ = await!(bar())?; | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:117:17 + --> $DIR/incorrect-syntax-suggestions.rs:115:17 | LL | let _ = await!(bar())?; | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:125:17 + --> $DIR/incorrect-syntax-suggestions.rs:123:17 | LL | let _ = await!(bar())?; | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` error: expected expression, found `=>` - --> $DIR/incorrect-syntax-suggestions.rs:133:25 + --> $DIR/incorrect-syntax-suggestions.rs:131:25 | LL | match await { await => () } | ----- ^^ expected expression @@ -121,13 +121,13 @@ LL | match await { await => () } | while parsing this incorrect await expression error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:133:11 + --> $DIR/incorrect-syntax-suggestions.rs:131:11 | LL | match await { await => () } | ^^^^^^^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ await => () }.await` error: expected one of `.`, `?`, `{`, or an operator, found `}` - --> $DIR/incorrect-syntax-suggestions.rs:136:1 + --> $DIR/incorrect-syntax-suggestions.rs:134:1 | LL | match await { await => () } | ----- - expected one of `.`, `?`, `{`, or an operator here @@ -138,7 +138,7 @@ LL | } | ^ unexpected token error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:55:13 + --> $DIR/incorrect-syntax-suggestions.rs:53:13 | LL | fn foo9() -> Result<(), ()> { | ---- this is not `async` @@ -146,7 +146,7 @@ LL | let _ = await bar(); | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:60:13 + --> $DIR/incorrect-syntax-suggestions.rs:58:13 | LL | fn foo10() -> Result<(), ()> { | ----- this is not `async` @@ -154,7 +154,7 @@ LL | let _ = await? bar(); | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:65:13 + --> $DIR/incorrect-syntax-suggestions.rs:63:13 | LL | fn foo11() -> Result<(), ()> { | ----- this is not `async` @@ -162,7 +162,7 @@ LL | let _ = await bar()?; | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:70:14 + --> $DIR/incorrect-syntax-suggestions.rs:68:14 | LL | fn foo12() -> Result<(), ()> { | ----- this is not `async` @@ -170,7 +170,7 @@ LL | let _ = (await bar())?; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:75:13 + --> $DIR/incorrect-syntax-suggestions.rs:73:13 | LL | fn foo13() -> Result<(), ()> { | ----- this is not `async` @@ -178,7 +178,7 @@ LL | let _ = bar().await(); | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:80:13 + --> $DIR/incorrect-syntax-suggestions.rs:78:13 | LL | fn foo14() -> Result<(), ()> { | ----- this is not `async` @@ -186,7 +186,7 @@ LL | let _ = bar().await()?; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:85:13 + --> $DIR/incorrect-syntax-suggestions.rs:83:13 | LL | fn foo15() -> Result<(), ()> { | ----- this is not `async` @@ -194,7 +194,7 @@ LL | let _ = bar().await; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:89:13 + --> $DIR/incorrect-syntax-suggestions.rs:87:13 | LL | fn foo16() -> Result<(), ()> { | ----- this is not `async` @@ -202,7 +202,7 @@ LL | let _ = bar().await?; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:94:17 + --> $DIR/incorrect-syntax-suggestions.rs:92:17 | LL | fn foo() -> Result<(), ()> { | --- this is not `async` @@ -210,7 +210,7 @@ LL | let _ = bar().await?; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:101:17 + --> $DIR/incorrect-syntax-suggestions.rs:99:17 | LL | let foo = || { | -- this is not `async` @@ -218,7 +218,7 @@ LL | let _ = bar().await?; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:117:17 + --> $DIR/incorrect-syntax-suggestions.rs:115:17 | LL | fn foo() -> Result<(), ()> { | --- this is not `async` @@ -226,7 +226,7 @@ LL | let _ = await!(bar())?; | ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:125:17 + --> $DIR/incorrect-syntax-suggestions.rs:123:17 | LL | let foo = || { | -- this is not `async` @@ -234,7 +234,7 @@ LL | let _ = await!(bar())?; | ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` - --> $DIR/incorrect-syntax-suggestions.rs:18:19 + --> $DIR/incorrect-syntax-suggestions.rs:16:19 | LL | let _ = await bar()?; | ^^^^^^ the `?` operator cannot be applied to type `impl std::future::Future` diff --git a/src/test/ui/async-await/await-unsize.rs b/src/test/ui/async-await/await-unsize.rs index d5e21257f4f7d..aa09d4bdf0883 100644 --- a/src/test/ui/async-await/await-unsize.rs +++ b/src/test/ui/async-await/await-unsize.rs @@ -3,8 +3,6 @@ // check-pass // edition:2018 -#![feature(async_await)] - async fn make_boxed_object() -> Box { Box::new(()) as _ } diff --git a/src/test/ui/async-await/bound-normalization.rs b/src/test/ui/async-await/bound-normalization.rs index 8026350aaf2fb..5d260682f1d81 100644 --- a/src/test/ui/async-await/bound-normalization.rs +++ b/src/test/ui/async-await/bound-normalization.rs @@ -1,8 +1,6 @@ // check-pass // edition:2018 -#![feature(async_await)] - // See issue 60414 trait Trait { diff --git a/src/test/ui/async-await/conditional-and-guaranteed-initialization.rs b/src/test/ui/async-await/conditional-and-guaranteed-initialization.rs index a5947e7f71870..56f4cbbd190f8 100644 --- a/src/test/ui/async-await/conditional-and-guaranteed-initialization.rs +++ b/src/test/ui/async-await/conditional-and-guaranteed-initialization.rs @@ -2,8 +2,6 @@ // edition:2018 // compile-flags: --crate-type lib -#![feature(async_await)] - async fn conditional_and_guaranteed_initialization(x: usize) -> usize { let y; if x > 5 { diff --git a/src/test/ui/async-await/dont-print-desugared-async.rs b/src/test/ui/async-await/dont-print-desugared-async.rs index 8150a260866b9..68341a24c4e5d 100644 --- a/src/test/ui/async-await/dont-print-desugared-async.rs +++ b/src/test/ui/async-await/dont-print-desugared-async.rs @@ -1,7 +1,6 @@ // Test that we don't show variables with from async fn desugaring // edition:2018 -#![feature(async_await)] async fn async_fn(&ref mut s: &[i32]) {} //~^ ERROR cannot borrow data in a `&` reference as mutable [E0596] diff --git a/src/test/ui/async-await/dont-print-desugared-async.stderr b/src/test/ui/async-await/dont-print-desugared-async.stderr index 47726ba65df98..2bf1e77f09b3f 100644 --- a/src/test/ui/async-await/dont-print-desugared-async.stderr +++ b/src/test/ui/async-await/dont-print-desugared-async.stderr @@ -1,5 +1,5 @@ error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/dont-print-desugared-async.rs:6:20 + --> $DIR/dont-print-desugared-async.rs:5:20 | LL | async fn async_fn(&ref mut s: &[i32]) {} | -^^^^^^^^^ diff --git a/src/test/ui/async-await/dont-suggest-missing-await.rs b/src/test/ui/async-await/dont-suggest-missing-await.rs index d551ef57985a1..a8e5b38ec1dd8 100644 --- a/src/test/ui/async-await/dont-suggest-missing-await.rs +++ b/src/test/ui/async-await/dont-suggest-missing-await.rs @@ -2,8 +2,6 @@ // This test ensures we don't make the suggestion in bodies that aren't `async`. -#![feature(async_await)] - fn take_u32(x: u32) {} async fn make_u32() -> u32 { diff --git a/src/test/ui/async-await/dont-suggest-missing-await.stderr b/src/test/ui/async-await/dont-suggest-missing-await.stderr index c60b0d1f30e80..c87e0bc221de7 100644 --- a/src/test/ui/async-await/dont-suggest-missing-await.stderr +++ b/src/test/ui/async-await/dont-suggest-missing-await.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/dont-suggest-missing-await.rs:16:18 + --> $DIR/dont-suggest-missing-await.rs:14:18 | LL | take_u32(x) | ^ expected u32, found opaque type diff --git a/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters-by-ref-binding.rs b/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters-by-ref-binding.rs index dfd8b2e361eef..9817d377a7886 100644 --- a/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters-by-ref-binding.rs +++ b/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters-by-ref-binding.rs @@ -3,7 +3,6 @@ // run-pass #![allow(unused_variables)] -#![feature(async_await)] // Test that the drop order for parameters in a fn and async fn matches up. Also test that // parameters (used or unused) are not dropped until the async fn completes execution. diff --git a/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters.rs b/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters.rs index 2a74485afb450..00072786a50a7 100644 --- a/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters.rs +++ b/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters.rs @@ -3,7 +3,6 @@ // run-pass #![allow(unused_variables)] -#![feature(async_await)] // Test that the drop order for parameters in a fn and async fn matches up. Also test that // parameters (used or unused) are not dropped until the async fn completes execution. diff --git a/src/test/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs b/src/test/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs index db396d3957e13..15cc9fbc81fb7 100644 --- a/src/test/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs +++ b/src/test/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs @@ -2,9 +2,10 @@ // edition:2018 // run-pass -#![allow(unused_variables)] #![deny(dead_code)] -#![feature(async_await)] +#![allow(unused_variables)] +#![allow(unused_must_use)] +#![allow(path_statements)] // Test that the drop order for locals in a fn and async fn matches up. extern crate arc_wake; @@ -12,7 +13,6 @@ extern crate arc_wake; use arc_wake::ArcWake; use std::cell::RefCell; use std::future::Future; -use std::marker::PhantomData; use std::pin::Pin; use std::rc::Rc; use std::sync::Arc; @@ -44,7 +44,7 @@ struct NeverReady; impl Future for NeverReady { type Output = (); - fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { Poll::Pending } } diff --git a/src/test/ui/async-await/drop-order/drop-order-for-temporary-in-tail-return-expr.rs b/src/test/ui/async-await/drop-order/drop-order-for-temporary-in-tail-return-expr.rs new file mode 100644 index 0000000000000..e40acff6dc117 --- /dev/null +++ b/src/test/ui/async-await/drop-order/drop-order-for-temporary-in-tail-return-expr.rs @@ -0,0 +1,95 @@ +// aux-build:arc_wake.rs +// edition:2018 +// run-pass + +#![allow(unused_variables)] + +// Test the drop order for parameters relative to local variables and +// temporaries created in the tail return expression of the function +// body. In particular, check that this drop order is the same between +// a `async fn` and an ordinary `fn`. See #64512. + +extern crate arc_wake; + +use arc_wake::ArcWake; +use std::cell::RefCell; +use std::future::Future; +use std::sync::Arc; +use std::rc::Rc; +use std::task::Context; + +struct EmptyWaker; + +impl ArcWake for EmptyWaker { + fn wake(self: Arc) {} +} + +#[derive(Debug, Eq, PartialEq)] +enum DropOrder { + Function, + Val(&'static str), +} + +type DropOrderListPtr = Rc>>; + +struct D(&'static str, DropOrderListPtr); + +impl Drop for D { + fn drop(&mut self) { + self.1.borrow_mut().push(DropOrder::Val(self.0)); + } +} + +/// Check drop order of temporary "temp" as compared to `x`, `y`, and `z`. +/// +/// Expected order: +/// - `z` +/// - temp +/// - `y` +/// - `x` +async fn foo_async(x: D, _y: D) { + let l = x.1.clone(); + let z = D("z", l.clone()); + l.borrow_mut().push(DropOrder::Function); + helper_async(&D("temp", l)).await +} + +async fn helper_async(v: &D) { } + +fn foo_sync(x: D, _y: D) { + let l = x.1.clone(); + let z = D("z", l.clone()); + l.borrow_mut().push(DropOrder::Function); + helper_sync(&D("temp", l)) +} + +fn helper_sync(v: &D) { } + +fn assert_drop_order_after_poll>( + f: impl FnOnce(DropOrderListPtr) -> Fut, + g: impl FnOnce(DropOrderListPtr), +) { + let empty = Arc::new(EmptyWaker); + let waker = ArcWake::into_waker(empty); + let mut cx = Context::from_waker(&waker); + + let actual_order = Rc::new(RefCell::new(Vec::new())); + let mut fut = Box::pin(f(actual_order.clone())); + let r = fut.as_mut().poll(&mut cx); + + assert!(match r { + std::task::Poll::Ready(()) => true, + _ => false, + }); + + let expected_order = Rc::new(RefCell::new(Vec::new())); + g(expected_order.clone()); + + assert_eq!(*actual_order.borrow(), *expected_order.borrow()); +} + +fn main() { + // Free functions (see doc comment on function for what it tests). + assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| foo_sync(D("x", l.clone()), D("_y", l.clone()))); +} diff --git a/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.rs b/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.rs index bcdb8878eb5d2..79dedb1ba285e 100644 --- a/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.rs +++ b/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.rs @@ -1,8 +1,5 @@ // edition:2018 -#![allow(unused_variables)] -#![feature(async_await)] - async fn foobar_async(x: u32, (a, _, _c): (u32, u32, u32), _: u32, _y: u32) { assert_eq!(__arg1, (1, 2, 3)); //~ ERROR cannot find value `__arg1` in this scope [E0425] assert_eq!(__arg2, 4); //~ ERROR cannot find value `__arg2` in this scope [E0425] diff --git a/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.stderr b/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.stderr index 484e1f4f4269e..aa04a613f47c1 100644 --- a/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.stderr +++ b/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.stderr @@ -1,23 +1,23 @@ error[E0425]: cannot find value `__arg1` in this scope - --> $DIR/drop-order-locals-are-hidden.rs:7:16 + --> $DIR/drop-order-locals-are-hidden.rs:4:16 | LL | assert_eq!(__arg1, (1, 2, 3)); | ^^^^^^ not found in this scope error[E0425]: cannot find value `__arg2` in this scope - --> $DIR/drop-order-locals-are-hidden.rs:8:16 + --> $DIR/drop-order-locals-are-hidden.rs:5:16 | LL | assert_eq!(__arg2, 4); | ^^^^^^ not found in this scope error[E0425]: cannot find value `__arg0` in this scope - --> $DIR/drop-order-locals-are-hidden.rs:12:16 + --> $DIR/drop-order-locals-are-hidden.rs:9:16 | LL | assert_eq!(__arg0, 1); | ^^^^^^ not found in this scope error[E0425]: cannot find value `__arg1` in this scope - --> $DIR/drop-order-locals-are-hidden.rs:13:16 + --> $DIR/drop-order-locals-are-hidden.rs:10:16 | LL | assert_eq!(__arg1, 2); | ^^^^^^ not found in this scope diff --git a/src/test/ui/async-await/drop-order/drop-order-when-cancelled.rs b/src/test/ui/async-await/drop-order/drop-order-when-cancelled.rs index 410a623681db5..9e8304935bffc 100644 --- a/src/test/ui/async-await/drop-order/drop-order-when-cancelled.rs +++ b/src/test/ui/async-await/drop-order/drop-order-when-cancelled.rs @@ -2,13 +2,12 @@ // edition:2018 // run-pass -#![allow(unused_variables)] -#![feature(async_await)] - // Test that the drop order for parameters in a fn and async fn matches up. Also test that // parameters (used or unused) are not dropped until the async fn is cancelled. // This file is mostly copy-pasted from drop-order-for-async-fn-parameters.rs +#![allow(unused_variables)] + extern crate arc_wake; use arc_wake::ArcWake; @@ -46,7 +45,7 @@ struct NeverReady; impl Future for NeverReady { type Output = (); - fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { Poll::Pending } } diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.rs b/src/test/ui/async-await/edition-deny-async-fns-2015.rs index a5bc181015475..c85896150c29f 100644 --- a/src/test/ui/async-await/edition-deny-async-fns-2015.rs +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.rs @@ -1,7 +1,5 @@ // edition:2015 -#![feature(async_await)] - async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition fn baz() { async fn foo() {} } //~ ERROR `async fn` is not permitted in the 2015 edition diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr index efb4462095d0d..7633825eb32ab 100644 --- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr @@ -1,59 +1,59 @@ error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:5:1 + --> $DIR/edition-deny-async-fns-2015.rs:3:1 | LL | async fn foo() {} | ^^^^^ error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:7:12 + --> $DIR/edition-deny-async-fns-2015.rs:5:12 | LL | fn baz() { async fn foo() {} } | ^^^^^ error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:10:5 + --> $DIR/edition-deny-async-fns-2015.rs:7:1 | -LL | async fn bar() {} - | ^^^^^ +LL | async fn async_baz() { + | ^^^^^ error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:9:1 + --> $DIR/edition-deny-async-fns-2015.rs:8:5 | -LL | async fn async_baz() { - | ^^^^^ +LL | async fn bar() {} + | ^^^^^ error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:16:5 + --> $DIR/edition-deny-async-fns-2015.rs:14:5 | LL | async fn foo() {} | ^^^^^ error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:20:5 + --> $DIR/edition-deny-async-fns-2015.rs:18:5 | LL | async fn foo() {} | ^^^^^ error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:38:9 + --> $DIR/edition-deny-async-fns-2015.rs:36:9 | LL | async fn bar() {} | ^^^^^ error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:28:9 + --> $DIR/edition-deny-async-fns-2015.rs:26:9 | LL | async fn foo() {} | ^^^^^ error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:33:13 + --> $DIR/edition-deny-async-fns-2015.rs:31:13 | LL | async fn bar() {} | ^^^^^ error[E0706]: trait fns cannot be declared `async` - --> $DIR/edition-deny-async-fns-2015.rs:20:5 + --> $DIR/edition-deny-async-fns-2015.rs:18:5 | LL | async fn foo() {} | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/async-await/generics-and-bounds.rs b/src/test/ui/async-await/generics-and-bounds.rs index 8b60f2f82f1d6..963b19b34a620 100644 --- a/src/test/ui/async-await/generics-and-bounds.rs +++ b/src/test/ui/async-await/generics-and-bounds.rs @@ -2,8 +2,6 @@ // edition:2018 // compile-flags: --crate-type lib -#![feature(async_await)] - use std::future::Future; pub async fn simple_generic() {} diff --git a/src/test/ui/async-await/issue-60709.rs b/src/test/ui/async-await/issue-60709.rs index ad0b49fa4a219..9ee419c4a56fb 100644 --- a/src/test/ui/async-await/issue-60709.rs +++ b/src/test/ui/async-await/issue-60709.rs @@ -4,9 +4,6 @@ // run-pass -#![feature(async_await)] -#![allow(unused)] - use std::future::Future; use std::task::Poll; use std::task::Context; diff --git a/src/test/ui/async-await/issue-61452.rs b/src/test/ui/async-await/issue-61452.rs index 20b9b645daead..9381251ad6968 100644 --- a/src/test/ui/async-await/issue-61452.rs +++ b/src/test/ui/async-await/issue-61452.rs @@ -1,5 +1,4 @@ // edition:2018 -#![feature(async_await)] pub async fn f(x: Option) { x.take(); diff --git a/src/test/ui/async-await/issue-61452.stderr b/src/test/ui/async-await/issue-61452.stderr index 742490d8de43c..5eb4b54871737 100644 --- a/src/test/ui/async-await/issue-61452.stderr +++ b/src/test/ui/async-await/issue-61452.stderr @@ -1,5 +1,5 @@ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/issue-61452.rs:5:5 + --> $DIR/issue-61452.rs:4:5 | LL | pub async fn f(x: Option) { | - help: consider changing this to be mutable: `mut x` @@ -7,7 +7,7 @@ LL | x.take(); | ^ cannot borrow as mutable error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/issue-61452.rs:10:5 + --> $DIR/issue-61452.rs:9:5 | LL | pub async fn g(x: usize) { | - diff --git a/src/test/ui/async-await/issue-61793.rs b/src/test/ui/async-await/issue-61793.rs index a18fad8bb9150..f6084be916745 100644 --- a/src/test/ui/async-await/issue-61793.rs +++ b/src/test/ui/async-await/issue-61793.rs @@ -6,9 +6,6 @@ // build-pass (FIXME(62277): could be check-pass?) // edition:2018 -#![feature(async_await)] -#![allow(unused)] - async fn foo(_: &(), _: F) {} fn main() { diff --git a/src/test/ui/async-await/issue-61949-self-return-type.rs b/src/test/ui/async-await/issue-61949-self-return-type.rs new file mode 100644 index 0000000000000..6a28c69193da0 --- /dev/null +++ b/src/test/ui/async-await/issue-61949-self-return-type.rs @@ -0,0 +1,27 @@ +// ignore-tidy-linelength +// edition:2018 + +// This test checks that `Self` is prohibited as a return type. See #61949 for context. + +pub struct Foo<'a> { + pub bar: &'a i32, +} + +impl<'a> Foo<'a> { + pub async fn new(_bar: &'a i32) -> Self { + //~^ ERROR `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope + Foo { + bar: &22 + } + } +} + +async fn foo() { + let x = { + let bar = 22; + Foo::new(&bar).await + }; + drop(x); +} + +fn main() { } diff --git a/src/test/ui/async-await/issue-61949-self-return-type.stderr b/src/test/ui/async-await/issue-61949-self-return-type.stderr new file mode 100644 index 0000000000000..12fb77d8dd637 --- /dev/null +++ b/src/test/ui/async-await/issue-61949-self-return-type.stderr @@ -0,0 +1,8 @@ +error: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope + --> $DIR/issue-61949-self-return-type.rs:11:40 + | +LL | pub async fn new(_bar: &'a i32) -> Self { + | ^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issue-62658.rs b/src/test/ui/async-await/issue-62658.rs index 90fbb47bffda8..d0af01e0c009f 100644 --- a/src/test/ui/async-await/issue-62658.rs +++ b/src/test/ui/async-await/issue-62658.rs @@ -4,8 +4,6 @@ // build-pass // edition:2018 -#![feature(async_await)] - async fn noop() {} async fn foo() { diff --git a/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime-1.rs b/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime-1.rs new file mode 100644 index 0000000000000..54059b29f72e2 --- /dev/null +++ b/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime-1.rs @@ -0,0 +1,19 @@ +// check-pass +// edition:2018 + +struct Test(String); + +impl Test { + async fn borrow_async(&self) {} + + fn with(&mut self, s: &str) -> &mut Self { + self.0 = s.into(); + self + } +} + +async fn test() { + Test("".to_string()).with("123").borrow_async().await; +} + +fn main() { } diff --git a/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime.rs b/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime.rs new file mode 100644 index 0000000000000..c5ea2b821ad78 --- /dev/null +++ b/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime.rs @@ -0,0 +1,12 @@ +// check-pass +// edition:2018 + +async fn foo(x: &[Vec]) -> u32 { + 0 +} + +async fn bar() { + foo(&[vec![123]]).await; +} + +fn main() { } diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.rs b/src/test/ui/async-await/issue-64130-non-send-future-diags.rs new file mode 100644 index 0000000000000..1936d1a2ed56e --- /dev/null +++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.rs @@ -0,0 +1,25 @@ +// edition:2018 + +use std::sync::Mutex; + +fn is_send(t: T) { + +} + +async fn foo() { + bar(&Mutex::new(22)).await; +} + +async fn bar(x: &Mutex) { + let g = x.lock().unwrap(); + baz().await; +} + +async fn baz() { + +} + +fn main() { + is_send(foo()); + //~^ ERROR `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely [E0277] +} diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr new file mode 100644 index 0000000000000..9e9fc52e30b7f --- /dev/null +++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr @@ -0,0 +1,23 @@ +error[E0277]: `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely + --> $DIR/issue-64130-non-send-future-diags.rs:23:5 + | +LL | fn is_send(t: T) { + | ------- ---- required by this bound in `is_send` +... +LL | is_send(foo()); + | ^^^^^^^ `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely + | + = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, u32>` +note: future does not implement `std::marker::Send` as this value is used across an await + --> $DIR/issue-64130-non-send-future-diags.rs:15:5 + | +LL | let g = x.lock().unwrap(); + | - has type `std::sync::MutexGuard<'_, u32>` +LL | baz().await; + | ^^^^^^^^^^^ await occurs here, with `g` maybe used later +LL | } + | - `g` is later dropped here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issue-64391.rs b/src/test/ui/async-await/issue-64391.rs new file mode 100644 index 0000000000000..c6faad3aad064 --- /dev/null +++ b/src/test/ui/async-await/issue-64391.rs @@ -0,0 +1,14 @@ +// Regression test for Issue #64391. The goal here is that this +// function compiles. In the past, due to incorrect drop order for +// temporaries in the tail expression, we failed to compile this +// example. The drop order itself is directly tested in +// `drop-order/drop-order-for-temporary-in-tail-return-expr.rs`. +// +// check-pass +// edition:2018 + +async fn add(x: u32, y: u32) -> u32 { + async { x + y }.await +} + +fn main() { } diff --git a/src/test/ui/async-await/issues/issue-51719.rs b/src/test/ui/async-await/issues/issue-51719.rs index 361a49c2774ec..09241f982aa8a 100644 --- a/src/test/ui/async-await/issues/issue-51719.rs +++ b/src/test/ui/async-await/issues/issue-51719.rs @@ -2,8 +2,6 @@ // // Tests that the .await syntax can't be used to make a generator -#![feature(async_await)] - async fn foo() {} fn make_generator() { diff --git a/src/test/ui/async-await/issues/issue-51719.stderr b/src/test/ui/async-await/issues/issue-51719.stderr index 2a9fb6cf0df6e..6c3c8889da7ce 100644 --- a/src/test/ui/async-await/issues/issue-51719.stderr +++ b/src/test/ui/async-await/issues/issue-51719.stderr @@ -1,5 +1,5 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/issue-51719.rs:10:19 + --> $DIR/issue-51719.rs:8:19 | LL | let _gen = || foo().await; | -- ^^^^^^^^^^^ only allowed inside `async` functions and blocks diff --git a/src/test/ui/async-await/issues/issue-51751.rs b/src/test/ui/async-await/issues/issue-51751.rs index 7afd7ecc82649..bc85a96cea99e 100644 --- a/src/test/ui/async-await/issues/issue-51751.rs +++ b/src/test/ui/async-await/issues/issue-51751.rs @@ -1,7 +1,5 @@ // edition:2018 -#![feature(async_await)] - async fn inc(limit: i64) -> i64 { limit + 1 } diff --git a/src/test/ui/async-await/issues/issue-51751.stderr b/src/test/ui/async-await/issues/issue-51751.stderr index 97b63d1590ec6..e50c78534f852 100644 --- a/src/test/ui/async-await/issues/issue-51751.stderr +++ b/src/test/ui/async-await/issues/issue-51751.stderr @@ -1,5 +1,5 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/issue-51751.rs:11:20 + --> $DIR/issue-51751.rs:9:20 | LL | fn main() { | ---- this is not `async` diff --git a/src/test/ui/async-await/issues/issue-53249.rs b/src/test/ui/async-await/issues/issue-53249.rs index c57dc6b0ef6f9..5cae070444460 100644 --- a/src/test/ui/async-await/issues/issue-53249.rs +++ b/src/test/ui/async-await/issues/issue-53249.rs @@ -1,7 +1,7 @@ // build-pass (FIXME(62277): could be check-pass?) // edition:2018 -#![feature(arbitrary_self_types, async_await)] +#![feature(arbitrary_self_types)] use std::task::{self, Poll}; use std::future::Future; diff --git a/src/test/ui/async-await/issues/issue-54752-async-block.rs b/src/test/ui/async-await/issues/issue-54752-async-block.rs index 0036de90b2579..64f260cfe01b6 100644 --- a/src/test/ui/async-await/issues/issue-54752-async-block.rs +++ b/src/test/ui/async-await/issues/issue-54752-async-block.rs @@ -3,7 +3,4 @@ // edition:2018 // pp-exact -#![feature(async_await)] -#![allow(unused_parens)] - fn main() { let _a = (async { }); } diff --git a/src/test/ui/async-await/issues/issue-54752-async-block.stderr b/src/test/ui/async-await/issues/issue-54752-async-block.stderr new file mode 100644 index 0000000000000..c3b3392cfc495 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-54752-async-block.stderr @@ -0,0 +1,8 @@ +warning: unnecessary parentheses around assigned value + --> $DIR/issue-54752-async-block.rs:6:22 + | +LL | fn main() { let _a = (async { }); } + | ^^^^^^^^^^^^ help: remove these parentheses + | + = note: `#[warn(unused_parens)]` on by default + diff --git a/src/test/ui/async-await/issues/issue-54974.rs b/src/test/ui/async-await/issues/issue-54974.rs index 040989b33fc1a..9adc0a8232388 100644 --- a/src/test/ui/async-await/issues/issue-54974.rs +++ b/src/test/ui/async-await/issues/issue-54974.rs @@ -1,8 +1,6 @@ // build-pass (FIXME(62277): could be check-pass?) // edition:2018 -#![feature(async_await)] - use std::sync::Arc; trait SomeTrait: Send + Sync + 'static { diff --git a/src/test/ui/async-await/issues/issue-55324.rs b/src/test/ui/async-await/issues/issue-55324.rs index 4f383a51a88e7..1d77d420127a8 100644 --- a/src/test/ui/async-await/issues/issue-55324.rs +++ b/src/test/ui/async-await/issues/issue-55324.rs @@ -1,11 +1,8 @@ // build-pass (FIXME(62277): could be check-pass?) // edition:2018 -#![feature(async_await)] - use std::future::Future; -#[allow(unused)] async fn foo>(x: &i32, future: F) -> i32 { let y = future.await; *x + y diff --git a/src/test/ui/async-await/issues/issue-55809.rs b/src/test/ui/async-await/issues/issue-55809.rs index b7e60b773b416..3b271775a3851 100644 --- a/src/test/ui/async-await/issues/issue-55809.rs +++ b/src/test/ui/async-await/issues/issue-55809.rs @@ -1,8 +1,6 @@ // edition:2018 // run-pass -#![feature(async_await)] - trait Foo { } impl Foo for () { } diff --git a/src/test/ui/async-await/issues/issue-58885.rs b/src/test/ui/async-await/issues/issue-58885.rs index 47744aeea6034..72a45b5007d7a 100644 --- a/src/test/ui/async-await/issues/issue-58885.rs +++ b/src/test/ui/async-await/issues/issue-58885.rs @@ -1,8 +1,6 @@ // build-pass (FIXME(62277): could be check-pass?) // edition:2018 -#![feature(async_await)] - struct Xyz { a: u64, } diff --git a/src/test/ui/async-await/issues/issue-59001.rs b/src/test/ui/async-await/issues/issue-59001.rs index 9334ddb0af588..ea780d9f62214 100644 --- a/src/test/ui/async-await/issues/issue-59001.rs +++ b/src/test/ui/async-await/issues/issue-59001.rs @@ -1,11 +1,8 @@ // build-pass (FIXME(62277): could be check-pass?) // edition:2018 -#![feature(async_await)] - use std::future::Future; -#[allow(unused)] async fn enter<'a, F, R>(mut callback: F) where F: FnMut(&'a mut i32) -> R, diff --git a/src/test/ui/async-await/issues/issue-59972.rs b/src/test/ui/async-await/issues/issue-59972.rs index 8f4254b10ceaf..c2e24a96b1d93 100644 --- a/src/test/ui/async-await/issues/issue-59972.rs +++ b/src/test/ui/async-await/issues/issue-59972.rs @@ -4,9 +4,7 @@ // run-pass -// compile-flags: --edition=2018 - -#![feature(async_await)] +// compile-flags: --edition=2018 -Aunused pub enum Uninhabited { } @@ -16,14 +14,12 @@ fn uninhabited_async() -> Uninhabited { async fn noop() { } -#[allow(unused)] async fn contains_never() { let error = uninhabited_async(); noop().await; let error2 = error; } -#[allow(unused)] async fn overlap_never() { let error1 = uninhabited_async(); noop().await; @@ -35,6 +31,4 @@ async fn overlap_never() { #[allow(unused_must_use)] fn main() { - contains_never(); - overlap_never(); } diff --git a/src/test/ui/async-await/issues/issue-60518.rs b/src/test/ui/async-await/issues/issue-60518.rs index e4bdc96511e3c..1ca051607518e 100644 --- a/src/test/ui/async-await/issues/issue-60518.rs +++ b/src/test/ui/async-await/issues/issue-60518.rs @@ -1,8 +1,6 @@ // build-pass (FIXME(62277): could be check-pass?) // edition:2018 -#![feature(async_await)] - // This is a regression test to ensure that simple bindings (where replacement arguments aren't // created during async fn lowering) that have their DefId used during HIR lowering (such as impl // trait) are visited during def collection and thus have a DefId. diff --git a/src/test/ui/async-await/issues/issue-60655-latebound-regions.rs b/src/test/ui/async-await/issues/issue-60655-latebound-regions.rs index 99213e64d16df..0d015e54f8b1c 100644 --- a/src/test/ui/async-await/issues/issue-60655-latebound-regions.rs +++ b/src/test/ui/async-await/issues/issue-60655-latebound-regions.rs @@ -3,7 +3,6 @@ // build-pass (FIXME(62277): could be check-pass?) // edition:2018 -#![feature(async_await)] #![feature(type_alias_impl_trait)] use std::future::Future; diff --git a/src/test/ui/async-await/issues/issue-60674.rs b/src/test/ui/async-await/issues/issue-60674.rs index 99cdcbafc766f..c0e34a8df77a4 100644 --- a/src/test/ui/async-await/issues/issue-60674.rs +++ b/src/test/ui/async-await/issues/issue-60674.rs @@ -1,7 +1,6 @@ // aux-build:issue-60674.rs // build-pass (FIXME(62277): could be check-pass?) // edition:2018 -#![feature(async_await)] // This is a regression test that ensures that `mut` patterns are not lost when provided as input // to a proc macro. diff --git a/src/test/ui/async-await/issues/issue-61187.rs b/src/test/ui/async-await/issues/issue-61187.rs index 8b939b43b8bd4..8585a42511104 100644 --- a/src/test/ui/async-await/issues/issue-61187.rs +++ b/src/test/ui/async-await/issues/issue-61187.rs @@ -1,8 +1,6 @@ // edition:2018 -#![feature(async_await)] -fn main() { -} +fn main() {} async fn response(data: Vec) { data.reverse(); //~ ERROR E0596 diff --git a/src/test/ui/async-await/issues/issue-61187.stderr b/src/test/ui/async-await/issues/issue-61187.stderr index a03142263202e..4d361c824dd6d 100644 --- a/src/test/ui/async-await/issues/issue-61187.stderr +++ b/src/test/ui/async-await/issues/issue-61187.stderr @@ -1,5 +1,5 @@ error[E0596]: cannot borrow `data` as mutable, as it is not declared as mutable - --> $DIR/issue-61187.rs:8:5 + --> $DIR/issue-61187.rs:6:5 | LL | async fn response(data: Vec) { | ---- help: consider changing this to be mutable: `mut data` diff --git a/src/test/ui/async-await/issues/issue-61986.rs b/src/test/ui/async-await/issues/issue-61986.rs index 77ecc47dfef12..879bc6912fce9 100644 --- a/src/test/ui/async-await/issues/issue-61986.rs +++ b/src/test/ui/async-await/issues/issue-61986.rs @@ -4,8 +4,6 @@ // Tests that we properly handle StorageDead/StorageLives for temporaries // created in async loop bodies. -#![feature(async_await)] - async fn bar() -> Option<()> { Some(()) } diff --git a/src/test/ui/async-await/issues/issue-62009-1.rs b/src/test/ui/async-await/issues/issue-62009-1.rs index ac6605bcefff9..788474365c9e5 100644 --- a/src/test/ui/async-await/issues/issue-62009-1.rs +++ b/src/test/ui/async-await/issues/issue-62009-1.rs @@ -1,6 +1,6 @@ // edition:2018 - -#![feature(async_await)] +// ignore-x86 +// ^ due to stderr output differences async fn print_dur() {} diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr index 2bbb6d079ead1..f63eaa4c48a97 100644 --- a/src/test/ui/async-await/issues/issue-62009-1.stderr +++ b/src/test/ui/async-await/issues/issue-62009-1.stderr @@ -32,8 +32,11 @@ error[E0277]: the trait bound `[closure@$DIR/issue-62009-1.rs:14:5: 14:15]: std: | LL | (|_| 2333).await; | ^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:14:5: 14:15]` + | + ::: $SRC_DIR/libstd/future.rs:LL:COL | - = note: required by `std::future::poll_with_tls_context` +LL | F: Future + | ------ required by this bound in `std::future::poll_with_tls_context` error: aborting due to 4 previous errors diff --git a/src/test/ui/async-await/issues/issue-62009-2.rs b/src/test/ui/async-await/issues/issue-62009-2.rs index 52b62eaa9e0a7..cb7336e613422 100644 --- a/src/test/ui/async-await/issues/issue-62009-2.rs +++ b/src/test/ui/async-await/issues/issue-62009-2.rs @@ -1,6 +1,6 @@ // edition:2018 -#![feature(async_await, async_closure)] +#![feature(async_closure)] async fn print_dur() {} diff --git a/src/test/ui/async-await/issues/issue-62517-1.rs b/src/test/ui/async-await/issues/issue-62517-1.rs new file mode 100644 index 0000000000000..4689ce36a78c0 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-62517-1.rs @@ -0,0 +1,21 @@ +// Regression test for #62517. We used to ICE when you had an `async +// fn` with an `impl Trait` return that mentioned a `dyn Bar` with no +// explicit lifetime bound. +// +// edition:2018 +// check-pass + +trait FirstTrait {} +trait SecondTrait { + type Item: ?Sized; +} + +async fn foo(x: &str) -> impl SecondTrait { +} + + +impl SecondTrait for T { + type Item = dyn FirstTrait; +} + +fn main() { } diff --git a/src/test/ui/async-await/issues/issue-62517-2.rs b/src/test/ui/async-await/issues/issue-62517-2.rs new file mode 100644 index 0000000000000..aaf28d6c132e3 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-62517-2.rs @@ -0,0 +1,16 @@ +// Regression test for #62517. We used to ICE when you had an `async +// fn` with an `impl Trait` return that mentioned a `dyn Bar` with no +// explicit lifetime bound. +// +// edition:2018 +// check-pass + +trait Object {} + +trait Alpha {} + +async fn foo<'a>(_: &'a ()) -> impl Alpha {} + +impl Alpha for T { } + +fn main() { } diff --git a/src/test/ui/async-await/issues/issue-63388-1.nll.stderr b/src/test/ui/async-await/issues/issue-63388-1.nll.stderr new file mode 100644 index 0000000000000..22610fe54a4cb --- /dev/null +++ b/src/test/ui/async-await/issues/issue-63388-1.nll.stderr @@ -0,0 +1,24 @@ +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds + --> $DIR/issue-63388-1.rs:12:10 + | +LL | ) -> &dyn Foo + | ^^^^^^^^ + | + = note: hidden type `impl std::future::Future` captures lifetime '_#22r + +error: lifetime may not live long enough + --> $DIR/issue-63388-1.rs:13:5 + | +LL | async fn do_sth<'a>( + | -- lifetime `'a` defined here +LL | &'a self, foo: &dyn Foo + | - lifetime `'_` defined here +LL | ) -> &dyn Foo +LL | / { +LL | | foo +LL | | } + | |_____^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'_` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/async-await/issues/issue-63388-1.rs b/src/test/ui/async-await/issues/issue-63388-1.rs new file mode 100644 index 0000000000000..baecf49c798e2 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-63388-1.rs @@ -0,0 +1,18 @@ +// edition:2018 + +struct Xyz { + a: u64, +} + +trait Foo {} + +impl Xyz { + async fn do_sth<'a>( + &'a self, foo: &dyn Foo + ) -> &dyn Foo + { + foo //~ ERROR lifetime mismatch + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-63388-1.stderr b/src/test/ui/async-await/issues/issue-63388-1.stderr new file mode 100644 index 0000000000000..2917fa9ccb7f2 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-63388-1.stderr @@ -0,0 +1,13 @@ +error[E0623]: lifetime mismatch + --> $DIR/issue-63388-1.rs:14:9 + | +LL | &'a self, foo: &dyn Foo + | -------- this parameter and the return type are declared with different lifetimes... +LL | ) -> &dyn Foo + | -------- +LL | { +LL | foo + | ^^^ ...but data from `foo` is returned here + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issues/issue-63388-2.nll.stderr b/src/test/ui/async-await/issues/issue-63388-2.nll.stderr new file mode 100644 index 0000000000000..7781af89deae2 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-63388-2.nll.stderr @@ -0,0 +1,11 @@ +error[E0106]: missing lifetime specifier + --> $DIR/issue-63388-2.rs:12:10 + | +LL | ) -> &dyn Foo + | ^ help: consider using the named lifetime: `&'a` + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `foo` or `bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/async-await/issues/issue-63388-2.rs b/src/test/ui/async-await/issues/issue-63388-2.rs new file mode 100644 index 0000000000000..73e7f25f97d0d --- /dev/null +++ b/src/test/ui/async-await/issues/issue-63388-2.rs @@ -0,0 +1,18 @@ +// edition:2018 + +struct Xyz { + a: u64, +} + +trait Foo {} + +impl Xyz { + async fn do_sth<'a>( + foo: &dyn Foo, bar: &'a dyn Foo //~ ERROR cannot infer + ) -> &dyn Foo //~ ERROR missing lifetime specifier + { + foo + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-63388-2.stderr b/src/test/ui/async-await/issues/issue-63388-2.stderr new file mode 100644 index 0000000000000..5099297fbeb19 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-63388-2.stderr @@ -0,0 +1,30 @@ +error[E0106]: missing lifetime specifier + --> $DIR/issue-63388-2.rs:12:10 + | +LL | ) -> &dyn Foo + | ^ help: consider using the named lifetime: `&'a` + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `foo` or `bar` + +error: cannot infer an appropriate lifetime + --> $DIR/issue-63388-2.rs:11:9 + | +LL | foo: &dyn Foo, bar: &'a dyn Foo + | ^^^ ...but this borrow... +... +LL | foo + | --- this return type evaluates to the `'static` lifetime... + | +note: ...can't outlive the lifetime '_ as defined on the method body at 11:14 + --> $DIR/issue-63388-2.rs:11:14 + | +LL | foo: &dyn Foo, bar: &'a dyn Foo + | ^ +help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime '_ as defined on the method body at 11:14 + | +LL | foo + '_ + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/async-await/issues/issue-63388-3.rs b/src/test/ui/async-await/issues/issue-63388-3.rs new file mode 100644 index 0000000000000..1a9822e02fa01 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-63388-3.rs @@ -0,0 +1,17 @@ +// edition:2018 +// check-pass + +struct Xyz { + a: u64, +} + +trait Foo {} + +impl Xyz { + async fn do_sth( + &self, foo: &dyn Foo + ) { + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-63388-4.rs b/src/test/ui/async-await/issues/issue-63388-4.rs new file mode 100644 index 0000000000000..58f9dacb3bcfa --- /dev/null +++ b/src/test/ui/async-await/issues/issue-63388-4.rs @@ -0,0 +1,10 @@ +// check-pass +// edition:2018 + +struct A; + +impl A { + async fn foo(&self, f: &u32) -> &A { self } +} + +fn main() { } diff --git a/src/test/ui/async-await/issues/issue-64391-2.rs b/src/test/ui/async-await/issues/issue-64391-2.rs new file mode 100644 index 0000000000000..eef2c1fb20ab4 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-64391-2.rs @@ -0,0 +1,20 @@ +// Regression test for #64391 +// +// As described on the issue, the (spurious) `DROP` inserted for the +// `"".to_string()` value was causing a (spurious) unwind path that +// led us to believe that the future might be dropped after `config` +// had been dropped. This cannot, in fact, happen. +// +// check-pass +// edition:2018 + +async fn connect() { + let config = 666; + connect2(&config, "".to_string()).await +} + +async fn connect2(_config: &u32, _tls: String) { + unimplemented!() +} + +fn main() { } diff --git a/src/test/ui/async-await/issues/issue-64433.rs b/src/test/ui/async-await/issues/issue-64433.rs new file mode 100644 index 0000000000000..802e09c8a1f00 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-64433.rs @@ -0,0 +1,30 @@ +// Regression test for issue #64433. +// +// See issue-64391-2.rs for more details, as that was fixed by the +// same PR. +// +// check-pass +// edition:2018 + +#[derive(Debug)] +struct A<'a> { + inner: Vec<&'a str>, +} + +struct B {} + +impl B { + async fn something_with_a(&mut self, a: A<'_>) -> Result<(), String> { + println!("{:?}", a); + Ok(()) + } +} + +async fn can_error(some_string: &str) -> Result<(), String> { + let a = A { inner: vec![some_string, "foo"] }; + let mut b = B {}; + Ok(b.something_with_a(a).await.map(|_| ())?) +} + +fn main() { +} diff --git a/src/test/ui/async-await/issues/issue-64477.rs b/src/test/ui/async-await/issues/issue-64477.rs new file mode 100644 index 0000000000000..5bd52d44a5827 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-64477.rs @@ -0,0 +1,20 @@ +// Regression test for #64477. +// +// We were incorrectly claiming that the `f(x).await` future captured +// a value of type `T`, and hence that `T: Send` would have to hold. +// +// check-pass +// edition:2018 + +use std::future::Future; +use std::pin::Pin; + +fn f(_: &T) -> Pin + Send>> { + unimplemented!() +} + +pub fn g(x: &'static T) -> impl Future + Send { + async move { f(x).await } +} + +fn main() { } diff --git a/src/test/ui/async-await/issues/issue-64964.rs b/src/test/ui/async-await/issues/issue-64964.rs new file mode 100644 index 0000000000000..11f6cb6af9cc6 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-64964.rs @@ -0,0 +1,22 @@ +// check-pass +// compile-flags: -Z query-dep-graph +// edition:2018 + +// Regression test for ICE related to `await`ing in a method + incr. comp. (#64964) + +struct Body; +impl Body { + async fn next(&mut self) { + async {}.await + } +} + +// Another reproduction: `await`ing with a variable from for-loop. + +async fn bar() { + for x in 0..10 { + async { Some(x) }.await.unwrap(); + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/non-async-enclosing-span.rs b/src/test/ui/async-await/issues/non-async-enclosing-span.rs new file mode 100644 index 0000000000000..d47c2137725d6 --- /dev/null +++ b/src/test/ui/async-await/issues/non-async-enclosing-span.rs @@ -0,0 +1,11 @@ +// edition:2018 + +async fn do_the_thing() -> u8 { + 8 +} +// #63398: point at the enclosing scope and not the previously seen closure +fn main() { //~ NOTE this is not `async` + let x = move || {}; + let y = do_the_thing().await; //~ ERROR `await` is only allowed inside `async` functions + //~^ NOTE only allowed inside `async` functions and blocks +} diff --git a/src/test/ui/async-await/issues/non-async-enclosing-span.stderr b/src/test/ui/async-await/issues/non-async-enclosing-span.stderr new file mode 100644 index 0000000000000..49ebf414c550b --- /dev/null +++ b/src/test/ui/async-await/issues/non-async-enclosing-span.stderr @@ -0,0 +1,11 @@ +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/non-async-enclosing-span.rs:9:13 + | +LL | fn main() { + | ---- this is not `async` +LL | let x = move || {}; +LL | let y = do_the_thing().await; + | ^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/move-part-await-return-rest-struct.rs b/src/test/ui/async-await/move-part-await-return-rest-struct.rs index 9bd7a515cbdbf..39ea2aae563a4 100644 --- a/src/test/ui/async-await/move-part-await-return-rest-struct.rs +++ b/src/test/ui/async-await/move-part-await-return-rest-struct.rs @@ -2,8 +2,6 @@ // edition:2018 // compile-flags: --crate-type lib -#![feature(async_await)] - struct Small { x: Vec, y: Vec, diff --git a/src/test/ui/async-await/move-part-await-return-rest-tuple.rs b/src/test/ui/async-await/move-part-await-return-rest-tuple.rs index 69eee855e7594..7b958b98b414f 100644 --- a/src/test/ui/async-await/move-part-await-return-rest-tuple.rs +++ b/src/test/ui/async-await/move-part-await-return-rest-tuple.rs @@ -2,8 +2,6 @@ // edition:2018 // compile-flags: --crate-type lib -#![feature(async_await)] - async fn move_part_await_return_rest_tuple() -> Vec { let x = (vec![3], vec![4, 4]); drop(x.1); diff --git a/src/test/ui/async-await/multiple-lifetimes/elided.rs b/src/test/ui/async-await/multiple-lifetimes/elided.rs index 45f3170d4c309..8258e2eff521b 100644 --- a/src/test/ui/async-await/multiple-lifetimes/elided.rs +++ b/src/test/ui/async-await/multiple-lifetimes/elided.rs @@ -3,8 +3,6 @@ // Test that we can use async fns with multiple arbitrary lifetimes. -#![feature(async_await)] - async fn multiple_elided_lifetimes(_: &u8, _: &u8) {} fn main() { diff --git a/src/test/ui/async-await/multiple-lifetimes/fn-ptr.rs b/src/test/ui/async-await/multiple-lifetimes/fn-ptr.rs index a7254cee75526..3912b854747de 100644 --- a/src/test/ui/async-await/multiple-lifetimes/fn-ptr.rs +++ b/src/test/ui/async-await/multiple-lifetimes/fn-ptr.rs @@ -3,8 +3,6 @@ // Test that we can use async fns with multiple arbitrary lifetimes. -#![feature(async_await)] - async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8, _: fn(&u8)) {} fn gimme(_: &u8) { } diff --git a/src/test/ui/async-await/multiple-lifetimes/hrtb.rs b/src/test/ui/async-await/multiple-lifetimes/hrtb.rs index 589e260d084b2..e788ca5ff49c3 100644 --- a/src/test/ui/async-await/multiple-lifetimes/hrtb.rs +++ b/src/test/ui/async-await/multiple-lifetimes/hrtb.rs @@ -1,11 +1,8 @@ // edition:2018 -// run-pass +// check-pass // Test that we can use async fns with multiple arbitrary lifetimes. -#![feature(async_await)] -#![allow(dead_code)] - use std::ops::Add; async fn multiple_hrtb_and_single_named_lifetime_ok<'c>( diff --git a/src/test/ui/async-await/multiple-lifetimes/named.rs b/src/test/ui/async-await/multiple-lifetimes/named.rs index cd479e256b4e5..e8eb98102f478 100644 --- a/src/test/ui/async-await/multiple-lifetimes/named.rs +++ b/src/test/ui/async-await/multiple-lifetimes/named.rs @@ -3,8 +3,6 @@ // Test that we can use async fns with multiple arbitrary lifetimes. -#![feature(async_await)] - async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {} fn main() { diff --git a/src/test/ui/async-await/multiple-lifetimes/partial-relation.rs b/src/test/ui/async-await/multiple-lifetimes/partial-relation.rs index 903c43950a5c4..02b105999f5bb 100644 --- a/src/test/ui/async-await/multiple-lifetimes/partial-relation.rs +++ b/src/test/ui/async-await/multiple-lifetimes/partial-relation.rs @@ -1,8 +1,6 @@ // edition:2018 // run-pass -#![feature(async_await)] - async fn lotsa_lifetimes<'a, 'b, 'c>(a: &'a u32, b: &'b u32, c: &'c u32) -> (&'a u32, &'b u32) where 'b: 'a { diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs index 08622311f7b1c..b901b61aa1898 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs @@ -4,7 +4,7 @@ // Test that a feature gate is needed to use `impl Trait` as the // return type of an async. -#![feature(async_await, member_constraints)] +#![feature(member_constraints)] trait Trait<'a, 'b> { } impl Trait<'_, '_> for T { } diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs index 08ecea4cc85fc..2c7a5cd378fc2 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs @@ -3,8 +3,6 @@ // Test that a feature gate is needed to use `impl Trait` as the // return type of an async. -#![feature(async_await)] - trait Trait<'a, 'b> { } impl Trait<'_, '_> for T { } diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr index de2c85d772a72..59d7728d41c4c 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr @@ -1,5 +1,5 @@ error: ambiguous lifetime bound in `impl Trait` - --> $DIR/ret-impl-trait-no-fg.rs:11:64 + --> $DIR/ret-impl-trait-no-fg.rs:9:64 | LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { | ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs index e1b714652737f..babc90a5e96ad 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs @@ -3,7 +3,7 @@ // Test that a feature gate is needed to use `impl Trait` as the // return type of an async. -#![feature(async_await, member_constraints)] +#![feature(member_constraints)] trait Trait<'a> { } impl Trait<'_> for T { } diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-ref.rs b/src/test/ui/async-await/multiple-lifetimes/ret-ref.rs index 98da90161e5fd..149c020f9cb9c 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-ref.rs +++ b/src/test/ui/async-await/multiple-lifetimes/ret-ref.rs @@ -4,8 +4,6 @@ // function (which takes multiple lifetimes) only returns data from // one of them. -#![feature(async_await)] - async fn multiple_named_lifetimes<'a, 'b>(a: &'a u8, _: &'b u8) -> &'a u8 { a } diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-ref.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-ref.stderr index fe70d35942c7c..d86e84033b8cd 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-ref.stderr +++ b/src/test/ui/async-await/multiple-lifetimes/ret-ref.stderr @@ -1,5 +1,5 @@ error[E0506]: cannot assign to `a` because it is borrowed - --> $DIR/ret-ref.rs:18:5 + --> $DIR/ret-ref.rs:16:5 | LL | let future = multiple_named_lifetimes(&a, &b); | -- borrow of `a` occurs here @@ -10,7 +10,7 @@ LL | let p = future.await; | ------ borrow later used here error[E0506]: cannot assign to `b` because it is borrowed - --> $DIR/ret-ref.rs:19:5 + --> $DIR/ret-ref.rs:17:5 | LL | let future = multiple_named_lifetimes(&a, &b); | -- borrow of `b` occurs here @@ -21,7 +21,7 @@ LL | let p = future.await; | ------ borrow later used here error[E0506]: cannot assign to `a` because it is borrowed - --> $DIR/ret-ref.rs:30:5 + --> $DIR/ret-ref.rs:28:5 | LL | let future = multiple_named_lifetimes(&a, &b); | -- borrow of `a` occurs here diff --git a/src/test/ui/async-await/multiple-lifetimes/variance.rs b/src/test/ui/async-await/multiple-lifetimes/variance.rs index b52ad17d5631d..6ed8bef956a52 100644 --- a/src/test/ui/async-await/multiple-lifetimes/variance.rs +++ b/src/test/ui/async-await/multiple-lifetimes/variance.rs @@ -4,9 +4,6 @@ // Test for async fn where the parameters have distinct lifetime // parameters that appear in all possible variances. -#![feature(async_await)] - -#[allow(dead_code)] async fn lotsa_lifetimes<'a, 'b, 'c>(_: fn(&'a u8), _: fn(&'b u8) -> &'b u8, _: fn() -> &'c u8) { } fn take_any(_: &u8) { } diff --git a/src/test/ui/async-await/mutually-recursive-async-impl-trait-type.rs b/src/test/ui/async-await/mutually-recursive-async-impl-trait-type.rs new file mode 100644 index 0000000000000..bb2a61f03ce1f --- /dev/null +++ b/src/test/ui/async-await/mutually-recursive-async-impl-trait-type.rs @@ -0,0 +1,13 @@ +// edition:2018 +// Test that impl trait does not allow creating recursive types that are +// otherwise forbidden when using `async` and `await`. + +async fn rec_1() { //~ ERROR recursion in an `async fn` + rec_2().await; +} + +async fn rec_2() { //~ ERROR recursion in an `async fn` + rec_1().await; +} + +fn main() {} diff --git a/src/test/ui/async-await/mutually-recursive-async-impl-trait-type.stderr b/src/test/ui/async-await/mutually-recursive-async-impl-trait-type.stderr new file mode 100644 index 0000000000000..9249308936e54 --- /dev/null +++ b/src/test/ui/async-await/mutually-recursive-async-impl-trait-type.stderr @@ -0,0 +1,19 @@ +error[E0733]: recursion in an `async fn` requires boxing + --> $DIR/mutually-recursive-async-impl-trait-type.rs:5:18 + | +LL | async fn rec_1() { + | ^ recursive `async fn` + | + = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`. + +error[E0733]: recursion in an `async fn` requires boxing + --> $DIR/mutually-recursive-async-impl-trait-type.rs:9:18 + | +LL | async fn rec_2() { + | ^ recursive `async fn` + | + = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`. + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0733`. diff --git a/src/test/ui/async-await/nested-in-impl.rs b/src/test/ui/async-await/nested-in-impl.rs new file mode 100644 index 0000000000000..76ed827d5973e --- /dev/null +++ b/src/test/ui/async-await/nested-in-impl.rs @@ -0,0 +1,15 @@ +// Test that async fn works when nested inside of +// impls with lifetime parameters. +// +// check-pass +// edition:2018 + +struct Foo<'a>(&'a ()); + +impl<'a> Foo<'a> { + fn test() { + async fn test() {} + } +} + +fn main() { } diff --git a/src/test/ui/async-await/no-args-non-move-async-closure.rs b/src/test/ui/async-await/no-args-non-move-async-closure.rs deleted file mode 100644 index 62d4b3fb6f23b..0000000000000 --- a/src/test/ui/async-await/no-args-non-move-async-closure.rs +++ /dev/null @@ -1,8 +0,0 @@ -// edition:2018 - -#![feature(async_await, async_closure)] - -fn main() { - let _ = async |x: u8| {}; - //~^ ERROR `async` non-`move` closures with arguments are not currently supported -} diff --git a/src/test/ui/async-await/no-async-const.rs b/src/test/ui/async-await/no-async-const.rs index 1db314a5aa208..7a6eb498b2ee0 100644 --- a/src/test/ui/async-await/no-async-const.rs +++ b/src/test/ui/async-await/no-async-const.rs @@ -2,7 +2,5 @@ // edition:2018 // compile-flags: --crate-type lib -#![feature(async_await)] - pub async const fn x() {} //~^ ERROR expected one of `fn` or `unsafe`, found `const` diff --git a/src/test/ui/async-await/no-async-const.stderr b/src/test/ui/async-await/no-async-const.stderr index cdb1c6e2d7bd9..edbdfb5652281 100644 --- a/src/test/ui/async-await/no-async-const.stderr +++ b/src/test/ui/async-await/no-async-const.stderr @@ -1,5 +1,5 @@ error: expected one of `fn` or `unsafe`, found `const` - --> $DIR/no-async-const.rs:7:11 + --> $DIR/no-async-const.rs:5:11 | LL | pub async const fn x() {} | ^^^^^ expected one of `fn` or `unsafe` here diff --git a/src/test/ui/async-await/no-const-async.rs b/src/test/ui/async-await/no-const-async.rs index 9f09d2188c7c0..ef7edf8504952 100644 --- a/src/test/ui/async-await/no-const-async.rs +++ b/src/test/ui/async-await/no-const-async.rs @@ -2,8 +2,6 @@ // edition:2018 // compile-flags: --crate-type lib -#![feature(async_await)] - pub const async fn x() {} -//~^ ERROR expected identifier, found reserved keyword `async` +//~^ ERROR expected identifier, found keyword `async` //~^^ expected `:`, found keyword `fn` diff --git a/src/test/ui/async-await/no-const-async.stderr b/src/test/ui/async-await/no-const-async.stderr index 693fbf186f913..fe0591457853e 100644 --- a/src/test/ui/async-await/no-const-async.stderr +++ b/src/test/ui/async-await/no-const-async.stderr @@ -1,15 +1,15 @@ -error: expected identifier, found reserved keyword `async` - --> $DIR/no-const-async.rs:7:11 +error: expected identifier, found keyword `async` + --> $DIR/no-const-async.rs:5:11 | LL | pub const async fn x() {} - | ^^^^^ expected identifier, found reserved keyword + | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | LL | pub const r#async fn x() {} | ^^^^^^^ error: expected `:`, found keyword `fn` - --> $DIR/no-const-async.rs:7:17 + --> $DIR/no-const-async.rs:5:17 | LL | pub const async fn x() {} | ^^ expected `:` diff --git a/src/test/ui/async-await/no-move-across-await-struct.rs b/src/test/ui/async-await/no-move-across-await-struct.rs index 58e094708979c..bef477bd256ec 100644 --- a/src/test/ui/async-await/no-move-across-await-struct.rs +++ b/src/test/ui/async-await/no-move-across-await-struct.rs @@ -2,8 +2,6 @@ // edition:2018 // compile-flags: --crate-type lib -#![feature(async_await)] - async fn no_move_across_await_struct() -> Vec { let s = Small { x: vec![31], y: vec![19, 1441] }; needs_vec(s.x).await; diff --git a/src/test/ui/async-await/no-move-across-await-struct.stderr b/src/test/ui/async-await/no-move-across-await-struct.stderr index 121c7791bd98e..88f147b8d9ddd 100644 --- a/src/test/ui/async-await/no-move-across-await-struct.stderr +++ b/src/test/ui/async-await/no-move-across-await-struct.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `s.x` - --> $DIR/no-move-across-await-struct.rs:10:5 + --> $DIR/no-move-across-await-struct.rs:8:5 | LL | needs_vec(s.x).await; | --- value moved here diff --git a/src/test/ui/async-await/no-move-across-await-tuple.rs b/src/test/ui/async-await/no-move-across-await-tuple.rs index 5d3ed3da1e316..565cbd7d5f4ae 100644 --- a/src/test/ui/async-await/no-move-across-await-tuple.rs +++ b/src/test/ui/async-await/no-move-across-await-tuple.rs @@ -2,8 +2,6 @@ // edition:2018 // compile-flags: --crate-type lib -#![feature(async_await)] - async fn no_move_across_await_tuple() -> Vec { let x = (vec![3], vec![4, 4]); drop(x.1); diff --git a/src/test/ui/async-await/no-move-across-await-tuple.stderr b/src/test/ui/async-await/no-move-across-await-tuple.stderr index 5da037ea5c0b6..fe98ecd599a23 100644 --- a/src/test/ui/async-await/no-move-across-await-tuple.stderr +++ b/src/test/ui/async-await/no-move-across-await-tuple.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `x.1` - --> $DIR/no-move-across-await-tuple.rs:11:5 + --> $DIR/no-move-across-await-tuple.rs:9:5 | LL | drop(x.1); | --- value moved here diff --git a/src/test/ui/async-await/no-non-guaranteed-initialization.rs b/src/test/ui/async-await/no-non-guaranteed-initialization.rs index a916afb6b09b7..6a34209d55289 100644 --- a/src/test/ui/async-await/no-non-guaranteed-initialization.rs +++ b/src/test/ui/async-await/no-non-guaranteed-initialization.rs @@ -2,15 +2,13 @@ // edition:2018 // compile-flags: --crate-type lib -#![feature(async_await)] - async fn no_non_guaranteed_initialization(x: usize) -> usize { let y; if x > 5 { y = echo(10).await; } y - //~^ use of possibly uninitialized variable: `y` + //~^ use of possibly-uninitialized variable: `y` } async fn echo(x: usize) -> usize { x + 1 } diff --git a/src/test/ui/async-await/no-non-guaranteed-initialization.stderr b/src/test/ui/async-await/no-non-guaranteed-initialization.stderr index fb94522cac08d..b9aa9924bb815 100644 --- a/src/test/ui/async-await/no-non-guaranteed-initialization.stderr +++ b/src/test/ui/async-await/no-non-guaranteed-initialization.stderr @@ -1,8 +1,8 @@ -error[E0381]: use of possibly uninitialized variable: `y` - --> $DIR/no-non-guaranteed-initialization.rs:12:5 +error[E0381]: use of possibly-uninitialized variable: `y` + --> $DIR/no-non-guaranteed-initialization.rs:10:5 | LL | y - | ^ use of possibly uninitialized `y` + | ^ use of possibly-uninitialized `y` error: aborting due to previous error diff --git a/src/test/ui/async-await/no-params-non-move-async-closure.rs b/src/test/ui/async-await/no-params-non-move-async-closure.rs new file mode 100644 index 0000000000000..3b15f35c260dc --- /dev/null +++ b/src/test/ui/async-await/no-params-non-move-async-closure.rs @@ -0,0 +1,8 @@ +// edition:2018 + +#![feature(async_closure)] + +fn main() { + let _ = async |x: u8| {}; + //~^ ERROR `async` non-`move` closures with parameters are not currently supported +} diff --git a/src/test/ui/async-await/no-args-non-move-async-closure.stderr b/src/test/ui/async-await/no-params-non-move-async-closure.stderr similarity index 63% rename from src/test/ui/async-await/no-args-non-move-async-closure.stderr rename to src/test/ui/async-await/no-params-non-move-async-closure.stderr index 1b4b86210f840..04c8c325fe7da 100644 --- a/src/test/ui/async-await/no-args-non-move-async-closure.stderr +++ b/src/test/ui/async-await/no-params-non-move-async-closure.stderr @@ -1,5 +1,5 @@ -error[E0708]: `async` non-`move` closures with arguments are not currently supported - --> $DIR/no-args-non-move-async-closure.rs:6:13 +error[E0708]: `async` non-`move` closures with parameters are not currently supported + --> $DIR/no-params-non-move-async-closure.rs:6:13 | LL | let _ = async |x: u8| {}; | ^^^^^^^^^^^^^ diff --git a/src/test/ui/async-await/partial-initialization-across-await.rs b/src/test/ui/async-await/partial-initialization-across-await.rs index 40f9f5202e77c..8a98a4b0f6bb4 100644 --- a/src/test/ui/async-await/partial-initialization-across-await.rs +++ b/src/test/ui/async-await/partial-initialization-across-await.rs @@ -3,8 +3,6 @@ // edition:2018 -#![feature(async_await)] - struct S { x: i32, y: i32 } struct T(i32, i32); @@ -13,7 +11,7 @@ async fn noop() {} async fn test_tuple() { let mut t: (i32, i32); t.0 = 42; - //~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381] + //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] noop().await; t.1 = 88; let _ = t; @@ -22,7 +20,7 @@ async fn test_tuple() { async fn test_tuple_struct() { let mut t: T; t.0 = 42; - //~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381] + //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] noop().await; t.1 = 88; let _ = t; @@ -31,7 +29,7 @@ async fn test_tuple_struct() { async fn test_struct() { let mut t: S; t.x = 42; - //~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381] + //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] noop().await; t.y = 88; let _ = t; diff --git a/src/test/ui/async-await/partial-initialization-across-await.stderr b/src/test/ui/async-await/partial-initialization-across-await.stderr index fe79eb08befaa..9a510c22c4b1e 100644 --- a/src/test/ui/async-await/partial-initialization-across-await.stderr +++ b/src/test/ui/async-await/partial-initialization-across-await.stderr @@ -1,20 +1,20 @@ -error[E0381]: assign to part of possibly uninitialized variable: `t` - --> $DIR/partial-initialization-across-await.rs:15:5 +error[E0381]: assign to part of possibly-uninitialized variable: `t` + --> $DIR/partial-initialization-across-await.rs:13:5 | LL | t.0 = 42; - | ^^^^^^^^ use of possibly uninitialized `t` + | ^^^^^^^^ use of possibly-uninitialized `t` -error[E0381]: assign to part of possibly uninitialized variable: `t` - --> $DIR/partial-initialization-across-await.rs:24:5 +error[E0381]: assign to part of possibly-uninitialized variable: `t` + --> $DIR/partial-initialization-across-await.rs:22:5 | LL | t.0 = 42; - | ^^^^^^^^ use of possibly uninitialized `t` + | ^^^^^^^^ use of possibly-uninitialized `t` -error[E0381]: assign to part of possibly uninitialized variable: `t` - --> $DIR/partial-initialization-across-await.rs:33:5 +error[E0381]: assign to part of possibly-uninitialized variable: `t` + --> $DIR/partial-initialization-across-await.rs:31:5 | LL | t.x = 42; - | ^^^^^^^^ use of possibly uninitialized `t` + | ^^^^^^^^ use of possibly-uninitialized `t` error: aborting due to 3 previous errors diff --git a/src/test/ui/async-await/recursive-async-impl-trait-type.rs b/src/test/ui/async-await/recursive-async-impl-trait-type.rs index 54f3339870bda..aa7733194587d 100644 --- a/src/test/ui/async-await/recursive-async-impl-trait-type.rs +++ b/src/test/ui/async-await/recursive-async-impl-trait-type.rs @@ -2,8 +2,6 @@ // Test that impl trait does not allow creating recursive types that are // otherwise forbidden when using `async` and `await`. -#![feature(async_await)] - async fn recursive_async_function() -> () { //~ ERROR recursive_async_function().await; } diff --git a/src/test/ui/async-await/recursive-async-impl-trait-type.stderr b/src/test/ui/async-await/recursive-async-impl-trait-type.stderr index 64f6eccd5479a..9ee014021804e 100644 --- a/src/test/ui/async-await/recursive-async-impl-trait-type.stderr +++ b/src/test/ui/async-await/recursive-async-impl-trait-type.stderr @@ -1,10 +1,10 @@ error[E0733]: recursion in an `async fn` requires boxing - --> $DIR/recursive-async-impl-trait-type.rs:7:40 + --> $DIR/recursive-async-impl-trait-type.rs:5:40 | LL | async fn recursive_async_function() -> () { - | ^^ an `async fn` cannot invoke itself directly + | ^^ recursive `async fn` | - = note: a recursive `async fn` must be rewritten to return a boxed future. + = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`. error: aborting due to previous error diff --git a/src/test/ui/async-await/return-ty-raw-ptr-coercion.rs b/src/test/ui/async-await/return-ty-raw-ptr-coercion.rs new file mode 100644 index 0000000000000..9fe0869cad6c0 --- /dev/null +++ b/src/test/ui/async-await/return-ty-raw-ptr-coercion.rs @@ -0,0 +1,25 @@ +// Check that we apply unsizing coercions based on the return type. +// +// Also serves as a regression test for #60424. +// +// edition:2018 +// check-pass + +#![allow(warnings)] + +use std::fmt::Debug; + +const TMP: u32 = 22; + +// Coerce from `&u32` to `*const u32` +fn raw_pointer_coercion() { + fn sync_example() -> *const u32 { + &TMP + } + + async fn async_example() -> *const u32 { + &TMP + } +} + +fn main() {} diff --git a/src/test/ui/async-await/return-ty-unsize-coercion.rs b/src/test/ui/async-await/return-ty-unsize-coercion.rs new file mode 100644 index 0000000000000..93832ef7eddb5 --- /dev/null +++ b/src/test/ui/async-await/return-ty-unsize-coercion.rs @@ -0,0 +1,45 @@ +// Check that we apply unsizing coercions based on the return type. +// +// Also serves as a regression test for #60424. +// +// edition:2018 +// check-pass + +#![allow(warnings)] + +use std::fmt::Debug; + +// Unsizing coercion from `Box<&'static str>` to `Box`. +fn unsize_trait_coercion() { + fn sync_example() -> Box { + Box::new("asdf") + } + + async fn async_example() -> Box { + Box::new("asdf") + } +} + +// Unsizing coercion from `Box<[u32; N]>` to `Box<[32]>`. +fn unsize_slice_coercion() { + fn sync_example() -> Box<[u32]> { + Box::new([0]) + } + + async fn async_example() -> Box<[u32]> { + Box::new([0]) + } +} + +// Unsizing coercion from `&[&str; 1]` to `&[&str]` +fn unsize_slice_str_coercion() { + fn sync_example() -> &'static [&'static str] { + &["hi"] + } + + async fn async_example() -> &'static [&'static str] { + &["hi"] + } +} + +fn main() {} diff --git a/src/test/ui/async-await/suggest-missing-await-closure.fixed b/src/test/ui/async-await/suggest-missing-await-closure.fixed index 60c9a8581ac9e..37b30ffe6800f 100644 --- a/src/test/ui/async-await/suggest-missing-await-closure.fixed +++ b/src/test/ui/async-await/suggest-missing-await-closure.fixed @@ -1,7 +1,7 @@ // edition:2018 // run-rustfix -#![feature(async_await, async_closure)] +#![feature(async_closure)] fn take_u32(_x: u32) {} diff --git a/src/test/ui/async-await/suggest-missing-await-closure.rs b/src/test/ui/async-await/suggest-missing-await-closure.rs index cb992a27bc1c6..18076a1516171 100644 --- a/src/test/ui/async-await/suggest-missing-await-closure.rs +++ b/src/test/ui/async-await/suggest-missing-await-closure.rs @@ -1,7 +1,7 @@ // edition:2018 // run-rustfix -#![feature(async_await, async_closure)] +#![feature(async_closure)] fn take_u32(_x: u32) {} diff --git a/src/test/ui/async-await/suggest-missing-await.fixed b/src/test/ui/async-await/suggest-missing-await.fixed index aa032682be822..7c02a907ce7ad 100644 --- a/src/test/ui/async-await/suggest-missing-await.fixed +++ b/src/test/ui/async-await/suggest-missing-await.fixed @@ -1,8 +1,6 @@ // edition:2018 // run-rustfix -#![feature(async_await)] - fn take_u32(_x: u32) {} async fn make_u32() -> u32 { diff --git a/src/test/ui/async-await/suggest-missing-await.rs b/src/test/ui/async-await/suggest-missing-await.rs index 2ca814fbb22b5..91abd44e65caf 100644 --- a/src/test/ui/async-await/suggest-missing-await.rs +++ b/src/test/ui/async-await/suggest-missing-await.rs @@ -1,8 +1,6 @@ // edition:2018 // run-rustfix -#![feature(async_await)] - fn take_u32(_x: u32) {} async fn make_u32() -> u32 { diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr index 9bae7150276a8..ccca97ec204b4 100644 --- a/src/test/ui/async-await/suggest-missing-await.stderr +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/suggest-missing-await.rs:15:14 + --> $DIR/suggest-missing-await.rs:13:14 | LL | take_u32(x) | ^ diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await.rs b/src/test/ui/async-await/suggest-switching-edition-on-await.rs new file mode 100644 index 0000000000000..1402f1ca92ba8 --- /dev/null +++ b/src/test/ui/async-await/suggest-switching-edition-on-await.rs @@ -0,0 +1,45 @@ +use std::pin::Pin; +use std::future::Future; + +fn main() {} + +fn await_on_struct_missing() { + struct S; + let x = S; + x.await; + //~^ ERROR no field `await` on type + //~| NOTE unknown field + //~| NOTE to `.await` a `Future`, switch to Rust 2018 + //~| HELP set `edition = "2018"` in `Cargo.toml` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide +} + +fn await_on_struct_similar() { + struct S { + awai: u8, + } + let x = S { awai: 42 }; + x.await; + //~^ ERROR no field `await` on type + //~| HELP a field with a similar name exists + //~| NOTE to `.await` a `Future`, switch to Rust 2018 + //~| HELP set `edition = "2018"` in `Cargo.toml` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide +} + +fn await_on_63533(x: Pin<&mut dyn Future>) { + x.await; + //~^ ERROR no field `await` on type + //~| NOTE unknown field + //~| NOTE to `.await` a `Future`, switch to Rust 2018 + //~| HELP set `edition = "2018"` in `Cargo.toml` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide +} + +fn await_on_apit(x: impl Future) { + x.await; + //~^ ERROR no field `await` on type + //~| NOTE to `.await` a `Future`, switch to Rust 2018 + //~| HELP set `edition = "2018"` in `Cargo.toml` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide +} diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await.stderr b/src/test/ui/async-await/suggest-switching-edition-on-await.stderr new file mode 100644 index 0000000000000..f623511c0eb23 --- /dev/null +++ b/src/test/ui/async-await/suggest-switching-edition-on-await.stderr @@ -0,0 +1,43 @@ +error[E0609]: no field `await` on type `await_on_struct_missing::S` + --> $DIR/suggest-switching-edition-on-await.rs:9:7 + | +LL | x.await; + | ^^^^^ unknown field + | + = note: to `.await` a `Future`, switch to Rust 2018 + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0609]: no field `await` on type `await_on_struct_similar::S` + --> $DIR/suggest-switching-edition-on-await.rs:22:7 + | +LL | x.await; + | ^^^^^ help: a field with a similar name exists: `awai` + | + = note: to `.await` a `Future`, switch to Rust 2018 + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0609]: no field `await` on type `std::pin::Pin<&mut dyn std::future::Future>` + --> $DIR/suggest-switching-edition-on-await.rs:31:7 + | +LL | x.await; + | ^^^^^ unknown field + | + = note: to `.await` a `Future`, switch to Rust 2018 + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0609]: no field `await` on type `impl Future` + --> $DIR/suggest-switching-edition-on-await.rs:40:7 + | +LL | x.await; + | ^^^^^ + | + = note: to `.await` a `Future`, switch to Rust 2018 + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0609`. diff --git a/src/test/ui/async-await/unreachable-lint-1.rs b/src/test/ui/async-await/unreachable-lint-1.rs new file mode 100644 index 0000000000000..d63d643c4e70b --- /dev/null +++ b/src/test/ui/async-await/unreachable-lint-1.rs @@ -0,0 +1,12 @@ +// edition:2018 +#![deny(unreachable_code)] + +async fn foo() { + return; bar().await; + //~^ ERROR unreachable statement +} + +async fn bar() { +} + +fn main() { } diff --git a/src/test/ui/async-await/unreachable-lint-1.stderr b/src/test/ui/async-await/unreachable-lint-1.stderr new file mode 100644 index 0000000000000..382581bf94554 --- /dev/null +++ b/src/test/ui/async-await/unreachable-lint-1.stderr @@ -0,0 +1,16 @@ +error: unreachable statement + --> $DIR/unreachable-lint-1.rs:5:13 + | +LL | return; bar().await; + | ------ ^^^^^^^^^^^^ unreachable statement + | | + | any code following this expression is unreachable + | +note: lint level defined here + --> $DIR/unreachable-lint-1.rs:2:9 + | +LL | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/unreachable-lint.rs b/src/test/ui/async-await/unreachable-lint.rs new file mode 100644 index 0000000000000..ca18cfde4f2f5 --- /dev/null +++ b/src/test/ui/async-await/unreachable-lint.rs @@ -0,0 +1,13 @@ +// check-pass +// edition:2018 +#![deny(unreachable_code)] + +async fn foo() { + endless().await; +} + +async fn endless() -> ! { + loop {} +} + +fn main() { } diff --git a/src/test/ui/async-await/unresolved_type_param.rs b/src/test/ui/async-await/unresolved_type_param.rs index 578d41fe0df0b..2876f9fea0e00 100644 --- a/src/test/ui/async-await/unresolved_type_param.rs +++ b/src/test/ui/async-await/unresolved_type_param.rs @@ -2,14 +2,14 @@ // Error message should pinpoint the type parameter T as needing to be bound // (rather than give a general error message) // edition:2018 -#![feature(async_await)] + async fn bar() -> () {} async fn foo() { bar().await; - //~^ ERROR type inside `async` object must be known in this context + //~^ ERROR type inside `async fn` body must be known in this context //~| NOTE cannot infer type for `T` - //~| NOTE the type is part of the `async` object because of this `await` + //~| NOTE the type is part of the `async fn` body because of this `await` //~| NOTE in this expansion of desugaring of `await` } fn main() {} diff --git a/src/test/ui/async-await/unresolved_type_param.stderr b/src/test/ui/async-await/unresolved_type_param.stderr index f3090a2b980e8..c7866fc774415 100644 --- a/src/test/ui/async-await/unresolved_type_param.stderr +++ b/src/test/ui/async-await/unresolved_type_param.stderr @@ -1,10 +1,10 @@ -error[E0698]: type inside `async` object must be known in this context +error[E0698]: type inside `async fn` body must be known in this context --> $DIR/unresolved_type_param.rs:9:5 | LL | bar().await; | ^^^ cannot infer type for `T` | -note: the type is part of the `async` object because of this `await` +note: the type is part of the `async fn` body because of this `await` --> $DIR/unresolved_type_param.rs:9:5 | LL | bar().await; diff --git a/src/test/ui/attributes/item-attributes.rs b/src/test/ui/attributes/item-attributes.rs index c760a28ecf0ba..79cd0f5fbc358 100644 --- a/src/test/ui/attributes/item-attributes.rs +++ b/src/test/ui/attributes/item-attributes.rs @@ -11,8 +11,6 @@ #![rustc_dummy] #![rustc_dummy(attr5)] -#![crate_id="foobar#0.1"] - // These are attributes of the following mod #[rustc_dummy = "val"] #[rustc_dummy = "val"] diff --git a/src/test/ui/attributes/multiple-invalid.rs b/src/test/ui/attributes/multiple-invalid.rs new file mode 100644 index 0000000000000..ae044eb843bd9 --- /dev/null +++ b/src/test/ui/attributes/multiple-invalid.rs @@ -0,0 +1,10 @@ +// This test checks that all expected errors occur when there are multiple invalid attributes +// on an item. + +#[inline] +//~^ ERROR attribute should be applied to function or closure [E0518] +#[target_feature(enable = "sse2")] +//~^ ERROR attribute should be applied to a function +const FOO: u8 = 0; + +fn main() { } diff --git a/src/test/ui/attributes/multiple-invalid.stderr b/src/test/ui/attributes/multiple-invalid.stderr new file mode 100644 index 0000000000000..9bd29f15dbcca --- /dev/null +++ b/src/test/ui/attributes/multiple-invalid.stderr @@ -0,0 +1,21 @@ +error[E0518]: attribute should be applied to function or closure + --> $DIR/multiple-invalid.rs:4:1 + | +LL | #[inline] + | ^^^^^^^^^ +... +LL | const FOO: u8 = 0; + | ------------------ not a function or closure + +error: attribute should be applied to a function + --> $DIR/multiple-invalid.rs:6:1 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | const FOO: u8 = 0; + | ------------------ not a function + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0518`. diff --git a/src/test/ui/attributes/obsolete-attr.rs b/src/test/ui/attributes/obsolete-attr.rs index 8759344e6f820..42f90eda166b6 100644 --- a/src/test/ui/attributes/obsolete-attr.rs +++ b/src/test/ui/attributes/obsolete-attr.rs @@ -1,9 +1,9 @@ -// Obsolete attributes fall back to feature gated custom attributes. +// Obsolete attributes fall back to unstable custom attributes. #[ab_isize="stdcall"] extern {} -//~^ ERROR cannot find attribute macro `ab_isize` in this scope +//~^ ERROR cannot find attribute `ab_isize` in this scope #[fixed_stack_segment] fn f() {} -//~^ ERROR cannot find attribute macro `fixed_stack_segment` in this scope +//~^ ERROR cannot find attribute `fixed_stack_segment` in this scope fn main() {} diff --git a/src/test/ui/attributes/obsolete-attr.stderr b/src/test/ui/attributes/obsolete-attr.stderr index 9c6909f65f3ea..2d7c257c6208c 100644 --- a/src/test/ui/attributes/obsolete-attr.stderr +++ b/src/test/ui/attributes/obsolete-attr.stderr @@ -1,10 +1,10 @@ -error: cannot find attribute macro `fixed_stack_segment` in this scope +error: cannot find attribute `fixed_stack_segment` in this scope --> $DIR/obsolete-attr.rs:6:3 | LL | #[fixed_stack_segment] fn f() {} | ^^^^^^^^^^^^^^^^^^^ -error: cannot find attribute macro `ab_isize` in this scope +error: cannot find attribute `ab_isize` in this scope --> $DIR/obsolete-attr.rs:3:3 | LL | #[ab_isize="stdcall"] extern {} diff --git a/src/test/ui/attributes/unknown-attr.rs b/src/test/ui/attributes/unknown-attr.rs index 140a1fc3f93e5..70fef04e95c67 100644 --- a/src/test/ui/attributes/unknown-attr.rs +++ b/src/test/ui/attributes/unknown-attr.rs @@ -1,12 +1,12 @@ -// Unknown attributes fall back to feature gated custom attributes. +// Unknown attributes fall back to unstable custom attributes. #![feature(custom_inner_attributes)] #![mutable_doc] -//~^ ERROR cannot find attribute macro `mutable_doc` in this scope +//~^ ERROR cannot find attribute `mutable_doc` in this scope #[dance] mod a {} -//~^ ERROR cannot find attribute macro `dance` in this scope +//~^ ERROR cannot find attribute `dance` in this scope #[dance] fn main() {} -//~^ ERROR cannot find attribute macro `dance` in this scope +//~^ ERROR cannot find attribute `dance` in this scope diff --git a/src/test/ui/attributes/unknown-attr.stderr b/src/test/ui/attributes/unknown-attr.stderr index 4d463874d669e..85c227dc83aa6 100644 --- a/src/test/ui/attributes/unknown-attr.stderr +++ b/src/test/ui/attributes/unknown-attr.stderr @@ -1,16 +1,16 @@ -error: cannot find attribute macro `mutable_doc` in this scope +error: cannot find attribute `mutable_doc` in this scope --> $DIR/unknown-attr.rs:5:4 | LL | #![mutable_doc] | ^^^^^^^^^^^ -error: cannot find attribute macro `dance` in this scope +error: cannot find attribute `dance` in this scope --> $DIR/unknown-attr.rs:8:3 | LL | #[dance] mod a {} | ^^^^^ -error: cannot find attribute macro `dance` in this scope +error: cannot find attribute `dance` in this scope --> $DIR/unknown-attr.rs:11:3 | LL | #[dance] fn main() {} diff --git a/src/test/ui/attributes/unnamed-field-attributes.rs b/src/test/ui/attributes/unnamed-field-attributes.rs new file mode 100644 index 0000000000000..93f364047e9a5 --- /dev/null +++ b/src/test/ui/attributes/unnamed-field-attributes.rs @@ -0,0 +1,9 @@ +// check-pass + +struct S( + #[rustfmt::skip] u8, + u16, + #[rustfmt::skip] u32, +); + +fn main() {} diff --git a/src/test/ui/attrs-resolution-errors.rs b/src/test/ui/attrs-resolution-errors.rs new file mode 100644 index 0000000000000..a38b3cfa6665e --- /dev/null +++ b/src/test/ui/attrs-resolution-errors.rs @@ -0,0 +1,40 @@ +enum FooEnum { + #[test] + //~^ ERROR expected an inert attribute, found an attribute macro + Bar(i32), +} + +struct FooStruct { + #[test] + //~^ ERROR expected an inert attribute, found an attribute macro + bar: i32, +} + +fn main() { + let foo_enum_bar = FooEnum::Bar(1); + match foo_enum_bar { + FooEnum::Bar(x) => {}, + _ => {} + } + + let foo_struct = FooStruct { bar: 1 }; + match foo_struct { + FooStruct { + #[test] bar + //~^ ERROR expected an inert attribute, found an attribute macro + } => {} + } + + match 1 { + 0 => {} + #[test] + //~^ ERROR expected an inert attribute, found an attribute macro + _ => {} + } + + let _another_foo_strunct = FooStruct { + #[test] + //~^ ERROR expected an inert attribute, found an attribute macro + bar: 1, + }; +} diff --git a/src/test/ui/attrs-resolution-errors.stderr b/src/test/ui/attrs-resolution-errors.stderr new file mode 100644 index 0000000000000..31f2a74edb333 --- /dev/null +++ b/src/test/ui/attrs-resolution-errors.stderr @@ -0,0 +1,32 @@ +error: expected an inert attribute, found an attribute macro + --> $DIR/attrs-resolution-errors.rs:2:5 + | +LL | #[test] + | ^^^^^^^ + +error: expected an inert attribute, found an attribute macro + --> $DIR/attrs-resolution-errors.rs:8:5 + | +LL | #[test] + | ^^^^^^^ + +error: expected an inert attribute, found an attribute macro + --> $DIR/attrs-resolution-errors.rs:23:13 + | +LL | #[test] bar + | ^^^^^^^ + +error: expected an inert attribute, found an attribute macro + --> $DIR/attrs-resolution-errors.rs:30:9 + | +LL | #[test] + | ^^^^^^^ + +error: expected an inert attribute, found an attribute macro + --> $DIR/attrs-resolution-errors.rs:36:9 + | +LL | #[test] + | ^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/attrs-resolution.rs b/src/test/ui/attrs-resolution.rs new file mode 100644 index 0000000000000..6809773237d2c --- /dev/null +++ b/src/test/ui/attrs-resolution.rs @@ -0,0 +1,37 @@ +// check-pass + +enum FooEnum { + #[rustfmt::skip] + Bar(i32), +} + +struct FooStruct { + #[rustfmt::skip] + bar: i32, +} + +fn main() { + let foo_enum_bar = FooEnum::Bar(1); + match foo_enum_bar { + FooEnum::Bar(x) => {} + _ => {} + } + + let foo_struct = FooStruct { bar: 1 }; + match foo_struct { + FooStruct { + #[rustfmt::skip] bar + } => {} + } + + match 1 { + 0 => {} + #[rustfmt::skip] + _ => {} + } + + let _another_foo_strunct = FooStruct { + #[rustfmt::skip] + bar: 1, + }; +} diff --git a/src/test/ui/auto-ref-slice-plus-ref.stderr b/src/test/ui/auto-ref-slice-plus-ref.stderr index f2e0d379d1b30..3e36f2402a990 100644 --- a/src/test/ui/auto-ref-slice-plus-ref.stderr +++ b/src/test/ui/auto-ref-slice-plus-ref.stderr @@ -12,7 +12,7 @@ error[E0599]: no method named `test` found for type `std::vec::Vec<{integer}>` i --> $DIR/auto-ref-slice-plus-ref.rs:8:7 | LL | a.test(); - | ^^^^ + | ^^^^ method not found in `std::vec::Vec<{integer}>` | = 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: @@ -22,7 +22,7 @@ error[E0599]: no method named `test` found for type `[{integer}; 1]` in the curr --> $DIR/auto-ref-slice-plus-ref.rs:10:11 | LL | ([1]).test(); - | ^^^^ + | ^^^^ method not found in `[{integer}; 1]` | = 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: @@ -32,7 +32,7 @@ error[E0599]: no method named `test` found for type `&[{integer}; 1]` in the cur --> $DIR/auto-ref-slice-plus-ref.rs:11:12 | LL | (&[1]).test(); - | ^^^^ + | ^^^^ method not found in `&[{integer}; 1]` | = 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: diff --git a/src/test/ui/auto-trait-validation.stderr b/src/test/ui/auto-trait-validation.stderr index ae21984c06d72..51422fab81fda 100644 --- a/src/test/ui/auto-trait-validation.stderr +++ b/src/test/ui/auto-trait-validation.stderr @@ -18,4 +18,5 @@ LL | auto trait MyTrait { fn foo() {} } error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0380`. +Some errors have detailed explanations: E0380, E0567, E0568. +For more information about an error, try `rustc --explain E0380`. diff --git a/src/test/ui/auxiliary/cond_plugin.rs b/src/test/ui/auxiliary/cond_plugin.rs index 1f97b556a0767..2819541bf6966 100644 --- a/src/test/ui/auxiliary/cond_plugin.rs +++ b/src/test/ui/auxiliary/cond_plugin.rs @@ -3,6 +3,7 @@ #![crate_type = "proc-macro"] #![feature(proc_macro_hygiene)] +#![feature(proc_macro_quote)] extern crate proc_macro; diff --git a/src/test/ui/auxiliary/proc_macro_def.rs b/src/test/ui/auxiliary/proc_macro_def.rs index dfc5a42d19c69..49cfb5518ba9c 100644 --- a/src/test/ui/auxiliary/proc_macro_def.rs +++ b/src/test/ui/auxiliary/proc_macro_def.rs @@ -3,6 +3,7 @@ #![crate_type = "proc-macro"] #![feature(proc_macro_hygiene)] +#![feature(proc_macro_quote)] extern crate proc_macro; diff --git a/src/test/ui/bind-by-move/bind-by-move-no-guards.rs b/src/test/ui/bind-by-move/bind-by-move-no-guards.rs deleted file mode 100644 index bc9b3a8de4ef5..0000000000000 --- a/src/test/ui/bind-by-move/bind-by-move-no-guards.rs +++ /dev/null @@ -1,13 +0,0 @@ -use std::sync::mpsc::channel; - -fn main() { - let (tx, rx) = channel(); - let x = Some(rx); - tx.send(false); - match x { - Some(z) if z.recv().unwrap() => { panic!() }, - //~^ ERROR cannot bind by-move into a pattern guard - Some(z) => { assert!(!z.recv().unwrap()); }, - None => panic!() - } -} diff --git a/src/test/ui/bind-by-move/bind-by-move-no-guards.stderr b/src/test/ui/bind-by-move/bind-by-move-no-guards.stderr deleted file mode 100644 index c5f0256c2c92f..0000000000000 --- a/src/test/ui/bind-by-move/bind-by-move-no-guards.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0008]: cannot bind by-move into a pattern guard - --> $DIR/bind-by-move-no-guards.rs:8:14 - | -LL | Some(z) if z.recv().unwrap() => { panic!() }, - | ^ moves value into pattern guard - | - = help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0008`. diff --git a/src/test/ui/block-expr-precedence.stderr b/src/test/ui/block-expr-precedence.stderr new file mode 100644 index 0000000000000..1307b5d6ddd82 --- /dev/null +++ b/src/test/ui/block-expr-precedence.stderr @@ -0,0 +1,8 @@ +warning: unnecessary trailing semicolons + --> $DIR/block-expr-precedence.rs:60:21 + | +LL | if (true) { 12; };;; -num; + | ^^ help: remove these semicolons + | + = note: `#[warn(redundant_semicolon)]` on by default + diff --git a/src/test/ui/block-result/consider-removing-last-semi.stderr b/src/test/ui/block-result/consider-removing-last-semi.stderr index 618d020ce08b5..f4984ca446309 100644 --- a/src/test/ui/block-result/consider-removing-last-semi.stderr +++ b/src/test/ui/block-result/consider-removing-last-semi.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn f() -> String { | - ^^^^^^ expected struct `std::string::String`, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression LL | 0u8; LL | "bla".to_string(); | - help: consider removing this semicolon @@ -18,7 +18,7 @@ error[E0308]: mismatched types LL | fn g() -> String { | - ^^^^^^ expected struct `std::string::String`, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression LL | "this won't work".to_string(); LL | "removeme".to_string(); | - help: consider removing this semicolon diff --git a/src/test/ui/block-result/issue-11714.stderr b/src/test/ui/block-result/issue-11714.stderr index d73489a602df4..cfb42c601279a 100644 --- a/src/test/ui/block-result/issue-11714.stderr +++ b/src/test/ui/block-result/issue-11714.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn blah() -> i32 { | ---- ^^^ expected i32, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression ... LL | ; | - help: consider removing this semicolon diff --git a/src/test/ui/block-result/issue-13428.stderr b/src/test/ui/block-result/issue-13428.stderr index 18adb15c9615d..f7cafab3d773b 100644 --- a/src/test/ui/block-result/issue-13428.stderr +++ b/src/test/ui/block-result/issue-13428.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn foo() -> String { | --- ^^^^^^ expected struct `std::string::String`, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression ... LL | ; | - help: consider removing this semicolon @@ -18,7 +18,7 @@ error[E0308]: mismatched types LL | fn bar() -> String { | --- ^^^^^^ expected struct `std::string::String`, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression LL | "foobar".to_string() LL | ; | - help: consider removing this semicolon diff --git a/src/test/ui/borrowck/assign_mutable_fields.stderr b/src/test/ui/borrowck/assign_mutable_fields.stderr index 35101df4e0a6e..40f1aae092dc6 100644 --- a/src/test/ui/borrowck/assign_mutable_fields.stderr +++ b/src/test/ui/borrowck/assign_mutable_fields.stderr @@ -1,14 +1,14 @@ -error[E0381]: assign to part of possibly uninitialized variable: `x` +error[E0381]: assign to part of possibly-uninitialized variable: `x` --> $DIR/assign_mutable_fields.rs:9:5 | LL | x.0 = 1; - | ^^^^^^^ use of possibly uninitialized `x` + | ^^^^^^^ use of possibly-uninitialized `x` -error[E0381]: assign to part of possibly uninitialized variable: `x` +error[E0381]: assign to part of possibly-uninitialized variable: `x` --> $DIR/assign_mutable_fields.rs:17:5 | LL | x.0 = 1; - | ^^^^^^^ use of possibly uninitialized `x` + | ^^^^^^^ use of possibly-uninitialized `x` error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-and-init.rs b/src/test/ui/borrowck/borrowck-and-init.rs index 4427e25186103..f11d44e2217ba 100644 --- a/src/test/ui/borrowck/borrowck-and-init.rs +++ b/src/test/ui/borrowck/borrowck-and-init.rs @@ -2,5 +2,5 @@ fn main() { let i: isize; println!("{}", false && { i = 5; true }); - println!("{}", i); //~ ERROR borrow of possibly uninitialized variable: `i` + println!("{}", i); //~ ERROR borrow of possibly-uninitialized variable: `i` } diff --git a/src/test/ui/borrowck/borrowck-and-init.stderr b/src/test/ui/borrowck/borrowck-and-init.stderr index 2db075194810e..c7e357d4604f7 100644 --- a/src/test/ui/borrowck/borrowck-and-init.stderr +++ b/src/test/ui/borrowck/borrowck-and-init.stderr @@ -1,8 +1,8 @@ -error[E0381]: borrow of possibly uninitialized variable: `i` +error[E0381]: borrow of possibly-uninitialized variable: `i` --> $DIR/borrowck-and-init.rs:5:20 | LL | println!("{}", i); - | ^ use of possibly uninitialized `i` + | ^ use of possibly-uninitialized `i` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr b/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr deleted file mode 100644 index f66994b3f100a..0000000000000 --- a/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr +++ /dev/null @@ -1,40 +0,0 @@ -error[E0503]: cannot use `y` because it was mutably borrowed - --> $DIR/borrowck-anon-fields-variant.rs:17:7 - | -LL | Foo::Y(ref mut a, _) => a, - | --------- borrow of `y.0` occurs here -... -LL | Foo::Y(_, ref mut b) => b, - | ^^^^^^^^^^^^^^^^^^^^ use of borrowed `y.0` -... -LL | *a += 1; - | ------- borrow later used here - -error[E0503]: cannot use `y` because it was mutably borrowed - --> $DIR/borrowck-anon-fields-variant.rs:37:7 - | -LL | Foo::Y(ref mut a, _) => a, - | --------- borrow of `y.0` occurs here -... -LL | Foo::Y(ref mut b, _) => b, - | ^^^^^^^^^^^^^^^^^^^^ use of borrowed `y.0` -... -LL | *a += 1; - | ------- borrow later used here - -error[E0499]: cannot borrow `y.0` as mutable more than once at a time - --> $DIR/borrowck-anon-fields-variant.rs:37:14 - | -LL | Foo::Y(ref mut a, _) => a, - | --------- first mutable borrow occurs here -... -LL | Foo::Y(ref mut b, _) => b, - | ^^^^^^^^^ second mutable borrow occurs here -... -LL | *a += 1; - | ------- first borrow later used here - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0499, E0503. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-anon-fields-variant.rs b/src/test/ui/borrowck/borrowck-anon-fields-variant.rs index 695809f58c551..cecc278e1931c 100644 --- a/src/test/ui/borrowck/borrowck-anon-fields-variant.rs +++ b/src/test/ui/borrowck/borrowck-anon-fields-variant.rs @@ -15,9 +15,7 @@ fn distinct_variant() { // reference. let b = match y { Foo::Y(_, ref mut b) => b, - //~^ WARNING cannot use `y` - //~| WARNING this error has been downgraded to a warning - //~| WARNING this warning will become a hard error in the future + //~^ ERROR cannot use `y` Foo::X => panic!() }; diff --git a/src/test/ui/borrowck/borrowck-anon-fields-variant.stderr b/src/test/ui/borrowck/borrowck-anon-fields-variant.stderr index e2d3e417ac3ac..2caeed1bd44ea 100644 --- a/src/test/ui/borrowck/borrowck-anon-fields-variant.stderr +++ b/src/test/ui/borrowck/borrowck-anon-fields-variant.stderr @@ -1,4 +1,4 @@ -warning[E0503]: cannot use `y` because it was mutably borrowed +error[E0503]: cannot use `y` because it was mutably borrowed --> $DIR/borrowck-anon-fields-variant.rs:17:7 | LL | Foo::Y(ref mut a, _) => a, @@ -9,13 +9,9 @@ LL | Foo::Y(_, ref mut b) => b, ... LL | *a += 1; | ------- borrow later used here - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future - = note: for more information, try `rustc --explain E0729` error[E0503]: cannot use `y` because it was mutably borrowed - --> $DIR/borrowck-anon-fields-variant.rs:37:7 + --> $DIR/borrowck-anon-fields-variant.rs:35:7 | LL | Foo::Y(ref mut a, _) => a, | --------- borrow of `y.0` occurs here @@ -27,7 +23,7 @@ LL | *a += 1; | ------- borrow later used here error[E0499]: cannot borrow `y.0` as mutable more than once at a time - --> $DIR/borrowck-anon-fields-variant.rs:37:14 + --> $DIR/borrowck-anon-fields-variant.rs:35:14 | LL | Foo::Y(ref mut a, _) => a, | --------- first mutable borrow occurs here @@ -38,7 +34,7 @@ LL | Foo::Y(ref mut b, _) => b, LL | *a += 1; | ------- first borrow later used here -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0499, E0503. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-asm.rs b/src/test/ui/borrowck/borrowck-asm.rs index 9c9cc04baafee..c1b0f39f9366c 100644 --- a/src/test/ui/borrowck/borrowck-asm.rs +++ b/src/test/ui/borrowck/borrowck-asm.rs @@ -57,7 +57,7 @@ mod test_cases { fn indirect_is_not_init() { let x: i32; unsafe { - asm!("nop" : "=*r"(x)); //~ ERROR use of possibly uninitialized variable + asm!("nop" : "=*r"(x)); //~ ERROR use of possibly-uninitialized variable } } diff --git a/src/test/ui/borrowck/borrowck-asm.stderr b/src/test/ui/borrowck/borrowck-asm.stderr index c771373022ac4..f85b5983acced 100644 --- a/src/test/ui/borrowck/borrowck-asm.stderr +++ b/src/test/ui/borrowck/borrowck-asm.stderr @@ -46,11 +46,11 @@ LL | unsafe { LL | asm!("nop" : "+r"(x)); | ^ cannot assign twice to immutable variable -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-asm.rs:60:32 | LL | asm!("nop" : "=*r"(x)); - | ^ use of possibly uninitialized `x` + | ^ use of possibly-uninitialized `x` error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/borrowck-asm.rs:68:31 diff --git a/src/test/ui/borrowck/borrowck-block-unint.rs b/src/test/ui/borrowck/borrowck-block-unint.rs index 1fed2d503bd35..1e7306acaee98 100644 --- a/src/test/ui/borrowck/borrowck-block-unint.rs +++ b/src/test/ui/borrowck/borrowck-block-unint.rs @@ -1,7 +1,7 @@ fn force(f: F) where F: FnOnce() { f(); } fn main() { let x: isize; - force(|| { //~ ERROR borrow of possibly uninitialized variable: `x` + force(|| { //~ ERROR borrow of possibly-uninitialized variable: `x` println!("{}", x); }); } diff --git a/src/test/ui/borrowck/borrowck-block-unint.stderr b/src/test/ui/borrowck/borrowck-block-unint.stderr index d2a49962bafca..578f89df46ce1 100644 --- a/src/test/ui/borrowck/borrowck-block-unint.stderr +++ b/src/test/ui/borrowck/borrowck-block-unint.stderr @@ -1,8 +1,8 @@ -error[E0381]: borrow of possibly uninitialized variable: `x` +error[E0381]: borrow of possibly-uninitialized variable: `x` --> $DIR/borrowck-block-unint.rs:4:11 | LL | force(|| { - | ^^ use of possibly uninitialized `x` + | ^^ use of possibly-uninitialized `x` LL | println!("{}", x); | - borrow occurs due to use in closure diff --git a/src/test/ui/borrowck/borrowck-break-uninit-2.rs b/src/test/ui/borrowck/borrowck-break-uninit-2.rs index dad5325cb8750..126d991a51c6e 100644 --- a/src/test/ui/borrowck/borrowck-break-uninit-2.rs +++ b/src/test/ui/borrowck/borrowck-break-uninit-2.rs @@ -6,7 +6,7 @@ fn foo() -> isize { x = 0; } - println!("{}", x); //~ ERROR borrow of possibly uninitialized variable: `x` + println!("{}", x); //~ ERROR borrow of possibly-uninitialized variable: `x` return 17; } diff --git a/src/test/ui/borrowck/borrowck-break-uninit-2.stderr b/src/test/ui/borrowck/borrowck-break-uninit-2.stderr index e40d8d9dfccb9..bc9b25c0221fc 100644 --- a/src/test/ui/borrowck/borrowck-break-uninit-2.stderr +++ b/src/test/ui/borrowck/borrowck-break-uninit-2.stderr @@ -1,8 +1,8 @@ -error[E0381]: borrow of possibly uninitialized variable: `x` +error[E0381]: borrow of possibly-uninitialized variable: `x` --> $DIR/borrowck-break-uninit-2.rs:9:20 | LL | println!("{}", x); - | ^ use of possibly uninitialized `x` + | ^ use of possibly-uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-break-uninit.rs b/src/test/ui/borrowck/borrowck-break-uninit.rs index 9af02b387d8b0..8ccb21ae8eebf 100644 --- a/src/test/ui/borrowck/borrowck-break-uninit.rs +++ b/src/test/ui/borrowck/borrowck-break-uninit.rs @@ -6,7 +6,7 @@ fn foo() -> isize { x = 0; } - println!("{}", x); //~ ERROR borrow of possibly uninitialized variable: `x` + println!("{}", x); //~ ERROR borrow of possibly-uninitialized variable: `x` return 17; } diff --git a/src/test/ui/borrowck/borrowck-break-uninit.stderr b/src/test/ui/borrowck/borrowck-break-uninit.stderr index bbf9b9f1241a2..766d5cfd6348c 100644 --- a/src/test/ui/borrowck/borrowck-break-uninit.stderr +++ b/src/test/ui/borrowck/borrowck-break-uninit.stderr @@ -1,8 +1,8 @@ -error[E0381]: borrow of possibly uninitialized variable: `x` +error[E0381]: borrow of possibly-uninitialized variable: `x` --> $DIR/borrowck-break-uninit.rs:9:20 | LL | println!("{}", x); - | ^ use of possibly uninitialized `x` + | ^ use of possibly-uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.rs b/src/test/ui/borrowck/borrowck-closures-mut-of-imm.rs index 24e06e3c4e666..d7e187a2b3958 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.rs +++ b/src/test/ui/borrowck/borrowck-closures-mut-of-imm.rs @@ -1,10 +1,6 @@ // Tests that two closures cannot simultaneously have mutable // and immutable access to the variable. Issue #6801. -fn get(x: &isize) -> isize { - *x -} - fn set(x: &mut isize) { *x = 4; } diff --git a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr b/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr index 3be7d725eda3a..784b903a5896a 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr +++ b/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr @@ -1,17 +1,17 @@ error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-closures-mut-of-imm.rs:13:25 + --> $DIR/borrowck-closures-mut-of-imm.rs:9:25 | LL | let mut c1 = || set(&mut *x); | ^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-closures-mut-of-imm.rs:15:25 + --> $DIR/borrowck-closures-mut-of-imm.rs:11:25 | LL | let mut c2 = || set(&mut *x); | ^^^^^^^ cannot borrow as mutable error[E0524]: two closures require unique access to `x` at the same time - --> $DIR/borrowck-closures-mut-of-imm.rs:15:18 + --> $DIR/borrowck-closures-mut-of-imm.rs:11:18 | LL | let mut c1 = || set(&mut *x); | -- - first borrow occurs due to use of `x` in closure @@ -28,4 +28,5 @@ LL | c2(); c1(); error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0524, E0596. +For more information about an error, try `rustc --explain E0524`. diff --git a/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr b/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr index a174388712158..471173e595f47 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr +++ b/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr @@ -15,3 +15,4 @@ LL | c2(); c1(); error: aborting due to previous error +For more information about this error, try `rustc --explain E0524`. diff --git a/src/test/ui/borrowck/borrowck-closures-unique.stderr b/src/test/ui/borrowck/borrowck-closures-unique.stderr index 9b53af4c01f59..2ed08b83c58b9 100644 --- a/src/test/ui/borrowck/borrowck-closures-unique.stderr +++ b/src/test/ui/borrowck/borrowck-closures-unique.stderr @@ -50,4 +50,5 @@ LL | let c1 = |y: &'static mut isize| x = y; error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0500`. +Some errors have detailed explanations: E0500, E0524. +For more information about an error, try `rustc --explain E0500`. diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.nll.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.nll.stderr deleted file mode 100644 index 20f05353d4633..0000000000000 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.nll.stderr +++ /dev/null @@ -1,366 +0,0 @@ -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-describe-lvalue.rs:262:13 - | -LL | let y = &mut x; - | ------ first mutable borrow occurs here -LL | &mut x; - | ^^^^^^ second mutable borrow occurs here -LL | *y = 1; - | ------ first borrow later used here - -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-describe-lvalue.rs:272:20 - | -LL | let y = &mut x; - | ------ first mutable borrow occurs here -LL | &mut x; - | ^^^^^^ second mutable borrow occurs here -LL | *y = 1; - | ------ first borrow later used here - -error: captured variable cannot escape `FnMut` closure body - --> $DIR/borrowck-describe-lvalue.rs:270:16 - | -LL | || { - | - inferred to be a `FnMut` closure -LL | / || { -LL | | let y = &mut x; -LL | | &mut x; -LL | | *y = 1; -LL | | drop(y); -LL | | } - | |_________________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body - | - = note: `FnMut` closures only have access to their captured variables while they are executing... - = note: ...therefore, they cannot allow references to captured variables to escape - -error[E0503]: cannot use `f.x` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:41:9 - | -LL | let x = f.x(); - | - borrow of `f` occurs here -LL | f.x; - | ^^^ use of borrowed `f` -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `g.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:48:9 - | -LL | let x = g.x(); - | - borrow of `g` occurs here -LL | g.0; - | ^^^ use of borrowed `g` -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `h.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:55:9 - | -LL | let x = &mut h.0; - | -------- borrow of `h.0` occurs here -LL | h.0; - | ^^^ use of borrowed `h.0` -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `e.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:63:20 - | -LL | let x = e.x(); - | - borrow of `e` occurs here -LL | match e { -LL | Baz::X(value) => value - | ^^^^^ use of borrowed `e` -LL | }; -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `u.a` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:71:9 - | -LL | let x = &mut u.a; - | -------- borrow of `u.a` occurs here -LL | u.a; - | ^^^ use of borrowed `u.a` -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `f.x` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:78:9 - | -LL | let x = f.x(); - | - borrow of `*f` occurs here -LL | f.x; - | ^^^ use of borrowed `*f` -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `g.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:85:9 - | -LL | let x = g.x(); - | - borrow of `*g` occurs here -LL | g.0; - | ^^^ use of borrowed `*g` -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `h.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:92:9 - | -LL | let x = &mut h.0; - | -------- borrow of `h.0` occurs here -LL | h.0; - | ^^^ use of borrowed `h.0` -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `e.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:100:20 - | -LL | let x = e.x(); - | - borrow of `*e` occurs here -LL | match *e { -LL | Baz::X(value) => value - | ^^^^^ use of borrowed `*e` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `u.a` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:109:9 - | -LL | let x = &mut u.a; - | -------- borrow of `u.a` occurs here -LL | u.a; - | ^^^ use of borrowed `u.a` -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:117:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | match v { -LL | &[x, _, .., _, _] => println!("{}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:122:18 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[_, x, .., _, _] => println!("{}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:127:25 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[_, _, .., x, _] => println!("{}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:132:28 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[_, _, .., _, x] => println!("{}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:143:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | match v { -LL | &[x @ ..] => println!("{:?}", x), - | ^^^^^^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:148:18 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[_, x @ ..] => println!("{:?}", x), - | ^^^^^^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:153:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[x @ .., _] => println!("{:?}", x), - | ^^^^^^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:158:18 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[_, x @ .., _] => println!("{:?}", x), - | ^^^^^^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `e` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:171:13 - | -LL | let x = &mut e; - | ------ borrow of `e` occurs here -LL | match e { -LL | E::A(ref ax) => - | ^^^^^^^^^^^^ use of borrowed `e` -... -LL | drop(x); - | - borrow later used here - -error[E0502]: cannot borrow `e.0` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:171:18 - | -LL | let x = &mut e; - | ------ mutable borrow occurs here -LL | match e { -LL | E::A(ref ax) => - | ^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0502]: cannot borrow `e.x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:175:23 - | -LL | let x = &mut e; - | ------ mutable borrow occurs here -... -LL | E::B { x: ref bx } => - | ^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0502]: cannot borrow `s.y.0` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:188:22 - | -LL | let x = &mut s; - | ------ mutable borrow occurs here -LL | match s { -LL | S { y: (ref y0, _), .. } => - | ^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0502]: cannot borrow `s.x.y` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:194:28 - | -LL | let x = &mut s; - | ------ mutable borrow occurs here -... -LL | S { x: F { y: ref x0, .. }, .. } => - | ^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0503]: cannot use `*v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:240:9 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | v[0].y; - | ^^^^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[_].y` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:240:9 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | v[0].y; - | ^^^^^^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0502]: cannot borrow `v[..].x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:251:24 - | -LL | let x = &mut v; - | ------ mutable borrow occurs here -LL | match v { -LL | &[_, F {x: ref xf, ..}] => println!("{}", xf), - | ^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:210:29 - | -LL | let x = &mut block; - | ---------- mutable borrow occurs here -LL | let p: &'a u8 = &*block.current; - | ^^^^^^^^^^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:227:33 - | -LL | let x = &mut block; - | ---------- mutable borrow occurs here -LL | let p : *const u8 = &*(*block).current; - | ^^^^^^^^^^^^^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0382]: use of moved value: `x` - --> $DIR/borrowck-describe-lvalue.rs:282:22 - | -LL | drop(x); - | - value moved here -LL | drop(x); - | ^ value used here after move - | - = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait - -error: aborting due to 32 previous errors - -Some errors have detailed explanations: E0382, E0499, E0502, E0503. -For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.rs b/src/test/ui/borrowck/borrowck-describe-lvalue.rs index c27d9519dc798..8425960aa8600 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.rs +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.rs @@ -208,10 +208,8 @@ fn main() { fn bump<'a>(mut block: &mut Block<'a>) { let x = &mut block; let p: &'a u8 = &*block.current; - //~^ WARNING cannot borrow `*block.current` as immutable because it is also borrowed as mutable - //~| this error has been downgraded - //~| this warning will become a hard error in the future - // Warning because of issue rust#38899 + //~^ ERROR cannot borrow `*block.current` as immutable because it is also borrowed as mutable + // See issue rust#38899 drop(x); } } @@ -225,10 +223,8 @@ fn main() { unsafe fn bump2(mut block: *mut Block2) { let x = &mut block; let p : *const u8 = &*(*block).current; - //~^ WARNING cannot borrow `*block.current` as immutable because it is also borrowed as mutable - //~| this error has been downgraded - //~| this warning will become a hard error in the future - // Warning because of issue rust#38899 + //~^ ERROR cannot borrow `*block.current` as immutable because it is also borrowed as mutable + // See issue rust#38899 drop(x); } } diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr index 38d847a90ff95..4213523d2fa4b 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-describe-lvalue.rs:262:13 + --> $DIR/borrowck-describe-lvalue.rs:258:13 | LL | let y = &mut x; | ------ first mutable borrow occurs here @@ -9,7 +9,7 @@ LL | *y = 1; | ------ first borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-describe-lvalue.rs:272:20 + --> $DIR/borrowck-describe-lvalue.rs:268:20 | LL | let y = &mut x; | ------ first mutable borrow occurs here @@ -19,7 +19,7 @@ LL | *y = 1; | ------ first borrow later used here error: captured variable cannot escape `FnMut` closure body - --> $DIR/borrowck-describe-lvalue.rs:270:16 + --> $DIR/borrowck-describe-lvalue.rs:266:16 | LL | || { | - inferred to be a `FnMut` closure @@ -295,7 +295,7 @@ LL | drop(x); | - mutable borrow later used here error[E0503]: cannot use `*v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:240:9 + --> $DIR/borrowck-describe-lvalue.rs:236:9 | LL | let x = &mut v; | ------ borrow of `v` occurs here @@ -306,7 +306,7 @@ LL | drop(x); | - borrow later used here error[E0503]: cannot use `v[_].y` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:240:9 + --> $DIR/borrowck-describe-lvalue.rs:236:9 | LL | let x = &mut v; | ------ borrow of `v` occurs here @@ -317,7 +317,7 @@ LL | drop(x); | - borrow later used here error[E0502]: cannot borrow `v[..].x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:251:24 + --> $DIR/borrowck-describe-lvalue.rs:247:24 | LL | let x = &mut v; | ------ mutable borrow occurs here @@ -328,7 +328,7 @@ LL | &[_, F {x: ref xf, ..}] => println!("{}", xf), LL | drop(x); | - mutable borrow later used here -warning[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable +error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable --> $DIR/borrowck-describe-lvalue.rs:210:29 | LL | let x = &mut block; @@ -338,13 +338,9 @@ LL | let p: &'a u8 = &*block.current; ... LL | drop(x); | - mutable borrow later used here - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future - = note: for more information, try `rustc --explain E0729` -warning[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:227:33 +error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:225:33 | LL | let x = &mut block; | ---------- mutable borrow occurs here @@ -353,13 +349,9 @@ LL | let p : *const u8 = &*(*block).current; ... LL | drop(x); | - mutable borrow later used here - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future - = note: for more information, try `rustc --explain E0729` error[E0382]: use of moved value: `x` - --> $DIR/borrowck-describe-lvalue.rs:282:22 + --> $DIR/borrowck-describe-lvalue.rs:278:22 | LL | drop(x); | - value moved here @@ -368,7 +360,7 @@ LL | drop(x); | = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait -error: aborting due to 30 previous errors +error: aborting due to 32 previous errors Some errors have detailed explanations: E0382, E0499, E0502, E0503. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-escaping-closure-error-2.polonius.stderr b/src/test/ui/borrowck/borrowck-escaping-closure-error-2.polonius.stderr deleted file mode 100644 index 89af8764557ff..0000000000000 --- a/src/test/ui/borrowck/borrowck-escaping-closure-error-2.polonius.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0597]: `books` does not live long enough - --> $DIR/borrowck-escaping-closure-error-2.rs:11:17 - | -LL | Box::new(|| books.push(4)) - | ------------^^^^^--------- - | | | | - | | | borrowed value does not live long enough - | | value captured here - | borrow later used here -LL | -LL | } - | - `books` dropped here while still borrowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/borrowck/borrowck-field-sensitivity.rs b/src/test/ui/borrowck/borrowck-field-sensitivity.rs index 88f74d1ed3300..ab607c2acbd4b 100644 --- a/src/test/ui/borrowck/borrowck-field-sensitivity.rs +++ b/src/test/ui/borrowck/borrowck-field-sensitivity.rs @@ -78,20 +78,20 @@ fn fu_move_after_fu_move() { fn copy_after_field_assign_after_uninit() { let mut x: A; - x.a = 1; //~ ERROR assign to part of possibly uninitialized variable: `x` + x.a = 1; //~ ERROR assign to part of possibly-uninitialized variable: `x` drop(x.a); } fn borrow_after_field_assign_after_uninit() { let mut x: A; - x.a = 1; //~ ERROR assign to part of possibly uninitialized variable: `x` + x.a = 1; //~ ERROR assign to part of possibly-uninitialized variable: `x` let p = &x.a; drop(*p); } fn move_after_field_assign_after_uninit() { let mut x: A; - x.b = box 1; //~ ERROR assign to part of possibly uninitialized variable: `x` + x.b = box 1; //~ ERROR assign to part of possibly-uninitialized variable: `x` drop(x.b); } diff --git a/src/test/ui/borrowck/borrowck-field-sensitivity.stderr b/src/test/ui/borrowck/borrowck-field-sensitivity.stderr index 89523235481ad..158b2e42f2ddf 100644 --- a/src/test/ui/borrowck/borrowck-field-sensitivity.stderr +++ b/src/test/ui/borrowck/borrowck-field-sensitivity.stderr @@ -108,23 +108,23 @@ LL | let _z = A { a: 4, .. x }; | = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait -error[E0381]: assign to part of possibly uninitialized variable: `x` +error[E0381]: assign to part of possibly-uninitialized variable: `x` --> $DIR/borrowck-field-sensitivity.rs:81:5 | LL | x.a = 1; - | ^^^^^^^ use of possibly uninitialized `x` + | ^^^^^^^ use of possibly-uninitialized `x` -error[E0381]: assign to part of possibly uninitialized variable: `x` +error[E0381]: assign to part of possibly-uninitialized variable: `x` --> $DIR/borrowck-field-sensitivity.rs:87:5 | LL | x.a = 1; - | ^^^^^^^ use of possibly uninitialized `x` + | ^^^^^^^ use of possibly-uninitialized `x` -error[E0381]: assign to part of possibly uninitialized variable: `x` +error[E0381]: assign to part of possibly-uninitialized variable: `x` --> $DIR/borrowck-field-sensitivity.rs:94:5 | LL | x.b = box 1; - | ^^^ use of possibly uninitialized `x` + | ^^^ use of possibly-uninitialized `x` error: aborting due to 14 previous errors diff --git a/src/test/ui/borrowck/borrowck-if-no-else.rs b/src/test/ui/borrowck/borrowck-if-no-else.rs index 044db99d54c1f..f59bcad6f61d7 100644 --- a/src/test/ui/borrowck/borrowck-if-no-else.rs +++ b/src/test/ui/borrowck/borrowck-if-no-else.rs @@ -2,5 +2,5 @@ fn foo(x: isize) { println!("{}", x); } fn main() { let x: isize; if 1 > 2 { x = 10; } - foo(x); //~ ERROR use of possibly uninitialized variable: `x` + foo(x); //~ ERROR use of possibly-uninitialized variable: `x` } diff --git a/src/test/ui/borrowck/borrowck-if-no-else.stderr b/src/test/ui/borrowck/borrowck-if-no-else.stderr index 1223e409d4df6..3e9d3d4f6d513 100644 --- a/src/test/ui/borrowck/borrowck-if-no-else.stderr +++ b/src/test/ui/borrowck/borrowck-if-no-else.stderr @@ -1,8 +1,8 @@ -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-if-no-else.rs:5:9 | LL | foo(x); - | ^ use of possibly uninitialized `x` + | ^ use of possibly-uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-if-with-else.rs b/src/test/ui/borrowck/borrowck-if-with-else.rs index f632d61a6c3c1..c13318b16c2fa 100644 --- a/src/test/ui/borrowck/borrowck-if-with-else.rs +++ b/src/test/ui/borrowck/borrowck-if-with-else.rs @@ -7,5 +7,5 @@ fn main() { } else { x = 10; } - foo(x); //~ ERROR use of possibly uninitialized variable: `x` + foo(x); //~ ERROR use of possibly-uninitialized variable: `x` } diff --git a/src/test/ui/borrowck/borrowck-if-with-else.stderr b/src/test/ui/borrowck/borrowck-if-with-else.stderr index d11f29b05f565..53b8a6bba2c76 100644 --- a/src/test/ui/borrowck/borrowck-if-with-else.stderr +++ b/src/test/ui/borrowck/borrowck-if-with-else.stderr @@ -1,8 +1,8 @@ -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-if-with-else.rs:10:9 | LL | foo(x); - | ^ use of possibly uninitialized `x` + | ^ use of possibly-uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.rs b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.rs index f7457781adc3e..9905e420f948d 100644 --- a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.rs +++ b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.rs @@ -1,7 +1,7 @@ fn main() { let j = || -> isize { let i: isize; - i //~ ERROR use of possibly uninitialized variable: `i` + i //~ ERROR use of possibly-uninitialized variable: `i` }; j(); } diff --git a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr index 82a602c6359c1..2d1d9bc8fa41d 100644 --- a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr +++ b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr @@ -1,8 +1,8 @@ -error[E0381]: use of possibly uninitialized variable: `i` +error[E0381]: use of possibly-uninitialized variable: `i` --> $DIR/borrowck-init-in-called-fn-expr.rs:4:9 | LL | i - | ^ use of possibly uninitialized `i` + | ^ use of possibly-uninitialized `i` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-init-in-fn-expr.rs b/src/test/ui/borrowck/borrowck-init-in-fn-expr.rs index 5055814625539..7dd3396c8c2cb 100644 --- a/src/test/ui/borrowck/borrowck-init-in-fn-expr.rs +++ b/src/test/ui/borrowck/borrowck-init-in-fn-expr.rs @@ -1,7 +1,7 @@ fn main() { let f = || -> isize { let i: isize; - i //~ ERROR use of possibly uninitialized variable: `i` + i //~ ERROR use of possibly-uninitialized variable: `i` }; println!("{}", f()); } diff --git a/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr b/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr index 899739378524c..fd8b90eda6032 100644 --- a/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr +++ b/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr @@ -1,8 +1,8 @@ -error[E0381]: use of possibly uninitialized variable: `i` +error[E0381]: use of possibly-uninitialized variable: `i` --> $DIR/borrowck-init-in-fn-expr.rs:4:9 | LL | i - | ^ use of possibly uninitialized `i` + | ^ use of possibly-uninitialized `i` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-init-in-fru.rs b/src/test/ui/borrowck/borrowck-init-in-fru.rs index 6da3098dc9336..d7ec2ed75c85c 100644 --- a/src/test/ui/borrowck/borrowck-init-in-fru.rs +++ b/src/test/ui/borrowck/borrowck-init-in-fru.rs @@ -7,6 +7,6 @@ struct Point { fn main() { let mut origin: Point; origin = Point { x: 10, ..origin }; - //~^ ERROR use of possibly uninitialized variable: `origin` [E0381] + //~^ ERROR use of possibly-uninitialized variable: `origin` [E0381] origin.clone(); } diff --git a/src/test/ui/borrowck/borrowck-init-in-fru.stderr b/src/test/ui/borrowck/borrowck-init-in-fru.stderr index fe55bc2fd95c0..a4c042d1c125f 100644 --- a/src/test/ui/borrowck/borrowck-init-in-fru.stderr +++ b/src/test/ui/borrowck/borrowck-init-in-fru.stderr @@ -1,8 +1,8 @@ -error[E0381]: use of possibly uninitialized variable: `origin` +error[E0381]: use of possibly-uninitialized variable: `origin` --> $DIR/borrowck-init-in-fru.rs:9:5 | LL | origin = Point { x: 10, ..origin }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly uninitialized `origin.y` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `origin.y` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-init-op-equal.rs b/src/test/ui/borrowck/borrowck-init-op-equal.rs index d3fa852ac91ba..784eb8cf85b8a 100644 --- a/src/test/ui/borrowck/borrowck-init-op-equal.rs +++ b/src/test/ui/borrowck/borrowck-init-op-equal.rs @@ -1,6 +1,6 @@ fn test() { let v: isize; - v += 1; //~ ERROR use of possibly uninitialized variable: `v` + v += 1; //~ ERROR use of possibly-uninitialized variable: `v` v.clone(); } diff --git a/src/test/ui/borrowck/borrowck-init-op-equal.stderr b/src/test/ui/borrowck/borrowck-init-op-equal.stderr index 9863ceb14240f..6c88778ae0e5a 100644 --- a/src/test/ui/borrowck/borrowck-init-op-equal.stderr +++ b/src/test/ui/borrowck/borrowck-init-op-equal.stderr @@ -1,8 +1,8 @@ -error[E0381]: use of possibly uninitialized variable: `v` +error[E0381]: use of possibly-uninitialized variable: `v` --> $DIR/borrowck-init-op-equal.rs:3:5 | LL | v += 1; - | ^^^^^^ use of possibly uninitialized `v` + | ^^^^^^ use of possibly-uninitialized `v` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-init-plus-equal.rs b/src/test/ui/borrowck/borrowck-init-plus-equal.rs index d895a2e16b537..d9d20a2a9c148 100644 --- a/src/test/ui/borrowck/borrowck-init-plus-equal.rs +++ b/src/test/ui/borrowck/borrowck-init-plus-equal.rs @@ -1,6 +1,6 @@ fn test() { let mut v: isize; - v = v + 1; //~ ERROR use of possibly uninitialized variable: `v` + v = v + 1; //~ ERROR use of possibly-uninitialized variable: `v` v.clone(); } diff --git a/src/test/ui/borrowck/borrowck-init-plus-equal.stderr b/src/test/ui/borrowck/borrowck-init-plus-equal.stderr index 80c4e0c80483d..fe09c8581df0e 100644 --- a/src/test/ui/borrowck/borrowck-init-plus-equal.stderr +++ b/src/test/ui/borrowck/borrowck-init-plus-equal.stderr @@ -1,8 +1,8 @@ -error[E0381]: use of possibly uninitialized variable: `v` +error[E0381]: use of possibly-uninitialized variable: `v` --> $DIR/borrowck-init-plus-equal.rs:3:9 | LL | v = v + 1; - | ^ use of possibly uninitialized `v` + | ^ use of possibly-uninitialized `v` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-migrate-to-nll.edition.stderr b/src/test/ui/borrowck/borrowck-migrate-to-nll.edition.stderr deleted file mode 100644 index a33a1d00a5786..0000000000000 --- a/src/test/ui/borrowck/borrowck-migrate-to-nll.edition.stderr +++ /dev/null @@ -1,15 +0,0 @@ -warning[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-migrate-to-nll.rs:28:21 - | -LL | let x = &mut block; - | ---------- mutable borrow occurs here -LL | let p: &'a u8 = &*block.current; - | ^^^^^^^^^^^^^^^ immutable borrow occurs here -LL | // (use `x` and `p` so enabling NLL doesn't assign overly short lifetimes) -LL | drop(x); - | - mutable borrow later used here - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future - = note: for more information, try `rustc --explain E0729` - diff --git a/src/test/ui/borrowck/borrowck-migrate-to-nll.rs b/src/test/ui/borrowck/borrowck-migrate-to-nll.rs deleted file mode 100644 index 6dda317e57efe..0000000000000 --- a/src/test/ui/borrowck/borrowck-migrate-to-nll.rs +++ /dev/null @@ -1,34 +0,0 @@ -// This is a test of the borrowck migrate mode. It leverages #38899, a -// bug that is fixed by NLL: this code is (unsoundly) accepted by -// AST-borrowck, but is correctly rejected by the NLL borrowck. -// -// Therefore, for backwards-compatiblity, under borrowck=migrate the -// NLL checks will be emitted as *warnings*. - -// NLL mode makes this compile-fail; we cannot currently encode a -// test that is run-pass or compile-fail based on compare-mode. So -// just ignore it instead: - -// ignore-compare-mode-nll -// ignore-compare-mode-polonius - -// revisions: zflag edition -//[zflag]compile-flags: -Z borrowck=migrate -//[edition]edition:2018 -//[zflag] run-pass -//[edition] run-pass - -pub struct Block<'a> { - current: &'a u8, - unrelated: &'a u8, -} - -fn bump<'a>(mut block: &mut Block<'a>) { - let x = &mut block; - let p: &'a u8 = &*block.current; - // (use `x` and `p` so enabling NLL doesn't assign overly short lifetimes) - drop(x); - drop(p); -} - -fn main() {} diff --git a/src/test/ui/borrowck/borrowck-migrate-to-nll.zflag.stderr b/src/test/ui/borrowck/borrowck-migrate-to-nll.zflag.stderr deleted file mode 100644 index a33a1d00a5786..0000000000000 --- a/src/test/ui/borrowck/borrowck-migrate-to-nll.zflag.stderr +++ /dev/null @@ -1,15 +0,0 @@ -warning[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-migrate-to-nll.rs:28:21 - | -LL | let x = &mut block; - | ---------- mutable borrow occurs here -LL | let p: &'a u8 = &*block.current; - | ^^^^^^^^^^^^^^^ immutable borrow occurs here -LL | // (use `x` and `p` so enabling NLL doesn't assign overly short lifetimes) -LL | drop(x); - | - mutable borrow later used here - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future - = note: for more information, try `rustc --explain E0729` - diff --git a/src/test/ui/borrowck/borrowck-mutate-in-guard.rs b/src/test/ui/borrowck/borrowck-mutate-in-guard.rs index 5b6aa7a979be5..9cbceeb945ccc 100644 --- a/src/test/ui/borrowck/borrowck-mutate-in-guard.rs +++ b/src/test/ui/borrowck/borrowck-mutate-in-guard.rs @@ -8,12 +8,9 @@ fn foo() -> isize { let mut x = Enum::A(&mut n); match x { Enum::A(_) if { x = Enum::B(false); false } => 1, - //~^ ERROR cannot assign in a pattern guard - //~| ERROR cannot assign `x` in match guard + //~^ ERROR cannot assign `x` in match guard Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, - //~^ ERROR cannot mutably borrow in a pattern guard - //~| ERROR cannot assign in a pattern guard - //~| ERROR cannot mutably borrow `x` in match guard + //~^ ERROR cannot mutably borrow `x` in match guard Enum::A(p) => *p, Enum::B(_) => 2, } diff --git a/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr b/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr index 674f137dbb043..6d05e97252d92 100644 --- a/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr +++ b/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr @@ -1,23 +1,3 @@ -error[E0302]: cannot assign in a pattern guard - --> $DIR/borrowck-mutate-in-guard.rs:10:25 - | -LL | Enum::A(_) if { x = Enum::B(false); false } => 1, - | ^^^^^^^^^^^^^^^^^^ assignment in pattern guard - -error[E0301]: cannot mutably borrow in a pattern guard - --> $DIR/borrowck-mutate-in-guard.rs:13:38 - | -LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, - | ^ borrowed mutably in pattern guard - | - = help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable - -error[E0302]: cannot assign in a pattern guard - --> $DIR/borrowck-mutate-in-guard.rs:13:41 - | -LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, - | ^^^^^^^^^^^^^^^^^^^ assignment in pattern guard - error[E0510]: cannot assign `x` in match guard --> $DIR/borrowck-mutate-in-guard.rs:10:25 | @@ -27,7 +7,7 @@ LL | Enum::A(_) if { x = Enum::B(false); false } => 1, | ^^^^^^^^^^^^^^^^^^ cannot assign error[E0510]: cannot mutably borrow `x` in match guard - --> $DIR/borrowck-mutate-in-guard.rs:13:33 + --> $DIR/borrowck-mutate-in-guard.rs:12:33 | LL | match x { | - value is immutable in match guard @@ -35,7 +15,6 @@ LL | match x { LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, | ^^^^^^ cannot mutably borrow -error: aborting due to 5 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0301, E0302, E0510. -For more information about an error, try `rustc --explain E0301`. +For more information about this error, try `rustc --explain E0510`. diff --git a/src/test/ui/borrowck/borrowck-or-init.rs b/src/test/ui/borrowck/borrowck-or-init.rs index c0d6c9c2739b2..81b0b80bf11b5 100644 --- a/src/test/ui/borrowck/borrowck-or-init.rs +++ b/src/test/ui/borrowck/borrowck-or-init.rs @@ -2,5 +2,5 @@ fn main() { let i: isize; println!("{}", false || { i = 5; true }); - println!("{}", i); //~ ERROR borrow of possibly uninitialized variable: `i` + println!("{}", i); //~ ERROR borrow of possibly-uninitialized variable: `i` } diff --git a/src/test/ui/borrowck/borrowck-or-init.stderr b/src/test/ui/borrowck/borrowck-or-init.stderr index 122f5192720cc..3fe8d9eededc5 100644 --- a/src/test/ui/borrowck/borrowck-or-init.stderr +++ b/src/test/ui/borrowck/borrowck-or-init.stderr @@ -1,8 +1,8 @@ -error[E0381]: borrow of possibly uninitialized variable: `i` +error[E0381]: borrow of possibly-uninitialized variable: `i` --> $DIR/borrowck-or-init.rs:5:20 | LL | println!("{}", i); - | ^ use of possibly uninitialized `i` + | ^ use of possibly-uninitialized `i` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-4.rs b/src/test/ui/borrowck/borrowck-partial-reinit-4.rs index 0fb955d201d03..5e5a8cdf4232b 100644 --- a/src/test/ui/borrowck/borrowck-partial-reinit-4.rs +++ b/src/test/ui/borrowck/borrowck-partial-reinit-4.rs @@ -15,7 +15,7 @@ impl Drop for Test2 { fn stuff() { let mut x : (Test2, Test2); (x.0).0 = Some(Test); - //~^ ERROR assign of possibly uninitialized variable: `x.0` + //~^ ERROR assign of possibly-uninitialized variable: `x.0` } fn main() { diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-4.stderr b/src/test/ui/borrowck/borrowck-partial-reinit-4.stderr index f0a9a7dd5e243..218c4f2de5bc7 100644 --- a/src/test/ui/borrowck/borrowck-partial-reinit-4.stderr +++ b/src/test/ui/borrowck/borrowck-partial-reinit-4.stderr @@ -1,8 +1,8 @@ -error[E0381]: assign of possibly uninitialized variable: `x.0` +error[E0381]: assign of possibly-uninitialized variable: `x.0` --> $DIR/borrowck-partial-reinit-4.rs:17:5 | LL | (x.0).0 = Some(Test); - | ^^^^^^^ use of possibly uninitialized `x.0` + | ^^^^^^^ use of possibly-uninitialized `x.0` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-return.rs b/src/test/ui/borrowck/borrowck-return.rs index e5bee2ca4bfeb..8c623356f6c6b 100644 --- a/src/test/ui/borrowck/borrowck-return.rs +++ b/src/test/ui/borrowck/borrowck-return.rs @@ -1,6 +1,6 @@ fn f() -> isize { let x: isize; - return x; //~ ERROR use of possibly uninitialized variable: `x` + return x; //~ ERROR use of possibly-uninitialized variable: `x` } fn main() { f(); } diff --git a/src/test/ui/borrowck/borrowck-return.stderr b/src/test/ui/borrowck/borrowck-return.stderr index a2b65af5dbfcd..bc74e8e343848 100644 --- a/src/test/ui/borrowck/borrowck-return.stderr +++ b/src/test/ui/borrowck/borrowck-return.stderr @@ -1,8 +1,8 @@ -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-return.rs:3:12 | LL | return x; - | ^ use of possibly uninitialized `x` + | ^ use of possibly-uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-storage-dead.stderr b/src/test/ui/borrowck/borrowck-storage-dead.stderr index 5b9f49c2e7c92..8e4932142f0db 100644 --- a/src/test/ui/borrowck/borrowck-storage-dead.stderr +++ b/src/test/ui/borrowck/borrowck-storage-dead.stderr @@ -1,8 +1,8 @@ -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-storage-dead.rs:16:17 | LL | let _ = x + 1; - | ^ use of possibly uninitialized `x` + | ^ use of possibly-uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-uninit-after-item.rs b/src/test/ui/borrowck/borrowck-uninit-after-item.rs index 83f3752a1a850..e9a389657c8fd 100644 --- a/src/test/ui/borrowck/borrowck-uninit-after-item.rs +++ b/src/test/ui/borrowck/borrowck-uninit-after-item.rs @@ -1,5 +1,5 @@ fn main() { let bar; fn baz(_x: isize) { } - baz(bar); //~ ERROR use of possibly uninitialized variable: `bar` + baz(bar); //~ ERROR use of possibly-uninitialized variable: `bar` } diff --git a/src/test/ui/borrowck/borrowck-uninit-after-item.stderr b/src/test/ui/borrowck/borrowck-uninit-after-item.stderr index 2d0b21dd0d6fb..f7f069b81be02 100644 --- a/src/test/ui/borrowck/borrowck-uninit-after-item.stderr +++ b/src/test/ui/borrowck/borrowck-uninit-after-item.stderr @@ -1,8 +1,8 @@ -error[E0381]: use of possibly uninitialized variable: `bar` +error[E0381]: use of possibly-uninitialized variable: `bar` --> $DIR/borrowck-uninit-after-item.rs:4:9 | LL | baz(bar); - | ^^^ use of possibly uninitialized `bar` + | ^^^ use of possibly-uninitialized `bar` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-uninit-field-access.stderr b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr index aa214f9c2f590..9f35a4a8d83bd 100644 --- a/src/test/ui/borrowck/borrowck-uninit-field-access.stderr +++ b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr @@ -1,8 +1,8 @@ -error[E0381]: use of possibly uninitialized variable: `a` +error[E0381]: use of possibly-uninitialized variable: `a` --> $DIR/borrowck-uninit-field-access.rs:21:13 | LL | let _ = a.x + 1; - | ^^^ use of possibly uninitialized `a.x` + | ^^^ use of possibly-uninitialized `a.x` error[E0382]: use of moved value: `line1.origin` --> $DIR/borrowck-uninit-field-access.rs:25:13 diff --git a/src/test/ui/borrowck/borrowck-uninit-in-assignop.rs b/src/test/ui/borrowck/borrowck-uninit-in-assignop.rs index bfb0dd4301dd1..20350d61d5bb6 100644 --- a/src/test/ui/borrowck/borrowck-uninit-in-assignop.rs +++ b/src/test/ui/borrowck/borrowck-uninit-in-assignop.rs @@ -3,32 +3,32 @@ pub fn main() { let x: isize; - x += 1; //~ ERROR use of possibly uninitialized variable: `x` + x += 1; //~ ERROR use of possibly-uninitialized variable: `x` let x: isize; - x -= 1; //~ ERROR use of possibly uninitialized variable: `x` + x -= 1; //~ ERROR use of possibly-uninitialized variable: `x` let x: isize; - x *= 1; //~ ERROR use of possibly uninitialized variable: `x` + x *= 1; //~ ERROR use of possibly-uninitialized variable: `x` let x: isize; - x /= 1; //~ ERROR use of possibly uninitialized variable: `x` + x /= 1; //~ ERROR use of possibly-uninitialized variable: `x` let x: isize; - x %= 1; //~ ERROR use of possibly uninitialized variable: `x` + x %= 1; //~ ERROR use of possibly-uninitialized variable: `x` let x: isize; - x ^= 1; //~ ERROR use of possibly uninitialized variable: `x` + x ^= 1; //~ ERROR use of possibly-uninitialized variable: `x` let x: isize; - x &= 1; //~ ERROR use of possibly uninitialized variable: `x` + x &= 1; //~ ERROR use of possibly-uninitialized variable: `x` let x: isize; - x |= 1; //~ ERROR use of possibly uninitialized variable: `x` + x |= 1; //~ ERROR use of possibly-uninitialized variable: `x` let x: isize; - x <<= 1; //~ ERROR use of possibly uninitialized variable: `x` + x <<= 1; //~ ERROR use of possibly-uninitialized variable: `x` let x: isize; - x >>= 1; //~ ERROR use of possibly uninitialized variable: `x` + x >>= 1; //~ ERROR use of possibly-uninitialized variable: `x` } diff --git a/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr b/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr index 163395e42d252..f2036df3ce92a 100644 --- a/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr +++ b/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr @@ -1,62 +1,62 @@ -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:6:5 | LL | x += 1; - | ^^^^^^ use of possibly uninitialized `x` + | ^^^^^^ use of possibly-uninitialized `x` -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:9:5 | LL | x -= 1; - | ^^^^^^ use of possibly uninitialized `x` + | ^^^^^^ use of possibly-uninitialized `x` -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:12:5 | LL | x *= 1; - | ^^^^^^ use of possibly uninitialized `x` + | ^^^^^^ use of possibly-uninitialized `x` -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:15:5 | LL | x /= 1; - | ^^^^^^ use of possibly uninitialized `x` + | ^^^^^^ use of possibly-uninitialized `x` -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:18:5 | LL | x %= 1; - | ^^^^^^ use of possibly uninitialized `x` + | ^^^^^^ use of possibly-uninitialized `x` -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:21:5 | LL | x ^= 1; - | ^^^^^^ use of possibly uninitialized `x` + | ^^^^^^ use of possibly-uninitialized `x` -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:24:5 | LL | x &= 1; - | ^^^^^^ use of possibly uninitialized `x` + | ^^^^^^ use of possibly-uninitialized `x` -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:27:5 | LL | x |= 1; - | ^^^^^^ use of possibly uninitialized `x` + | ^^^^^^ use of possibly-uninitialized `x` -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:30:5 | LL | x <<= 1; - | ^^^^^^^ use of possibly uninitialized `x` + | ^^^^^^^ use of possibly-uninitialized `x` -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:33:5 | LL | x >>= 1; - | ^^^^^^^ use of possibly uninitialized `x` + | ^^^^^^^ use of possibly-uninitialized `x` error: aborting due to 10 previous errors diff --git a/src/test/ui/borrowck/borrowck-uninit-ref-chain.rs b/src/test/ui/borrowck/borrowck-uninit-ref-chain.rs index fa9148f984077..0ccea49f329bb 100644 --- a/src/test/ui/borrowck/borrowck-uninit-ref-chain.rs +++ b/src/test/ui/borrowck/borrowck-uninit-ref-chain.rs @@ -15,19 +15,19 @@ fn main() { let mut a: S; - a.x = 0; //~ ERROR assign to part of possibly uninitialized variable: `a` [E0381] + a.x = 0; //~ ERROR assign to part of possibly-uninitialized variable: `a` [E0381] let _b = &a.x; let mut a: S<&&i32, &&i32>; - a.x = &&0; //~ ERROR assign to part of possibly uninitialized variable: `a` [E0381] + a.x = &&0; //~ ERROR assign to part of possibly-uninitialized variable: `a` [E0381] let _b = &**a.x; let mut a: S; - a.x = 0; //~ ERROR assign to part of possibly uninitialized variable: `a` [E0381] + a.x = 0; //~ ERROR assign to part of possibly-uninitialized variable: `a` [E0381] let _b = &a.y; let mut a: S<&&i32, &&i32>; - a.x = &&0; //~ assign to part of possibly uninitialized variable: `a` [E0381] + a.x = &&0; //~ assign to part of possibly-uninitialized variable: `a` [E0381] let _b = &**a.y; } diff --git a/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr b/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr index d87621f04d653..d99a50df75b8c 100644 --- a/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr +++ b/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr @@ -1,44 +1,44 @@ -error[E0381]: borrow of possibly uninitialized variable: `x` +error[E0381]: borrow of possibly-uninitialized variable: `x` --> $DIR/borrowck-uninit-ref-chain.rs:8:14 | LL | let _y = &**x; - | ^^^^ use of possibly uninitialized `**x` + | ^^^^ use of possibly-uninitialized `**x` -error[E0381]: borrow of possibly uninitialized variable: `x` +error[E0381]: borrow of possibly-uninitialized variable: `x` --> $DIR/borrowck-uninit-ref-chain.rs:11:14 | LL | let _y = &**x; - | ^^^^ use of possibly uninitialized `**x` + | ^^^^ use of possibly-uninitialized `**x` -error[E0381]: borrow of possibly uninitialized variable: `x` +error[E0381]: borrow of possibly-uninitialized variable: `x` --> $DIR/borrowck-uninit-ref-chain.rs:14:14 | LL | let _y = &**x; - | ^^^^ use of possibly uninitialized `**x` + | ^^^^ use of possibly-uninitialized `**x` -error[E0381]: assign to part of possibly uninitialized variable: `a` +error[E0381]: assign to part of possibly-uninitialized variable: `a` --> $DIR/borrowck-uninit-ref-chain.rs:18:5 | LL | a.x = 0; - | ^^^^^^^ use of possibly uninitialized `a` + | ^^^^^^^ use of possibly-uninitialized `a` -error[E0381]: assign to part of possibly uninitialized variable: `a` +error[E0381]: assign to part of possibly-uninitialized variable: `a` --> $DIR/borrowck-uninit-ref-chain.rs:22:5 | LL | a.x = &&0; - | ^^^^^^^^^ use of possibly uninitialized `a` + | ^^^^^^^^^ use of possibly-uninitialized `a` -error[E0381]: assign to part of possibly uninitialized variable: `a` +error[E0381]: assign to part of possibly-uninitialized variable: `a` --> $DIR/borrowck-uninit-ref-chain.rs:27:5 | LL | a.x = 0; - | ^^^^^^^ use of possibly uninitialized `a` + | ^^^^^^^ use of possibly-uninitialized `a` -error[E0381]: assign to part of possibly uninitialized variable: `a` +error[E0381]: assign to part of possibly-uninitialized variable: `a` --> $DIR/borrowck-uninit-ref-chain.rs:31:5 | LL | a.x = &&0; - | ^^^^^^^^^ use of possibly uninitialized `a` + | ^^^^^^^^^ use of possibly-uninitialized `a` error: aborting due to 7 previous errors diff --git a/src/test/ui/borrowck/borrowck-uninit.rs b/src/test/ui/borrowck/borrowck-uninit.rs index 71c1f596fa21b..017b955a39535 100644 --- a/src/test/ui/borrowck/borrowck-uninit.rs +++ b/src/test/ui/borrowck/borrowck-uninit.rs @@ -2,5 +2,5 @@ fn foo(x: isize) { println!("{}", x); } fn main() { let x: isize; - foo(x); //~ ERROR use of possibly uninitialized variable: `x` + foo(x); //~ ERROR use of possibly-uninitialized variable: `x` } diff --git a/src/test/ui/borrowck/borrowck-uninit.stderr b/src/test/ui/borrowck/borrowck-uninit.stderr index 5db9c1b250cc2..effc209e81659 100644 --- a/src/test/ui/borrowck/borrowck-uninit.stderr +++ b/src/test/ui/borrowck/borrowck-uninit.stderr @@ -1,8 +1,8 @@ -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-uninit.rs:5:9 | LL | foo(x); - | ^ use of possibly uninitialized `x` + | ^ use of possibly-uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-union-uninitialized.rs b/src/test/ui/borrowck/borrowck-union-uninitialized.rs index 9cab0b19202a0..3cc71e7cece0e 100644 --- a/src/test/ui/borrowck/borrowck-union-uninitialized.rs +++ b/src/test/ui/borrowck/borrowck-union-uninitialized.rs @@ -10,8 +10,8 @@ fn main() { unsafe { let mut s: S; let mut u: U; - s.a = 0; //~ ERROR assign to part of possibly uninitialized variable: `s` - u.a = 0; //~ ERROR assign to part of possibly uninitialized variable: `u` + s.a = 0; //~ ERROR assign to part of possibly-uninitialized variable: `s` + u.a = 0; //~ ERROR assign to part of possibly-uninitialized variable: `u` let sa = s.a; let ua = u.a; } diff --git a/src/test/ui/borrowck/borrowck-union-uninitialized.stderr b/src/test/ui/borrowck/borrowck-union-uninitialized.stderr index 06c884e244667..bd9ec5e579ca9 100644 --- a/src/test/ui/borrowck/borrowck-union-uninitialized.stderr +++ b/src/test/ui/borrowck/borrowck-union-uninitialized.stderr @@ -1,14 +1,14 @@ -error[E0381]: assign to part of possibly uninitialized variable: `s` +error[E0381]: assign to part of possibly-uninitialized variable: `s` --> $DIR/borrowck-union-uninitialized.rs:13:9 | LL | s.a = 0; - | ^^^^^^^ use of possibly uninitialized `s` + | ^^^^^^^ use of possibly-uninitialized `s` -error[E0381]: assign to part of possibly uninitialized variable: `u` +error[E0381]: assign to part of possibly-uninitialized variable: `u` --> $DIR/borrowck-union-uninitialized.rs:14:9 | LL | u.a = 0; - | ^^^^^^^ use of possibly uninitialized `u` + | ^^^^^^^ use of possibly-uninitialized `u` error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr b/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr index c03ef759f570a..d1b396aba8257 100644 --- a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr +++ b/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr @@ -1,14 +1,14 @@ -error[E0381]: use of possibly uninitialized variable: `w` +error[E0381]: use of possibly-uninitialized variable: `w` --> $DIR/borrowck-use-in-index-lvalue.rs:3:5 | LL | w[5] = 0; - | ^^^^ use of possibly uninitialized `*w` + | ^^^^ use of possibly-uninitialized `*w` -error[E0381]: use of possibly uninitialized variable: `w` +error[E0381]: use of possibly-uninitialized variable: `w` --> $DIR/borrowck-use-in-index-lvalue.rs:6:5 | LL | w[5] = 0; - | ^^^^ use of possibly uninitialized `*w` + | ^^^^ use of possibly-uninitialized `*w` error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr index 2b80140c6b376..ca5227c98c862 100644 --- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr +++ b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr @@ -1,8 +1,8 @@ -error[E0381]: borrow of possibly uninitialized variable: `x` +error[E0381]: borrow of possibly-uninitialized variable: `x` --> $DIR/borrowck-use-uninitialized-in-cast-trait.rs:9:13 | LL | let y = x as *const dyn Foo; - | ^ use of possibly uninitialized `*x` + | ^ use of possibly-uninitialized `*x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr index 84e717a4639cd..24897a0f2dc9c 100644 --- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr +++ b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr @@ -1,8 +1,8 @@ -error[E0381]: borrow of possibly uninitialized variable: `x` +error[E0381]: borrow of possibly-uninitialized variable: `x` --> $DIR/borrowck-use-uninitialized-in-cast.rs:7:13 | LL | let y = x as *const i32; - | ^ use of possibly uninitialized `*x` + | ^ use of possibly-uninitialized `*x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-while-break.rs b/src/test/ui/borrowck/borrowck-while-break.rs index e16bc58656d81..48e4221470221 100644 --- a/src/test/ui/borrowck/borrowck-while-break.rs +++ b/src/test/ui/borrowck/borrowck-while-break.rs @@ -4,7 +4,7 @@ fn test(cond: bool) { v = 3; break; } - println!("{}", v); //~ ERROR borrow of possibly uninitialized variable: `v` + println!("{}", v); //~ ERROR borrow of possibly-uninitialized variable: `v` } fn main() { diff --git a/src/test/ui/borrowck/borrowck-while-break.stderr b/src/test/ui/borrowck/borrowck-while-break.stderr index 0fe3cdc96a874..3eaaf8d7df08d 100644 --- a/src/test/ui/borrowck/borrowck-while-break.stderr +++ b/src/test/ui/borrowck/borrowck-while-break.stderr @@ -1,8 +1,8 @@ -error[E0381]: borrow of possibly uninitialized variable: `v` +error[E0381]: borrow of possibly-uninitialized variable: `v` --> $DIR/borrowck-while-break.rs:7:20 | LL | println!("{}", v); - | ^ use of possibly uninitialized `v` + | ^ use of possibly-uninitialized `v` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-while-cond.rs b/src/test/ui/borrowck/borrowck-while-cond.rs index 28a5fb18a7f1d..b3ec20711c12b 100644 --- a/src/test/ui/borrowck/borrowck-while-cond.rs +++ b/src/test/ui/borrowck/borrowck-while-cond.rs @@ -1,4 +1,4 @@ fn main() { let x: bool; - while x { } //~ ERROR use of possibly uninitialized variable: `x` + while x { } //~ ERROR use of possibly-uninitialized variable: `x` } diff --git a/src/test/ui/borrowck/borrowck-while-cond.stderr b/src/test/ui/borrowck/borrowck-while-cond.stderr index 06deae345ab60..92937a9c5730e 100644 --- a/src/test/ui/borrowck/borrowck-while-cond.stderr +++ b/src/test/ui/borrowck/borrowck-while-cond.stderr @@ -1,8 +1,8 @@ -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-while-cond.rs:3:11 | LL | while x { } - | ^ use of possibly uninitialized `x` + | ^ use of possibly-uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-while.rs b/src/test/ui/borrowck/borrowck-while.rs index 4274fa997a0ab..6b3220c7d8591 100644 --- a/src/test/ui/borrowck/borrowck-while.rs +++ b/src/test/ui/borrowck/borrowck-while.rs @@ -1,7 +1,7 @@ fn f() -> isize { let mut x: isize; while 1 == 1 { x = 10; } - return x; //~ ERROR use of possibly uninitialized variable: `x` + return x; //~ ERROR use of possibly-uninitialized variable: `x` } fn main() { f(); } diff --git a/src/test/ui/borrowck/borrowck-while.stderr b/src/test/ui/borrowck/borrowck-while.stderr index 60622d648dd23..a1f8f64725dcd 100644 --- a/src/test/ui/borrowck/borrowck-while.stderr +++ b/src/test/ui/borrowck/borrowck-while.stderr @@ -1,8 +1,8 @@ -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/borrowck-while.rs:4:12 | LL | return x; - | ^ use of possibly uninitialized `x` + | ^ use of possibly-uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/disallow-possibly-uninitialized.rs b/src/test/ui/borrowck/disallow-possibly-uninitialized.rs index a987c00b09191..7043cb3a164e7 100644 --- a/src/test/ui/borrowck/disallow-possibly-uninitialized.rs +++ b/src/test/ui/borrowck/disallow-possibly-uninitialized.rs @@ -4,19 +4,19 @@ fn main() { let mut t: (u64, u64); t.0 = 1; - //~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381] + //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] t.1 = 1; let mut t: (u64, u64); t.1 = 1; - //~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381] + //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] t.0 = 1; let mut t: (u64, u64); t.0 = 1; - //~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381] + //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] let mut t: (u64,); t.0 = 1; - //~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381] + //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] } diff --git a/src/test/ui/borrowck/disallow-possibly-uninitialized.stderr b/src/test/ui/borrowck/disallow-possibly-uninitialized.stderr index a32b17b165934..8d5b39341c109 100644 --- a/src/test/ui/borrowck/disallow-possibly-uninitialized.stderr +++ b/src/test/ui/borrowck/disallow-possibly-uninitialized.stderr @@ -1,26 +1,26 @@ -error[E0381]: assign to part of possibly uninitialized variable: `t` +error[E0381]: assign to part of possibly-uninitialized variable: `t` --> $DIR/disallow-possibly-uninitialized.rs:6:5 | LL | t.0 = 1; - | ^^^^^^^ use of possibly uninitialized `t` + | ^^^^^^^ use of possibly-uninitialized `t` -error[E0381]: assign to part of possibly uninitialized variable: `t` +error[E0381]: assign to part of possibly-uninitialized variable: `t` --> $DIR/disallow-possibly-uninitialized.rs:11:5 | LL | t.1 = 1; - | ^^^^^^^ use of possibly uninitialized `t` + | ^^^^^^^ use of possibly-uninitialized `t` -error[E0381]: assign to part of possibly uninitialized variable: `t` +error[E0381]: assign to part of possibly-uninitialized variable: `t` --> $DIR/disallow-possibly-uninitialized.rs:16:5 | LL | t.0 = 1; - | ^^^^^^^ use of possibly uninitialized `t` + | ^^^^^^^ use of possibly-uninitialized `t` -error[E0381]: assign to part of possibly uninitialized variable: `t` +error[E0381]: assign to part of possibly-uninitialized variable: `t` --> $DIR/disallow-possibly-uninitialized.rs:20:5 | LL | t.0 = 1; - | ^^^^^^^ use of possibly uninitialized `t` + | ^^^^^^^ use of possibly-uninitialized `t` error: aborting due to 4 previous errors diff --git a/src/test/ui/borrowck/issue-10876.rs b/src/test/ui/borrowck/issue-10876.rs index 20ab905fec46e..22eaa119f2467 100644 --- a/src/test/ui/borrowck/issue-10876.rs +++ b/src/test/ui/borrowck/issue-10876.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass enum Nat { S(Box), diff --git a/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.rs b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.rs new file mode 100644 index 0000000000000..f1fd1b507c71e --- /dev/null +++ b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.rs @@ -0,0 +1,7 @@ +fn main() { + let f = move || {}; + let _action = move || { + || f() // The `nested` closure + //~^ ERROR lifetime may not live long enough + }; +} diff --git a/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr new file mode 100644 index 0000000000000..3781691ff41dc --- /dev/null +++ b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9 + | +LL | let _action = move || { + | ------- + | | | + | | return type of closure is [closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9: 4:15 f:&'2 [closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:2:13: 2:23]] + | lifetime `'1` represents this closure's body +LL | || f() // The `nested` closure + | ^^^^^^ returning this value requires that `'1` must outlive `'2` + | + = note: closure implements `Fn`, so references to captured variables can't escape the closure + +error: aborting due to previous error + diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs index 8d8ac279b23a8..f031a144443b3 100644 --- a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs +++ b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs @@ -10,7 +10,7 @@ fn main() { { let mut t: Tuple; t.0 = S(1); - //~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381] + //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] t.1 = 2; println!("{:?} {:?}", t.0, t.1); } @@ -18,7 +18,7 @@ fn main() { { let mut u: Tpair; u.0 = S(1); - //~^ ERROR assign to part of possibly uninitialized variable: `u` [E0381] + //~^ ERROR assign to part of possibly-uninitialized variable: `u` [E0381] u.1 = 2; println!("{:?} {:?}", u.0, u.1); } @@ -26,7 +26,7 @@ fn main() { { let mut v: Spair; v.x = S(1); - //~^ ERROR assign to part of possibly uninitialized variable: `v` [E0381] + //~^ ERROR assign to part of possibly-uninitialized variable: `v` [E0381] v.y = 2; println!("{:?} {:?}", v.x, v.y); } diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr index 6f18ff161372a..22c6c3964edc1 100644 --- a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr +++ b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr @@ -1,20 +1,20 @@ -error[E0381]: assign to part of possibly uninitialized variable: `t` +error[E0381]: assign to part of possibly-uninitialized variable: `t` --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:12:9 | LL | t.0 = S(1); - | ^^^^^^^^^^ use of possibly uninitialized `t` + | ^^^^^^^^^^ use of possibly-uninitialized `t` -error[E0381]: assign to part of possibly uninitialized variable: `u` +error[E0381]: assign to part of possibly-uninitialized variable: `u` --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:20:9 | LL | u.0 = S(1); - | ^^^^^^^^^^ use of possibly uninitialized `u` + | ^^^^^^^^^^ use of possibly-uninitialized `u` -error[E0381]: assign to part of possibly uninitialized variable: `v` +error[E0381]: assign to part of possibly-uninitialized variable: `v` --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:28:9 | LL | v.x = S(1); - | ^^^^^^^^^^ use of possibly uninitialized `v` + | ^^^^^^^^^^ use of possibly-uninitialized `v` error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs index 1a1b376bf9bcf..660d9e85ef54e 100644 --- a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs +++ b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs @@ -10,7 +10,7 @@ fn main() { { let t: Tuple; t.0 = S(1); - //~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381] + //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] t.1 = 2; println!("{:?} {:?}", t.0, t.1); } @@ -18,7 +18,7 @@ fn main() { { let u: Tpair; u.0 = S(1); - //~^ ERROR assign to part of possibly uninitialized variable: `u` [E0381] + //~^ ERROR assign to part of possibly-uninitialized variable: `u` [E0381] u.1 = 2; println!("{:?} {:?}", u.0, u.1); } @@ -26,7 +26,7 @@ fn main() { { let v: Spair; v.x = S(1); - //~^ ERROR assign to part of possibly uninitialized variable: `v` [E0381] + //~^ ERROR assign to part of possibly-uninitialized variable: `v` [E0381] v.y = 2; println!("{:?} {:?}", v.x, v.y); } diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr index 68873ac5c02e2..5f9c978c342f6 100644 --- a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr +++ b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr @@ -1,20 +1,20 @@ -error[E0381]: assign to part of possibly uninitialized variable: `t` +error[E0381]: assign to part of possibly-uninitialized variable: `t` --> $DIR/issue-54499-field-mutation-of-never-init.rs:12:9 | LL | t.0 = S(1); - | ^^^^^^^^^^ use of possibly uninitialized `t` + | ^^^^^^^^^^ use of possibly-uninitialized `t` -error[E0381]: assign to part of possibly uninitialized variable: `u` +error[E0381]: assign to part of possibly-uninitialized variable: `u` --> $DIR/issue-54499-field-mutation-of-never-init.rs:20:9 | LL | u.0 = S(1); - | ^^^^^^^^^^ use of possibly uninitialized `u` + | ^^^^^^^^^^ use of possibly-uninitialized `u` -error[E0381]: assign to part of possibly uninitialized variable: `v` +error[E0381]: assign to part of possibly-uninitialized variable: `v` --> $DIR/issue-54499-field-mutation-of-never-init.rs:28:9 | LL | v.x = S(1); - | ^^^^^^^^^^ use of possibly uninitialized `v` + | ^^^^^^^^^^ use of possibly-uninitialized `v` error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/issue-62107-match-arm-scopes.rs b/src/test/ui/borrowck/issue-62107-match-arm-scopes.rs index 220b2ecf04d38..f8efa8c891eb3 100644 --- a/src/test/ui/borrowck/issue-62107-match-arm-scopes.rs +++ b/src/test/ui/borrowck/issue-62107-match-arm-scopes.rs @@ -1,7 +1,7 @@ fn main() { let e: i32; match e { - //~^ ERROR use of possibly uninitialized variable + //~^ ERROR use of possibly-uninitialized variable ref u if true => {} ref v if true => { let tx = 0; diff --git a/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr b/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr index 9701343d2b1dd..0eca447b55159 100644 --- a/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr +++ b/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr @@ -1,8 +1,8 @@ -error[E0381]: use of possibly uninitialized variable: `e` +error[E0381]: use of possibly-uninitialized variable: `e` --> $DIR/issue-62107-match-arm-scopes.rs:3:11 | LL | match e { - | ^ use of possibly uninitialized `e` + | ^ use of possibly-uninitialized `e` error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-64453.rs b/src/test/ui/borrowck/issue-64453.rs new file mode 100644 index 0000000000000..d8ab6b6e25f6f --- /dev/null +++ b/src/test/ui/borrowck/issue-64453.rs @@ -0,0 +1,24 @@ +struct Project; +struct Value; + +static settings_dir: String = format!(""); +//~^ ERROR [E0019] +//~| ERROR [E0015] +//~| ERROR [E0015] + +fn from_string(_: String) -> Value { + Value +} +fn set_editor(_: Value) {} + +fn main() { + let settings_data = from_string(settings_dir); + //~^ ERROR cannot move out of static item `settings_dir` [E0507] + let args: i32 = 0; + + match args { + ref x if x == &0 => set_editor(settings_data), + ref x if x == &1 => set_editor(settings_data), + _ => unimplemented!(), + } +} diff --git a/src/test/ui/borrowck/issue-64453.stderr b/src/test/ui/borrowck/issue-64453.stderr new file mode 100644 index 0000000000000..6987417fe192e --- /dev/null +++ b/src/test/ui/borrowck/issue-64453.stderr @@ -0,0 +1,34 @@ +error[E0507]: cannot move out of static item `settings_dir` + --> $DIR/issue-64453.rs:15:37 + | +LL | let settings_data = from_string(settings_dir); + | ^^^^^^^^^^^^ move occurs because `settings_dir` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0019]: static contains unimplemented expression type + --> $DIR/issue-64453.rs:4:31 + | +LL | static settings_dir: String = format!(""); + | ^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants + --> $DIR/issue-64453.rs:4:31 + | +LL | static settings_dir: String = format!(""); + | ^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants + --> $DIR/issue-64453.rs:4:31 + | +LL | static settings_dir: String = format!(""); + | ^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0015, E0019, E0507. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/borrowck/move-error-snippets-ext.rs b/src/test/ui/borrowck/move-error-snippets-ext.rs new file mode 100644 index 0000000000000..c77f6c8276e70 --- /dev/null +++ b/src/test/ui/borrowck/move-error-snippets-ext.rs @@ -0,0 +1,7 @@ +// ignore-test + +macro_rules! aaa { + ($c:ident) => {{ + let a = $c; + }} +} diff --git a/src/test/ui/borrowck/move-error-snippets.rs b/src/test/ui/borrowck/move-error-snippets.rs new file mode 100644 index 0000000000000..64f9565382886 --- /dev/null +++ b/src/test/ui/borrowck/move-error-snippets.rs @@ -0,0 +1,23 @@ +// Test that we don't ICE after trying to construct a cross-file snippet #63800. + +// compile-flags: --test + +#[macro_use] +#[path = "move-error-snippets-ext.rs"] +mod move_error_snippets_ext; + +struct A; + +macro_rules! sss { + () => { + #[test] + fn fff() { + static D: A = A; + aaa!(D); //~ ERROR cannot move + } + }; +} + +sss!(); + +fn main() {} diff --git a/src/test/ui/borrowck/move-error-snippets.stderr b/src/test/ui/borrowck/move-error-snippets.stderr new file mode 100644 index 0000000000000..77463c48591bc --- /dev/null +++ b/src/test/ui/borrowck/move-error-snippets.stderr @@ -0,0 +1,15 @@ +error[E0507]: cannot move out of static item `D` + --> $DIR/move-error-snippets.rs:16:18 + | +LL | | #[macro_use] + | |__________________^ move occurs because `D` has type `A`, which does not implement the `Copy` trait +... +LL | aaa!(D); + | __________________^ +... +LL | sss!(); + | ------- in this macro invocation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.polonius.stderr b/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.polonius.stderr deleted file mode 100644 index a5b2e8762746c..0000000000000 --- a/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.polonius.stderr +++ /dev/null @@ -1,59 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:5:21 - | -LL | let ref mut x = 1234543; - | ^^^^^^^ creates a temporary which is freed while still in use -LL | x - | - borrow later used here -LL | } - | - temporary value is freed at the end of this statement - | - = note: consider using a `let` binding to create a longer lived value - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:10:25 - | -LL | let (ref mut x, ) = (1234543, ); - | ^^^^^^^^^^^ creates a temporary which is freed while still in use -LL | x - | - borrow later used here -LL | } - | - temporary value is freed at the end of this statement - | - = note: consider using a `let` binding to create a longer lived value - -error[E0515]: cannot return value referencing temporary value - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:15:5 - | -LL | match 1234543 { - | ^ ------- temporary value created here - | _____| - | | -LL | | ref mut x => x -LL | | } - | |_____^ returns a value referencing data owned by the current function - -error[E0515]: cannot return value referencing temporary value - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:21:5 - | -LL | match (123443,) { - | ^ --------- temporary value created here - | _____| - | | -LL | | (ref mut x,) => x, -LL | | } - | |_____^ returns a value referencing data owned by the current function - -error[E0515]: cannot return reference to temporary value - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:27:5 - | -LL | &mut 1234543 - | ^^^^^------- - | | | - | | temporary value created here - | returns a reference to data owned by the current function - -error: aborting due to 5 previous errors - -Some errors have detailed explanations: E0515, E0716. -For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/borrowck/reassignment_immutable_fields.stderr b/src/test/ui/borrowck/reassignment_immutable_fields.stderr index d455a8f078743..f09db378a75b4 100644 --- a/src/test/ui/borrowck/reassignment_immutable_fields.stderr +++ b/src/test/ui/borrowck/reassignment_immutable_fields.stderr @@ -1,14 +1,14 @@ -error[E0381]: assign to part of possibly uninitialized variable: `x` +error[E0381]: assign to part of possibly-uninitialized variable: `x` --> $DIR/reassignment_immutable_fields.rs:7:5 | LL | x.0 = 1; - | ^^^^^^^ use of possibly uninitialized `x` + | ^^^^^^^ use of possibly-uninitialized `x` -error[E0381]: assign to part of possibly uninitialized variable: `x` +error[E0381]: assign to part of possibly-uninitialized variable: `x` --> $DIR/reassignment_immutable_fields.rs:15:5 | LL | x.0 = 1; - | ^^^^^^^ use of possibly uninitialized `x` + | ^^^^^^^ use of possibly-uninitialized `x` error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr b/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr index 649c127dcc9d4..5f346708eb610 100644 --- a/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr +++ b/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr @@ -1,8 +1,8 @@ -error[E0381]: assign to part of possibly uninitialized variable: `x` +error[E0381]: assign to part of possibly-uninitialized variable: `x` --> $DIR/reassignment_immutable_fields_overlapping.rs:12:5 | LL | x.a = 1; - | ^^^^^^^ use of possibly uninitialized `x` + | ^^^^^^^ use of possibly-uninitialized `x` error[E0594]: cannot assign to `x.b`, as `x` is not declared as mutable --> $DIR/reassignment_immutable_fields_overlapping.rs:13:5 diff --git a/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr b/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr index 9a2824ccb3cd2..14f0fee84c9aa 100644 --- a/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr +++ b/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr @@ -7,11 +7,11 @@ LL | x = (22, 44); LL | x.0 = 1; | ^^^^^^^ cannot assign -error[E0381]: assign to part of possibly uninitialized variable: `x` +error[E0381]: assign to part of possibly-uninitialized variable: `x` --> $DIR/reassignment_immutable_fields_twice.rs:12:5 | LL | x.0 = 1; - | ^^^^^^^ use of possibly uninitialized `x` + | ^^^^^^^ use of possibly-uninitialized `x` error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/two-phase-across-loop.rs b/src/test/ui/borrowck/two-phase-across-loop.rs index 12222342c95a1..3fcea7d171349 100644 --- a/src/test/ui/borrowck/two-phase-across-loop.rs +++ b/src/test/ui/borrowck/two-phase-across-loop.rs @@ -1,4 +1,4 @@ -// Test that a borrow which starts as a 2-phase borrow and gets +// Test that a borrow which starts as a two-phase borrow and gets // carried around a loop winds up conflicting with itself. struct Foo { x: String } diff --git a/src/test/ui/borrowck/two-phase-multiple-activations.rs b/src/test/ui/borrowck/two-phase-multiple-activations.rs index a7fa7fac13e73..599138a9ce0f1 100644 --- a/src/test/ui/borrowck/two-phase-multiple-activations.rs +++ b/src/test/ui/borrowck/two-phase-multiple-activations.rs @@ -11,7 +11,7 @@ pub trait FakeRead { } impl FakeRead for Foo { - fn read_to_end(&mut self, buf: &mut Vec) -> Result { + fn read_to_end(&mut self, _buf: &mut Vec) -> Result { Ok(4) } } @@ -19,5 +19,5 @@ impl FakeRead for Foo { fn main() { let mut a = Foo {}; let mut v = Vec::new(); - a.read_to_end(&mut v); + a.read_to_end(&mut v).unwrap(); } diff --git a/src/test/ui/borrowck/two-phase-surprise-no-conflict.polonius.stderr b/src/test/ui/borrowck/two-phase-surprise-no-conflict.polonius.stderr deleted file mode 100644 index 7b246426a2333..0000000000000 --- a/src/test/ui/borrowck/two-phase-surprise-no-conflict.polonius.stderr +++ /dev/null @@ -1,148 +0,0 @@ -error[E0503]: cannot use `self.cx` because it was mutably borrowed - --> $DIR/two-phase-surprise-no-conflict.rs:21:23 - | -LL | let _mut_borrow = &mut *self; - | ---------- borrow of `*self` occurs here -LL | let _access = self.cx; - | ^^^^^^^ use of borrowed `*self` -LL | -LL | _mut_borrow; - | ----------- borrow later used here - -error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable - --> $DIR/two-phase-surprise-no-conflict.rs:57:17 - | -LL | self.hash_expr(&self.cx_mut.body(eid).value); - | ^^^^^---------^^-----------^^^^^^^^^^^^^^^^^ - | | | | - | | | immutable borrow occurs here - | | immutable borrow later used by call - | mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:119:51 - | -LL | reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut))); - | --- --------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:122:54 - | -LL | reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); - | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:125:53 - | -LL | reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); - | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:128:44 - | -LL | reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut)); - | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable - --> $DIR/two-phase-surprise-no-conflict.rs:138:5 - | -LL | reg.register_bound(Box::new(CapturePass::new(®.sess_mut))); - | ^^^^--------------^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^^^ - | | | | - | | | immutable borrow occurs here - | | immutable borrow later used by call - | mutable borrow occurs here - -error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable - --> $DIR/two-phase-surprise-no-conflict.rs:141:5 - | -LL | reg.register_univ(Box::new(CapturePass::new(®.sess_mut))); - | ^^^^-------------^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^^^ - | | | | - | | | immutable borrow occurs here - | | immutable borrow later used by call - | mutable borrow occurs here - -error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable - --> $DIR/two-phase-surprise-no-conflict.rs:144:5 - | -LL | reg.register_ref(&CapturePass::new(®.sess_mut)); - | ^^^^------------^^^^^^^^^^^^^^^^^^^-------------^^ - | | | | - | | | immutable borrow occurs here - | | immutable borrow later used by call - | mutable borrow occurs here - -error[E0499]: cannot borrow `*reg` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:154:5 - | -LL | reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | ^^^^--------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------^^^ - | | | | - | | | first mutable borrow occurs here - | | first borrow later used by call - | second mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:154:54 - | -LL | reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `*reg` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:158:5 - | -LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | ^^^^-------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------^^^ - | | | | - | | | first mutable borrow occurs here - | | first borrow later used by call - | second mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:158:53 - | -LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `*reg` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:162:5 - | -LL | reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut)); - | ^^^^------------^^^^^^^^^^^^^^^^^^^^^^^-----------------^^ - | | | | - | | | first mutable borrow occurs here - | | first borrow later used by call - | second mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:162:44 - | -LL | reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut)); - | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error: aborting due to 15 previous errors - -Some errors have detailed explanations: E0499, E0502, E0503. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/two-phase-surprise-no-conflict.rs b/src/test/ui/borrowck/two-phase-surprise-no-conflict.rs index 3fd24bbf290b5..6d37d1ded6400 100644 --- a/src/test/ui/borrowck/two-phase-surprise-no-conflict.rs +++ b/src/test/ui/borrowck/two-phase-surprise-no-conflict.rs @@ -31,7 +31,7 @@ impl <'a> SpanlessHash<'a> { // // Not okay without two-phase borrows: the implicit // `&mut self` of the receiver is evaluated first, and - // that conflicts with the `self.cx`` access during + // that conflicts with the `self.cx` access during // argument evaluation, as demonstrated in `fn demo` // above. // diff --git a/src/test/ui/break-outside-loop.rs b/src/test/ui/break-outside-loop.rs index fef298f7c3919..c424c25c646bd 100644 --- a/src/test/ui/break-outside-loop.rs +++ b/src/test/ui/break-outside-loop.rs @@ -7,8 +7,8 @@ fn cond() -> bool { true } fn foo(_: F) where F: FnOnce() {} fn main() { - let pth = break; //~ ERROR: `break` outside of loop - if cond() { continue } //~ ERROR: `continue` outside of loop + let pth = break; //~ ERROR: `break` outside of a loop + if cond() { continue } //~ ERROR: `continue` outside of a loop while cond() { if cond() { break } @@ -21,5 +21,5 @@ fn main() { let rs: Foo = Foo{t: pth}; - let unconstrained = break; //~ ERROR: `break` outside of loop + let unconstrained = break; //~ ERROR: `break` outside of a loop } diff --git a/src/test/ui/break-outside-loop.stderr b/src/test/ui/break-outside-loop.stderr index 8f4656ab394cd..8b686356055a3 100644 --- a/src/test/ui/break-outside-loop.stderr +++ b/src/test/ui/break-outside-loop.stderr @@ -1,32 +1,37 @@ -error[E0268]: `break` outside of loop +error[E0268]: `break` outside of a loop --> $DIR/break-outside-loop.rs:10:15 | LL | let pth = break; - | ^^^^^ cannot break outside of a loop + | ^^^^^ cannot `break` outside of a loop -error[E0268]: `continue` outside of loop +error[E0268]: `continue` outside of a loop --> $DIR/break-outside-loop.rs:11:17 | LL | if cond() { continue } - | ^^^^^^^^ cannot break outside of a loop + | ^^^^^^^^ cannot `continue` outside of a loop error[E0267]: `break` inside of a closure --> $DIR/break-outside-loop.rs:17:25 | +LL | foo(|| { + | -- enclosing closure LL | if cond() { break } - | ^^^^^ cannot break inside of a closure + | ^^^^^ cannot `break` inside of a closure error[E0267]: `continue` inside of a closure --> $DIR/break-outside-loop.rs:18:25 | +LL | foo(|| { + | -- enclosing closure +LL | if cond() { break } LL | if cond() { continue } - | ^^^^^^^^ cannot break inside of a closure + | ^^^^^^^^ cannot `continue` inside of a closure -error[E0268]: `break` outside of loop +error[E0268]: `break` outside of a loop --> $DIR/break-outside-loop.rs:24:25 | LL | let unconstrained = break; - | ^^^^^ cannot break outside of a loop + | ^^^^^ cannot `break` outside of a loop error: aborting due to 5 previous errors diff --git a/src/test/ui/c-variadic/variadic-ffi-1.stderr b/src/test/ui/c-variadic/variadic-ffi-1.stderr index 695eba2a7ee40..73f72a177bcaa 100644 --- a/src/test/ui/c-variadic/variadic-ffi-1.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-1.stderr @@ -29,7 +29,7 @@ LL | let x: unsafe extern "C" fn(f: isize, x: u8) = foo; | ^^^ expected non-variadic fn, found variadic function | = note: expected type `unsafe extern "C" fn(isize, u8)` - found type `for<'r> unsafe extern "C" fn(isize, u8, std::ffi::VaListImpl<'r>, ...) {foo}` + found type `unsafe extern "C" fn(isize, u8, ...) {foo}` error[E0308]: mismatched types --> $DIR/variadic-ffi-1.rs:20:54 @@ -37,7 +37,7 @@ error[E0308]: mismatched types LL | let y: extern "C" fn(f: isize, x: u8, ...) = bar; | ^^^ expected variadic fn, found non-variadic function | - = note: expected type `for<'r> extern "C" fn(isize, u8, std::ffi::VaListImpl<'r>, ...)` + = note: expected type `extern "C" fn(isize, u8, ...)` found type `extern "C" fn(isize, u8) {bar}` error[E0617]: can't pass `f32` to variadic function diff --git a/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr b/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr index 4947d6e529108..8b70b15fa6e50 100644 --- a/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr @@ -1,18 +1,30 @@ -error[E0621]: explicit lifetime required in the type of `ap` +error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:8:5 | LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { - | --- help: add explicit lifetime `'f` to the type of `ap`: `core::ffi::VaListImpl<'f>` + | -- -- has type `core::ffi::VaListImpl<'1>` + | | + | lifetime `'f` defined here LL | ap - | ^^ lifetime `'f` required + | ^^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'f` -error[E0621]: explicit lifetime required in the type of `ap` +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:8:5 + | +LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { + | -- -- has type `core::ffi::VaListImpl<'1>` + | | + | lifetime `'f` defined here +LL | ap + | ^^ returning this value requires that `'1` must outlive `'f` + +error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:12:5 | LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { - | --- help: add explicit lifetime `'static` to the type of `ap`: `core::ffi::VaListImpl<'static>` + | -- has type `core::ffi::VaListImpl<'1>` LL | ap - | ^^ lifetime `'static` required + | ^^ returning this value requires that `'1` must outlive `'static` error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:16:33 @@ -37,14 +49,14 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:20:5 | LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'1>` + | ------- ------- has type `core::ffi::VaListImpl<'2>` | | - | has type `&mut core::ffi::VaListImpl<'2>` + | has type `&mut core::ffi::VaListImpl<'1>` LL | *ap0 = ap1; - | ^^^^ assignment requires that `'1` must outlive `'2` + | ^^^^ assignment requires that `'2` must outlive `'1` error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:25:5 + --> $DIR/variadic-ffi-4.rs:24:5 | LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { | --- ------- has type `core::ffi::VaListImpl<'2>` @@ -54,17 +66,17 @@ LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:25:5 + --> $DIR/variadic-ffi-4.rs:24:5 | LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { - | --- ------- has type `core::ffi::VaListImpl<'1>` + | --- ------- has type `core::ffi::VaListImpl<'2>` | | - | has type `&mut core::ffi::VaListImpl<'2>` + | has type `&mut core::ffi::VaListImpl<'1>` LL | ap0 = &mut ap1; - | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` + | ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1` error[E0384]: cannot assign to immutable argument `ap0` - --> $DIR/variadic-ffi-4.rs:25:5 + --> $DIR/variadic-ffi-4.rs:24:5 | LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { | --- help: make this binding mutable: `mut ap0` @@ -72,7 +84,7 @@ LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ cannot assign to immutable argument error[E0597]: `ap1` does not live long enough - --> $DIR/variadic-ffi-4.rs:25:11 + --> $DIR/variadic-ffi-4.rs:24:11 | LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { | - let's call the lifetime of this reference `'1` @@ -86,7 +98,7 @@ LL | } | - `ap1` dropped here while still borrowed error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:33:12 + --> $DIR/variadic-ffi-4.rs:31:12 | LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { | ------- ------- has type `core::ffi::VaListImpl<'2>` @@ -96,16 +108,16 @@ LL | *ap0 = ap1.clone(); | ^^^^^^^^^^^ argument requires that `'1` must outlive `'2` error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:33:12 + --> $DIR/variadic-ffi-4.rs:31:12 | LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'1>` + | ------- ------- has type `core::ffi::VaListImpl<'2>` | | - | has type `&mut core::ffi::VaListImpl<'2>` + | has type `&mut core::ffi::VaListImpl<'1>` LL | *ap0 = ap1.clone(); - | ^^^^^^^^^^^ argument requires that `'1` must outlive `'2` + | ^^^^^^^^^^^ argument requires that `'2` must outlive `'1` -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors -Some errors have detailed explanations: E0384, E0597, E0621. +Some errors have detailed explanations: E0384, E0597. For more information about an error, try `rustc --explain E0384`. diff --git a/src/test/ui/c-variadic/variadic-ffi-4.rs b/src/test/ui/c-variadic/variadic-ffi-4.rs index 4a50d352a5b20..a4d658cef1630 100644 --- a/src/test/ui/c-variadic/variadic-ffi-4.rs +++ b/src/test/ui/c-variadic/variadic-ffi-4.rs @@ -5,11 +5,11 @@ use core::ffi::{VaList, VaListImpl}; pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { - ap //~ ERROR: explicit lifetime required + ap //~ ERROR: mismatched types } pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { - ap //~ ERROR: explicit lifetime required + ap //~ ERROR: mismatched types } pub unsafe extern "C" fn no_escape2(_: usize, ap: ...) { @@ -18,18 +18,15 @@ pub unsafe extern "C" fn no_escape2(_: usize, ap: ...) { pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { *ap0 = ap1; //~ ERROR: mismatched types - //~^ ERROR: mismatched types } pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { ap0 = &mut ap1; //~^ ERROR: a value of type `core::ffi::VaListImpl<'_>` is borrowed for too long - //~^^ ERROR: mismatched types - //~^^^ ERROR: mismatched types - //~^^^^ ERROR: cannot infer an appropriate lifetime + //~| ERROR: mismatched types + //~| ERROR: cannot infer an appropriate lifetime } pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { *ap0 = ap1.clone(); //~ ERROR: mismatched types - //~^ ERROR: mismatched types } diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr index 7aa510e611304..3d552f88ba667 100644 --- a/src/test/ui/c-variadic/variadic-ffi-4.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr @@ -1,18 +1,42 @@ -error[E0621]: explicit lifetime required in the type of `ap` +error[E0308]: mismatched types --> $DIR/variadic-ffi-4.rs:8:5 | -LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { - | --- help: add explicit lifetime `'f` to the type of `ap`: `core::ffi::VaListImpl<'f>` LL | ap - | ^^ lifetime `'f` required + | ^^ lifetime mismatch + | + = note: expected type `core::ffi::VaListImpl<'f>` + found type `core::ffi::VaListImpl<'_>` +note: the scope of call-site for function at 7:78... + --> $DIR/variadic-ffi-4.rs:7:78 + | +LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { + | ______________________________________________________________________________^ +LL | | ap +LL | | } + | |_^ +note: ...does not necessarily outlive the lifetime 'f as defined on the function body at 7:37 + --> $DIR/variadic-ffi-4.rs:7:37 + | +LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { + | ^^ -error[E0621]: explicit lifetime required in the type of `ap` +error[E0308]: mismatched types --> $DIR/variadic-ffi-4.rs:12:5 | -LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { - | --- help: add explicit lifetime `'static` to the type of `ap`: `core::ffi::VaListImpl<'static>` LL | ap - | ^^ lifetime `'static` required + | ^^ lifetime mismatch + | + = note: expected type `core::ffi::VaListImpl<'static>` + found type `core::ffi::VaListImpl<'_>` +note: the scope of call-site for function at 11:79... + --> $DIR/variadic-ffi-4.rs:11:79 + | +LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { + | _______________________________________________________________________________^ +LL | | ap +LL | | } + | |_^ + = note: ...does not necessarily outlive the static lifetime error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/variadic-ffi-4.rs:16:33 @@ -47,12 +71,12 @@ LL | *ap0 = ap1; | = note: expected type `core::ffi::VaListImpl<'_>` found type `core::ffi::VaListImpl<'_>` -note: the anonymous lifetime #3 defined on the function body at 19:1... - --> $DIR/variadic-ffi-4.rs:19:1 +note: the scope of call-site for function at 19:87... + --> $DIR/variadic-ffi-4.rs:19:87 | -LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { +LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { + | _______________________________________________________________________________________^ LL | | *ap0 = ap1; -LL | | LL | | } | |_^ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 19:1 @@ -60,216 +84,130 @@ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the f | LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { LL | | *ap0 = ap1; -LL | | -LL | | } - | |_^ - -error[E0308]: mismatched types - --> $DIR/variadic-ffi-4.rs:20:12 - | -LL | *ap0 = ap1; - | ^^^ lifetime mismatch - | - = note: expected type `core::ffi::VaListImpl<'_>` - found type `core::ffi::VaListImpl<'_>` -note: the anonymous lifetime #2 defined on the function body at 19:1... - --> $DIR/variadic-ffi-4.rs:19:1 - | -LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { -LL | | *ap0 = ap1; -LL | | -LL | | } - | |_^ -note: ...does not necessarily outlive the anonymous lifetime #3 defined on the function body at 19:1 - --> $DIR/variadic-ffi-4.rs:19:1 - | -LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { -LL | | *ap0 = ap1; -LL | | LL | | } | |_^ error[E0490]: a value of type `core::ffi::VaListImpl<'_>` is borrowed for too long - --> $DIR/variadic-ffi-4.rs:25:11 + --> $DIR/variadic-ffi-4.rs:24:11 | LL | ap0 = &mut ap1; | ^^^^^^^^ | -note: the type is valid for the anonymous lifetime #1 defined on the function body at 24:1 - --> $DIR/variadic-ffi-4.rs:24:1 - | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { -LL | | ap0 = &mut ap1; -LL | | -LL | | -LL | | -LL | | -LL | | } - | |_^ -note: but the borrow lasts for the anonymous lifetime #3 defined on the function body at 24:1 - --> $DIR/variadic-ffi-4.rs:24:1 - | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { -LL | | ap0 = &mut ap1; -LL | | -LL | | -LL | | -LL | | -LL | | } - | |_^ - -error[E0308]: mismatched types - --> $DIR/variadic-ffi-4.rs:25:11 - | -LL | ap0 = &mut ap1; - | ^^^^^^^^ lifetime mismatch - | - = note: expected type `&mut core::ffi::VaListImpl<'_>` - found type `&mut core::ffi::VaListImpl<'_>` -note: the anonymous lifetime #3 defined on the function body at 24:1... - --> $DIR/variadic-ffi-4.rs:24:1 +note: the type is valid for the anonymous lifetime #1 defined on the function body at 23:1 + --> $DIR/variadic-ffi-4.rs:23:1 | LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; LL | | LL | | LL | | -LL | | LL | | } | |_^ -note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 24:1 - --> $DIR/variadic-ffi-4.rs:24:1 +note: but the borrow lasts for the scope of call-site for function at 23:83 + --> $DIR/variadic-ffi-4.rs:23:83 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { +LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { + | ___________________________________________________________________________________^ LL | | ap0 = &mut ap1; LL | | LL | | LL | | -LL | | LL | | } | |_^ error[E0308]: mismatched types - --> $DIR/variadic-ffi-4.rs:25:11 + --> $DIR/variadic-ffi-4.rs:24:11 | LL | ap0 = &mut ap1; | ^^^^^^^^ lifetime mismatch | = note: expected type `&mut core::ffi::VaListImpl<'_>` found type `&mut core::ffi::VaListImpl<'_>` -note: the anonymous lifetime #2 defined on the function body at 24:1... - --> $DIR/variadic-ffi-4.rs:24:1 +note: the scope of call-site for function at 23:83... + --> $DIR/variadic-ffi-4.rs:23:83 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { +LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { + | ___________________________________________________________________________________^ LL | | ap0 = &mut ap1; LL | | LL | | LL | | -LL | | LL | | } | |_^ -note: ...does not necessarily outlive the anonymous lifetime #3 defined on the function body at 24:1 - --> $DIR/variadic-ffi-4.rs:24:1 +note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 23:1 + --> $DIR/variadic-ffi-4.rs:23:1 | LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; LL | | LL | | LL | | -LL | | LL | | } | |_^ error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements - --> $DIR/variadic-ffi-4.rs:25:11 + --> $DIR/variadic-ffi-4.rs:24:11 | LL | ap0 = &mut ap1; | ^^^^^^^^ | -note: first, the lifetime cannot outlive the anonymous lifetime #3 defined on the function body at 24:1... - --> $DIR/variadic-ffi-4.rs:24:1 +note: first, the lifetime cannot outlive the scope of call-site for function at 23:83... + --> $DIR/variadic-ffi-4.rs:23:83 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { +LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { + | ___________________________________________________________________________________^ LL | | ap0 = &mut ap1; LL | | LL | | LL | | -LL | | LL | | } | |_^ note: ...so that the type `core::ffi::VaListImpl<'_>` is not borrowed for too long - --> $DIR/variadic-ffi-4.rs:25:11 + --> $DIR/variadic-ffi-4.rs:24:11 | LL | ap0 = &mut ap1; | ^^^^^^^^ -note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the function body at 24:1... - --> $DIR/variadic-ffi-4.rs:24:1 +note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the function body at 23:1... + --> $DIR/variadic-ffi-4.rs:23:1 | LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; LL | | LL | | LL | | -LL | | LL | | } | |_^ note: ...so that reference does not outlive borrowed content - --> $DIR/variadic-ffi-4.rs:25:11 + --> $DIR/variadic-ffi-4.rs:24:11 | LL | ap0 = &mut ap1; | ^^^^^^^^ error[E0308]: mismatched types - --> $DIR/variadic-ffi-4.rs:33:12 + --> $DIR/variadic-ffi-4.rs:31:12 | LL | *ap0 = ap1.clone(); | ^^^^^^^^^^^ lifetime mismatch | = note: expected type `core::ffi::VaListImpl<'_>` found type `core::ffi::VaListImpl<'_>` -note: the anonymous lifetime #3 defined on the function body at 32:1... - --> $DIR/variadic-ffi-4.rs:32:1 +note: the scope of call-site for function at 30:87... + --> $DIR/variadic-ffi-4.rs:30:87 | -LL | / pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { +LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { + | _______________________________________________________________________________________^ LL | | *ap0 = ap1.clone(); -LL | | LL | | } | |_^ -note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 32:1 - --> $DIR/variadic-ffi-4.rs:32:1 +note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 30:1 + --> $DIR/variadic-ffi-4.rs:30:1 | LL | / pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { LL | | *ap0 = ap1.clone(); -LL | | -LL | | } - | |_^ - -error[E0308]: mismatched types - --> $DIR/variadic-ffi-4.rs:33:12 - | -LL | *ap0 = ap1.clone(); - | ^^^^^^^^^^^ lifetime mismatch - | - = note: expected type `core::ffi::VaListImpl<'_>` - found type `core::ffi::VaListImpl<'_>` -note: the anonymous lifetime #2 defined on the function body at 32:1... - --> $DIR/variadic-ffi-4.rs:32:1 - | -LL | / pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { -LL | | *ap0 = ap1.clone(); -LL | | -LL | | } - | |_^ -note: ...does not necessarily outlive the anonymous lifetime #3 defined on the function body at 32:1 - --> $DIR/variadic-ffi-4.rs:32:1 - | -LL | / pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { -LL | | *ap0 = ap1.clone(); -LL | | LL | | } | |_^ -error: aborting due to 11 previous errors +error: aborting due to 8 previous errors -Some errors have detailed explanations: E0308, E0621. +Some errors have detailed explanations: E0308, E0495. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.rs b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.rs new file mode 100644 index 0000000000000..e3b642a9d418d --- /dev/null +++ b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.rs @@ -0,0 +1,6 @@ +extern { + fn foo(...); + //~^ ERROR C-variadic function must be declared with at least one named argument +} + +fn main() {} diff --git a/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr new file mode 100644 index 0000000000000..cb6060525fc0d --- /dev/null +++ b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr @@ -0,0 +1,8 @@ +error: C-variadic function must be declared with at least one named argument + --> $DIR/variadic-ffi-no-fixed-args.rs:2:11 + | +LL | fn foo(...); + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/cfg/cfg_stmt_expr.rs b/src/test/ui/cfg/cfg_stmt_expr.rs index e466ad69f721c..6381bb2d58877 100644 --- a/src/test/ui/cfg/cfg_stmt_expr.rs +++ b/src/test/ui/cfg/cfg_stmt_expr.rs @@ -57,7 +57,7 @@ fn main() { // check that macro expanded code works macro_rules! if_cfg { - ($cfg:meta $ib:block else $eb:block) => { + ($cfg:meta? $ib:block else $eb:block) => { { let r; #[cfg($cfg)] @@ -69,7 +69,7 @@ fn main() { } } - let n = if_cfg!(unset { + let n = if_cfg!(unset? { 413 } else { 612 diff --git a/src/test/ui/chalkify/type_inference.stderr b/src/test/ui/chalkify/type_inference.stderr index 6cb33f2f2c8c6..c6bc306e45a1c 100644 --- a/src/test/ui/chalkify/type_inference.stderr +++ b/src/test/ui/chalkify/type_inference.stderr @@ -10,17 +10,15 @@ LL | only_foo(x); error[E0277]: the trait bound `{float}: Bar` is not satisfied --> $DIR/type_inference.rs:25:5 | +LL | fn only_bar(_x: T) { } + | -------- --- required by this bound in `only_bar` +... LL | only_bar(x); | ^^^^^^^^ the trait `Bar` is not implemented for `{float}` | = help: the following implementations were found: -note: required by `only_bar` - --> $DIR/type_inference.rs:12:1 - | -LL | fn only_bar(_x: T) { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/check-static-values-constraints.stderr b/src/test/ui/check-static-values-constraints.stderr index a13c217483d5d..7d7ecbd1a26a5 100644 --- a/src/test/ui/check-static-values-constraints.stderr +++ b/src/test/ui/check-static-values-constraints.stderr @@ -108,5 +108,5 @@ LL | let y = { static x: Box = box 3; x }; error: aborting due to 17 previous errors -Some errors have detailed explanations: E0010, E0015, E0019, E0507. +Some errors have detailed explanations: E0010, E0015, E0019, E0493, E0507. For more information about an error, try `rustc --explain E0010`. diff --git a/src/test/ui/class-cast-to-trait.stderr b/src/test/ui/class-cast-to-trait.stderr index 39f308cdfd490..4cab52e3e974c 100644 --- a/src/test/ui/class-cast-to-trait.stderr +++ b/src/test/ui/class-cast-to-trait.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `eat` found for type `std::boxed::Box` --> $DIR/class-cast-to-trait.rs:53:8 | LL | nyan.eat(); - | ^^^ + | ^^^ method not found in `std::boxed::Box` error: aborting due to previous error diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr index 7e4ac4e8ce656..a6b52b258f005 100644 --- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr @@ -1,53 +1,41 @@ error[E0631]: type mismatch in closure arguments --> $DIR/expect-fn-supply-fn.rs:30:5 | +LL | fn with_closure_expecting_fn_with_free_region(_: F) + | ------------------------------------------ +LL | where F: for<'a> FnOnce(fn(&'a u32), &i32) + | ------------------------- required by this bound in `with_closure_expecting_fn_with_free_region` +... LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _` | | | expected signature of `fn(fn(&'a u32), &i32) -> _` - | -note: required by `with_closure_expecting_fn_with_free_region` - --> $DIR/expect-fn-supply-fn.rs:1:1 - | -LL | / fn with_closure_expecting_fn_with_free_region(_: F) -LL | | where F: for<'a> FnOnce(fn(&'a u32), &i32) -LL | | { -LL | | } - | |_^ error[E0631]: type mismatch in closure arguments --> $DIR/expect-fn-supply-fn.rs:37:5 | +LL | fn with_closure_expecting_fn_with_bound_region(_: F) + | ------------------------------------------- +LL | where F: FnOnce(fn(&u32), &i32) + | ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region` +... LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _` | | | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` - | -note: required by `with_closure_expecting_fn_with_bound_region` - --> $DIR/expect-fn-supply-fn.rs:6:1 - | -LL | / fn with_closure_expecting_fn_with_bound_region(_: F) -LL | | where F: FnOnce(fn(&u32), &i32) -LL | | { -LL | | } - | |_^ error[E0631]: type mismatch in closure arguments --> $DIR/expect-fn-supply-fn.rs:46:5 | +LL | fn with_closure_expecting_fn_with_bound_region(_: F) + | ------------------------------------------- +LL | where F: FnOnce(fn(&u32), &i32) + | ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region` +... LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _` | | | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` - | -note: required by `with_closure_expecting_fn_with_bound_region` - --> $DIR/expect-fn-supply-fn.rs:6:1 - | -LL | / fn with_closure_expecting_fn_with_bound_region(_: F) -LL | | where F: FnOnce(fn(&u32), &i32) -LL | | { -LL | | } - | |_^ error: aborting due to 3 previous errors diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr index 40fab4d4edf78..ac4666fe36de6 100644 --- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr @@ -39,53 +39,41 @@ LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {}); error[E0631]: type mismatch in closure arguments --> $DIR/expect-fn-supply-fn.rs:30:5 | +LL | fn with_closure_expecting_fn_with_free_region(_: F) + | ------------------------------------------ +LL | where F: for<'a> FnOnce(fn(&'a u32), &i32) + | ------------------------- required by this bound in `with_closure_expecting_fn_with_free_region` +... LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _` | | | expected signature of `fn(fn(&'a u32), &i32) -> _` - | -note: required by `with_closure_expecting_fn_with_free_region` - --> $DIR/expect-fn-supply-fn.rs:1:1 - | -LL | / fn with_closure_expecting_fn_with_free_region(_: F) -LL | | where F: for<'a> FnOnce(fn(&'a u32), &i32) -LL | | { -LL | | } - | |_^ error[E0631]: type mismatch in closure arguments --> $DIR/expect-fn-supply-fn.rs:37:5 | +LL | fn with_closure_expecting_fn_with_bound_region(_: F) + | ------------------------------------------- +LL | where F: FnOnce(fn(&u32), &i32) + | ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region` +... LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _` | | | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` - | -note: required by `with_closure_expecting_fn_with_bound_region` - --> $DIR/expect-fn-supply-fn.rs:6:1 - | -LL | / fn with_closure_expecting_fn_with_bound_region(_: F) -LL | | where F: FnOnce(fn(&u32), &i32) -LL | | { -LL | | } - | |_^ error[E0631]: type mismatch in closure arguments --> $DIR/expect-fn-supply-fn.rs:46:5 | +LL | fn with_closure_expecting_fn_with_bound_region(_: F) + | ------------------------------------------- +LL | where F: FnOnce(fn(&u32), &i32) + | ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region` +... LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _` | | | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` - | -note: required by `with_closure_expecting_fn_with_bound_region` - --> $DIR/expect-fn-supply-fn.rs:6:1 - | -LL | / fn with_closure_expecting_fn_with_bound_region(_: F) -LL | | where F: FnOnce(fn(&u32), &i32) -LL | | { -LL | | } - | |_^ error: aborting due to 5 previous errors diff --git a/src/test/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr b/src/test/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr index c9a697496de59..9fbe95a9c3945 100644 --- a/src/test/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr +++ b/src/test/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr @@ -1,19 +1,15 @@ error[E0631]: type mismatch in closure arguments --> $DIR/expect-infer-var-appearing-twice.rs:14:5 | +LL | fn with_closure(_: F) + | ------------ +LL | where F: FnOnce(A, A) + | ------------ required by this bound in `with_closure` +... LL | with_closure(|x: u32, y: i32| { | ^^^^^^^^^^^^ ---------------- found signature of `fn(u32, i32) -> _` | | | expected signature of `fn(_, _) -> _` - | -note: required by `with_closure` - --> $DIR/expect-infer-var-appearing-twice.rs:1:1 - | -LL | / fn with_closure(_: F) -LL | | where F: FnOnce(A, A) -LL | | { -LL | | } - | |_^ error: aborting due to previous error diff --git a/src/test/ui/closure-expected.stderr b/src/test/ui/closure-expected.stderr index ff77423577db6..ae4f4d69b5ef5 100644 --- a/src/test/ui/closure-expected.stderr +++ b/src/test/ui/closure-expected.stderr @@ -1,8 +1,8 @@ error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `{integer}` - --> $DIR/closure-expected.rs:3:15 + --> $DIR/closure-expected.rs:3:23 | LL | let y = x.or_else(4); - | ^^^^^^^ expected an `FnOnce<()>` closure, found `{integer}` + | ^ expected an `FnOnce<()>` closure, found `{integer}` | = help: the trait `std::ops::FnOnce<()>` is not implemented for `{integer}` = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ } diff --git a/src/test/ui/closures/closure-array-break-length.rs b/src/test/ui/closures/closure-array-break-length.rs index a7f16d70ba860..f3567db1fac9c 100644 --- a/src/test/ui/closures/closure-array-break-length.rs +++ b/src/test/ui/closures/closure-array-break-length.rs @@ -1,9 +1,9 @@ fn main() { - |_: [_; continue]| {}; //~ ERROR: `continue` outside of loop + |_: [_; continue]| {}; //~ ERROR: `continue` outside of a loop - while |_: [_; continue]| {} {} //~ ERROR: `continue` outside of loop + while |_: [_; continue]| {} {} //~ ERROR: `continue` outside of a loop //~^ ERROR mismatched types - while |_: [_; break]| {} {} //~ ERROR: `break` outside of loop + while |_: [_; break]| {} {} //~ ERROR: `break` outside of a loop //~^ ERROR mismatched types } diff --git a/src/test/ui/closures/closure-array-break-length.stderr b/src/test/ui/closures/closure-array-break-length.stderr index 46fbd3e0fae0b..18da4a94e6f05 100644 --- a/src/test/ui/closures/closure-array-break-length.stderr +++ b/src/test/ui/closures/closure-array-break-length.stderr @@ -1,20 +1,20 @@ -error[E0268]: `continue` outside of loop +error[E0268]: `continue` outside of a loop --> $DIR/closure-array-break-length.rs:2:13 | LL | |_: [_; continue]| {}; - | ^^^^^^^^ cannot break outside of a loop + | ^^^^^^^^ cannot `continue` outside of a loop -error[E0268]: `continue` outside of loop +error[E0268]: `continue` outside of a loop --> $DIR/closure-array-break-length.rs:4:19 | LL | while |_: [_; continue]| {} {} - | ^^^^^^^^ cannot break outside of a loop + | ^^^^^^^^ cannot `continue` outside of a loop -error[E0268]: `break` outside of loop +error[E0268]: `break` outside of a loop --> $DIR/closure-array-break-length.rs:7:19 | LL | while |_: [_; break]| {} {} - | ^^^^^ cannot break outside of a loop + | ^^^^^ cannot `break` outside of a loop error[E0308]: mismatched types --> $DIR/closure-array-break-length.rs:4:11 diff --git a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr index 81c4f4e00aba0..51077b1b2922e 100644 --- a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr +++ b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr @@ -1,6 +1,9 @@ error[E0277]: `F` cannot be sent between threads safely --> $DIR/closure-bounds-cant-promote-superkind-in-struct.rs:5:1 | +LL | struct X where F: FnOnce() + 'static + Send { + | ---------------------------------------------- required by `X` +... LL | / fn foo(blk: F) -> X where F: FnOnce() + 'static { LL | | LL | | return X { field: blk }; @@ -9,11 +12,6 @@ LL | | } | = help: the trait `std::marker::Send` is not implemented for `F` = help: consider adding a `where F: std::marker::Send` bound -note: required by `X` - --> $DIR/closure-bounds-cant-promote-superkind-in-struct.rs:1:1 - | -LL | struct X where F: FnOnce() + 'static + Send { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/closures/closure-bounds-subtype.stderr b/src/test/ui/closures/closure-bounds-subtype.stderr index 3b9fd10af3860..4b703eded69c3 100644 --- a/src/test/ui/closures/closure-bounds-subtype.stderr +++ b/src/test/ui/closures/closure-bounds-subtype.stderr @@ -1,16 +1,14 @@ error[E0277]: `F` cannot be shared between threads safely - --> $DIR/closure-bounds-subtype.rs:13:5 + --> $DIR/closure-bounds-subtype.rs:13:22 | +LL | fn take_const_owned(_: F) where F: FnOnce() + Sync + Send { + | ---------------- ---- required by this bound in `take_const_owned` +... LL | take_const_owned(f); - | ^^^^^^^^^^^^^^^^ `F` cannot be shared between threads safely + | ^ `F` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `F` = help: consider adding a `where F: std::marker::Sync` bound -note: required by `take_const_owned` - --> $DIR/closure-bounds-subtype.rs:4:1 - | -LL | fn take_const_owned(_: F) where F: FnOnce() + Sync + Send { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/closures/closure-move-sync.rs b/src/test/ui/closures/closure-move-sync.rs index 580cd1af4f303..951a3bcb5f423 100644 --- a/src/test/ui/closures/closure-move-sync.rs +++ b/src/test/ui/closures/closure-move-sync.rs @@ -1,3 +1,5 @@ +// ignore-x86 +// ^ due to stderr output differences use std::thread; use std::sync::mpsc::channel; diff --git a/src/test/ui/closures/closure-move-sync.stderr b/src/test/ui/closures/closure-move-sync.stderr index 8afebc7c74816..f676df9c559eb 100644 --- a/src/test/ui/closures/closure-move-sync.stderr +++ b/src/test/ui/closures/closure-move-sync.stderr @@ -1,24 +1,32 @@ error[E0277]: `std::sync::mpsc::Receiver<()>` cannot be shared between threads safely - --> $DIR/closure-move-sync.rs:6:13 + --> $DIR/closure-move-sync.rs:8:13 | LL | let t = thread::spawn(|| { | ^^^^^^^^^^^^^ `std::sync::mpsc::Receiver<()>` cannot be shared between threads safely + | + ::: $SRC_DIR/libstd/thread/mod.rs:LL:COL + | +LL | F: FnOnce() -> T, F: Send + 'static, T: Send + 'static + | ---- required by this bound in `std::thread::spawn` | = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Receiver<()>` = note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Receiver<()>` - = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:6:27: 9:6 recv:&std::sync::mpsc::Receiver<()>]` - = note: required by `std::thread::spawn` + = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:8:27: 11:6 recv:&std::sync::mpsc::Receiver<()>]` error[E0277]: `std::sync::mpsc::Sender<()>` cannot be shared between threads safely - --> $DIR/closure-move-sync.rs:18:5 + --> $DIR/closure-move-sync.rs:20:5 | LL | thread::spawn(|| tx.send(()).unwrap()); | ^^^^^^^^^^^^^ `std::sync::mpsc::Sender<()>` cannot be shared between threads safely + | + ::: $SRC_DIR/libstd/thread/mod.rs:LL:COL + | +LL | F: FnOnce() -> T, F: Send + 'static, T: Send + 'static + | ---- required by this bound in `std::thread::spawn` | = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender<()>` = note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Sender<()>` - = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:18:19: 18:42 tx:&std::sync::mpsc::Sender<()>]` - = note: required by `std::thread::spawn` + = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:20:19: 20:42 tx:&std::sync::mpsc::Sender<()>]` error: aborting due to 2 previous errors diff --git a/src/test/ui/codemap_tests/bad-format-args.rs b/src/test/ui/codemap_tests/bad-format-args.rs index 9f90185774467..dff248344a53d 100644 --- a/src/test/ui/codemap_tests/bad-format-args.rs +++ b/src/test/ui/codemap_tests/bad-format-args.rs @@ -1,5 +1,5 @@ fn main() { format!(); //~ ERROR requires at least a format string argument format!("" 1); //~ ERROR expected token: `,` - format!("", 1 1); //~ ERROR expected token: `,` + format!("", 1 1); //~ ERROR expected one of } diff --git a/src/test/ui/codemap_tests/bad-format-args.stderr b/src/test/ui/codemap_tests/bad-format-args.stderr index 5b01314d8ad4f..3372ef6dea1fc 100644 --- a/src/test/ui/codemap_tests/bad-format-args.stderr +++ b/src/test/ui/codemap_tests/bad-format-args.stderr @@ -12,11 +12,11 @@ error: expected token: `,` LL | format!("" 1); | ^ expected `,` -error: expected token: `,` +error: expected one of `,`, `.`, `?`, or an operator, found `1` --> $DIR/bad-format-args.rs:4:19 | LL | format!("", 1 1); - | ^ expected `,` + | ^ expected one of `,`, `.`, `?`, or an operator here error: aborting due to 3 previous errors diff --git a/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr b/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr index 70c1093e9ed48..8fe24bae7c6ca 100644 --- a/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr +++ b/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr @@ -25,7 +25,7 @@ LL | fn baz(&self) {} LL | fn baz(&self) {} | ---------------- other definition for `baz` | - = note: upstream crates may add new impl of trait `std::marker::Copy` for type `std::vec::Vec<_>` in future versions + = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::vec::Vec<_>` in future versions error: aborting due to 3 previous errors diff --git a/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr b/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr index 057de5b625e87..955793e8586e7 100644 --- a/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr +++ b/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn plus_one(x: i32) -> i32 { | -------- ^^^ expected i32, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression LL | x + 1; | - help: consider removing this semicolon | @@ -17,7 +17,7 @@ error[E0308]: mismatched types LL | fn foo() -> Result { | --- ^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression LL | Ok(1); | - help: consider removing this semicolon | diff --git a/src/test/ui/coercion/coercion-slice.rs b/src/test/ui/coercion/coercion-slice.rs index 312b634c9fd0b..b69edcf260637 100644 --- a/src/test/ui/coercion/coercion-slice.rs +++ b/src/test/ui/coercion/coercion-slice.rs @@ -4,5 +4,5 @@ fn main() { let _: &[i32] = [0]; //~^ ERROR mismatched types //~| expected type `&[i32]` - //~| expected &[i32], found array of 1 elements + //~| expected &[i32], found array of 1 element } diff --git a/src/test/ui/coercion/coercion-slice.stderr b/src/test/ui/coercion/coercion-slice.stderr index 6fa712371178b..ccd776e987938 100644 --- a/src/test/ui/coercion/coercion-slice.stderr +++ b/src/test/ui/coercion/coercion-slice.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | let _: &[i32] = [0]; | ^^^ | | - | expected &[i32], found array of 1 elements + | expected &[i32], found array of 1 element | help: consider borrowing here: `&[0]` | = note: expected type `&[i32]` diff --git a/src/test/ui/coherence/auxiliary/coherence_lib.rs b/src/test/ui/coherence/auxiliary/coherence_lib.rs index 9a5ec82430639..c22819831ab24 100644 --- a/src/test/ui/coherence/auxiliary/coherence_lib.rs +++ b/src/test/ui/coherence/auxiliary/coherence_lib.rs @@ -5,11 +5,11 @@ pub trait Remote { } pub trait Remote1 { - fn foo(&self, t: T) { } + fn foo(&self, _t: T) { } } pub trait Remote2 { - fn foo(&self, t: T, u: U) { } + fn foo(&self, _t: T, _u: U) { } } pub struct Pair(T,U); diff --git a/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.old.stderr b/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.old.stderr index c38d7456a9952..18a7cea95bdb9 100644 --- a/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.old.stderr +++ b/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.old.stderr @@ -1,10 +1,10 @@ error[E0038]: the trait `NotObjectSafe` cannot be made into an object --> $DIR/coherence-impl-trait-for-trait-object-safe.rs:11:6 | +LL | trait NotObjectSafe { fn eq(&self, other: Self); } + | -- method `eq` references the `Self` type in its parameters or return type LL | impl NotObjectSafe for dyn NotObjectSafe { } | ^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object - | - = note: method `eq` references the `Self` type in its arguments or return type error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.re.stderr b/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.re.stderr index c38d7456a9952..18a7cea95bdb9 100644 --- a/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.re.stderr +++ b/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.re.stderr @@ -1,10 +1,10 @@ error[E0038]: the trait `NotObjectSafe` cannot be made into an object --> $DIR/coherence-impl-trait-for-trait-object-safe.rs:11:6 | +LL | trait NotObjectSafe { fn eq(&self, other: Self); } + | -- method `eq` references the `Self` type in its parameters or return type LL | impl NotObjectSafe for dyn NotObjectSafe { } | ^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object - | - = note: method `eq` references the `Self` type in its arguments or return type error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence-overlap-upstream-inherent.old.stderr b/src/test/ui/coherence/coherence-overlap-upstream-inherent.old.stderr index 928b65e003918..3a3e1a4afc3bb 100644 --- a/src/test/ui/coherence/coherence-overlap-upstream-inherent.old.stderr +++ b/src/test/ui/coherence/coherence-overlap-upstream-inherent.old.stderr @@ -7,7 +7,7 @@ LL | impl A where T: Remote { fn dummy(&self) { } } LL | impl A { fn dummy(&self) { } } | ------------------- other definition for `dummy` | - = note: upstream crates may add new impl of trait `coherence_lib::Remote` for type `i16` in future versions + = note: upstream crates may add a new impl of trait `coherence_lib::Remote` for type `i16` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence-overlap-upstream-inherent.re.stderr b/src/test/ui/coherence/coherence-overlap-upstream-inherent.re.stderr index 928b65e003918..3a3e1a4afc3bb 100644 --- a/src/test/ui/coherence/coherence-overlap-upstream-inherent.re.stderr +++ b/src/test/ui/coherence/coherence-overlap-upstream-inherent.re.stderr @@ -7,7 +7,7 @@ LL | impl A where T: Remote { fn dummy(&self) { } } LL | impl A { fn dummy(&self) { } } | ------------------- other definition for `dummy` | - = note: upstream crates may add new impl of trait `coherence_lib::Remote` for type `i16` in future versions + = note: upstream crates may add a new impl of trait `coherence_lib::Remote` for type `i16` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence-overlap-upstream.old.stderr b/src/test/ui/coherence/coherence-overlap-upstream.old.stderr index 6c3484c2d8c4d..bd6f59f346b6d 100644 --- a/src/test/ui/coherence/coherence-overlap-upstream.old.stderr +++ b/src/test/ui/coherence/coherence-overlap-upstream.old.stderr @@ -6,7 +6,7 @@ LL | impl Foo for T where T: Remote {} LL | impl Foo for i16 {} | ^^^^^^^^^^^^^^^^ conflicting implementation for `i16` | - = note: upstream crates may add new impl of trait `coherence_lib::Remote` for type `i16` in future versions + = note: upstream crates may add a new impl of trait `coherence_lib::Remote` for type `i16` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence-overlap-upstream.re.stderr b/src/test/ui/coherence/coherence-overlap-upstream.re.stderr index 6c3484c2d8c4d..bd6f59f346b6d 100644 --- a/src/test/ui/coherence/coherence-overlap-upstream.re.stderr +++ b/src/test/ui/coherence/coherence-overlap-upstream.re.stderr @@ -6,7 +6,7 @@ LL | impl Foo for T where T: Remote {} LL | impl Foo for i16 {} | ^^^^^^^^^^^^^^^^ conflicting implementation for `i16` | - = note: upstream crates may add new impl of trait `coherence_lib::Remote` for type `i16` in future versions + = note: upstream crates may add a new impl of trait `coherence_lib::Remote` for type `i16` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence-projection-conflict-orphan.old.stderr b/src/test/ui/coherence/coherence-projection-conflict-orphan.old.stderr index cde9360ddf2c8..728eae5e547da 100644 --- a/src/test/ui/coherence/coherence-projection-conflict-orphan.old.stderr +++ b/src/test/ui/coherence/coherence-projection-conflict-orphan.old.stderr @@ -7,7 +7,7 @@ LL | LL | impl Foo for A { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32` | - = note: upstream crates may add new impl of trait `std::iter::Iterator` for type `i32` in future versions + = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `i32` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence-projection-conflict-orphan.re.stderr b/src/test/ui/coherence/coherence-projection-conflict-orphan.re.stderr index cde9360ddf2c8..728eae5e547da 100644 --- a/src/test/ui/coherence/coherence-projection-conflict-orphan.re.stderr +++ b/src/test/ui/coherence/coherence-projection-conflict-orphan.re.stderr @@ -7,7 +7,7 @@ LL | LL | impl Foo for A { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32` | - = note: upstream crates may add new impl of trait `std::iter::Iterator` for type `i32` in future versions + = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `i32` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_tuple.old.stderr b/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_tuple.old.stderr index 12c7a1f977c3f..4d9f55c121547 100644 --- a/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_tuple.old.stderr +++ b/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_tuple.old.stderr @@ -7,7 +7,7 @@ LL | impl MyTrait for T { } LL | impl MyTrait for lib::MyFundamentalStruct<(MyType,)> { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `lib::MyFundamentalStruct<(MyType,)>` | - = note: upstream crates may add new impl of trait `lib::MyCopy` for type `lib::MyFundamentalStruct<(MyType,)>` in future versions + = note: upstream crates may add a new impl of trait `lib::MyCopy` for type `lib::MyFundamentalStruct<(MyType,)>` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_tuple.re.stderr b/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_tuple.re.stderr index 12c7a1f977c3f..4d9f55c121547 100644 --- a/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_tuple.re.stderr +++ b/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_tuple.re.stderr @@ -7,7 +7,7 @@ LL | impl MyTrait for T { } LL | impl MyTrait for lib::MyFundamentalStruct<(MyType,)> { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `lib::MyFundamentalStruct<(MyType,)>` | - = note: upstream crates may add new impl of trait `lib::MyCopy` for type `lib::MyFundamentalStruct<(MyType,)>` in future versions + = note: upstream crates may add a new impl of trait `lib::MyCopy` for type `lib::MyFundamentalStruct<(MyType,)>` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_copy_like_err_struct.old.stderr b/src/test/ui/coherence/coherence_copy_like_err_struct.old.stderr index 1b6c62e9bf3a8..f0bcf659bb696 100644 --- a/src/test/ui/coherence/coherence_copy_like_err_struct.old.stderr +++ b/src/test/ui/coherence/coherence_copy_like_err_struct.old.stderr @@ -7,7 +7,7 @@ LL | impl MyTrait for T { } LL | impl MyTrait for lib::MyStruct { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `lib::MyStruct` | - = note: upstream crates may add new impl of trait `lib::MyCopy` for type `lib::MyStruct` in future versions + = note: upstream crates may add a new impl of trait `lib::MyCopy` for type `lib::MyStruct` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_copy_like_err_struct.re.stderr b/src/test/ui/coherence/coherence_copy_like_err_struct.re.stderr index 1b6c62e9bf3a8..f0bcf659bb696 100644 --- a/src/test/ui/coherence/coherence_copy_like_err_struct.re.stderr +++ b/src/test/ui/coherence/coherence_copy_like_err_struct.re.stderr @@ -7,7 +7,7 @@ LL | impl MyTrait for T { } LL | impl MyTrait for lib::MyStruct { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `lib::MyStruct` | - = note: upstream crates may add new impl of trait `lib::MyCopy` for type `lib::MyStruct` in future versions + = note: upstream crates may add a new impl of trait `lib::MyCopy` for type `lib::MyStruct` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_copy_like_err_tuple.old.stderr b/src/test/ui/coherence/coherence_copy_like_err_tuple.old.stderr index 11bd788c76153..a40153af2cf30 100644 --- a/src/test/ui/coherence/coherence_copy_like_err_tuple.old.stderr +++ b/src/test/ui/coherence/coherence_copy_like_err_tuple.old.stderr @@ -7,7 +7,7 @@ LL | impl MyTrait for T { } LL | impl MyTrait for (MyType,) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(MyType,)` | - = note: upstream crates may add new impl of trait `lib::MyCopy` for type `(MyType,)` in future versions + = note: upstream crates may add a new impl of trait `lib::MyCopy` for type `(MyType,)` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_copy_like_err_tuple.re.stderr b/src/test/ui/coherence/coherence_copy_like_err_tuple.re.stderr index 11bd788c76153..a40153af2cf30 100644 --- a/src/test/ui/coherence/coherence_copy_like_err_tuple.re.stderr +++ b/src/test/ui/coherence/coherence_copy_like_err_tuple.re.stderr @@ -7,7 +7,7 @@ LL | impl MyTrait for T { } LL | impl MyTrait for (MyType,) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(MyType,)` | - = note: upstream crates may add new impl of trait `lib::MyCopy` for type `(MyType,)` in future versions + = note: upstream crates may add a new impl of trait `lib::MyCopy` for type `(MyType,)` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_inherent.old.stderr b/src/test/ui/coherence/coherence_inherent.old.stderr index fa564459b2133..e71547cb89f9c 100644 --- a/src/test/ui/coherence/coherence_inherent.old.stderr +++ b/src/test/ui/coherence/coherence_inherent.old.stderr @@ -2,10 +2,10 @@ error[E0599]: no method named `the_fn` found for type `&Lib::TheStruct` in the c --> $DIR/coherence_inherent.rs:35:11 | LL | s.the_fn(); - | ^^^^^^ + | ^^^^^^ method not found in `&Lib::TheStruct` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + = note: the following trait is implemented but not in scope; perhaps add a `use` for it: `use Lib::TheTrait;` error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_inherent.re.stderr b/src/test/ui/coherence/coherence_inherent.re.stderr index fa564459b2133..e71547cb89f9c 100644 --- a/src/test/ui/coherence/coherence_inherent.re.stderr +++ b/src/test/ui/coherence/coherence_inherent.re.stderr @@ -2,10 +2,10 @@ error[E0599]: no method named `the_fn` found for type `&Lib::TheStruct` in the c --> $DIR/coherence_inherent.rs:35:11 | LL | s.the_fn(); - | ^^^^^^ + | ^^^^^^ method not found in `&Lib::TheStruct` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + = note: the following trait is implemented but not in scope; perhaps add a `use` for it: `use Lib::TheTrait;` error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_inherent_cc.old.stderr b/src/test/ui/coherence/coherence_inherent_cc.old.stderr index 4d93e699031f3..3683943c5c819 100644 --- a/src/test/ui/coherence/coherence_inherent_cc.old.stderr +++ b/src/test/ui/coherence/coherence_inherent_cc.old.stderr @@ -2,10 +2,10 @@ error[E0599]: no method named `the_fn` found for type `&coherence_inherent_cc_li --> $DIR/coherence_inherent_cc.rs:26:11 | LL | s.the_fn(); - | ^^^^^^ + | ^^^^^^ method not found in `&coherence_inherent_cc_lib::TheStruct` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + = note: the following trait is implemented but not in scope; perhaps add a `use` for it: `use coherence_inherent_cc_lib::TheTrait;` error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_inherent_cc.re.stderr b/src/test/ui/coherence/coherence_inherent_cc.re.stderr index 4d93e699031f3..3683943c5c819 100644 --- a/src/test/ui/coherence/coherence_inherent_cc.re.stderr +++ b/src/test/ui/coherence/coherence_inherent_cc.re.stderr @@ -2,10 +2,10 @@ error[E0599]: no method named `the_fn` found for type `&coherence_inherent_cc_li --> $DIR/coherence_inherent_cc.rs:26:11 | LL | s.the_fn(); - | ^^^^^^ + | ^^^^^^ method not found in `&coherence_inherent_cc_lib::TheStruct` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + = note: the following trait is implemented but not in scope; perhaps add a `use` for it: `use coherence_inherent_cc_lib::TheTrait;` error: aborting due to previous error diff --git a/src/test/ui/coherence/conflicting-impl-with-err.rs b/src/test/ui/coherence/conflicting-impl-with-err.rs new file mode 100644 index 0000000000000..3e0234b874d7b --- /dev/null +++ b/src/test/ui/coherence/conflicting-impl-with-err.rs @@ -0,0 +1,16 @@ +struct ErrorKind; +struct Error(ErrorKind); + +impl From for Error { //~ ERROR failed to resolve + fn from(_: nope::Thing) -> Self { //~ ERROR failed to resolve + unimplemented!() + } +} + +impl From for Error { + fn from(_: ErrorKind) -> Self { + unimplemented!() + } +} + +fn main() {} diff --git a/src/test/ui/coherence/conflicting-impl-with-err.stderr b/src/test/ui/coherence/conflicting-impl-with-err.stderr new file mode 100644 index 0000000000000..a8a5730accdd8 --- /dev/null +++ b/src/test/ui/coherence/conflicting-impl-with-err.stderr @@ -0,0 +1,15 @@ +error[E0433]: failed to resolve: use of undeclared type or module `nope` + --> $DIR/conflicting-impl-with-err.rs:4:11 + | +LL | impl From for Error { + | ^^^^ use of undeclared type or module `nope` + +error[E0433]: failed to resolve: use of undeclared type or module `nope` + --> $DIR/conflicting-impl-with-err.rs:5:16 + | +LL | fn from(_: nope::Thing) -> Self { + | ^^^^ use of undeclared type or module `nope` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.rs b/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.rs new file mode 100644 index 0000000000000..b08fedc5e11c2 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for f64 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.stderr b/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.stderr new file mode 100644 index 0000000000000..04e96f29230fb --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[foreign]-for-foreign.stderr @@ -0,0 +1,12 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign[foreign]-for-foreign.rs:12:1 + | +LL | impl Remote1 for f64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl-foreign[foreign]-for-local.rs b/src/test/ui/coherence/impl-foreign[foreign]-for-local.rs new file mode 100644 index 0000000000000..33e85c164763e --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[foreign]-for-local.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Local { +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[foreign[t]_local]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[foreign[t]_local]-for-foreign.rs new file mode 100644 index 0000000000000..54d4bf04a583c --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[foreign[t]_local]-for-foreign.rs @@ -0,0 +1,14 @@ +#![feature(re_rebalance_coherence)] + +// check-pass +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +impl Remote2, Local> for usize { } + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].rs b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].rs new file mode 100644 index 0000000000000..66a4d9d273469 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].rs @@ -0,0 +1,20 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Box { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +impl<'a, T> Remote1 for &'a T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].stderr new file mode 100644 index 0000000000000..2467097b1a8b3 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[foreign]-for-fundamental[t].rs:12:1 + | +LL | impl Remote1 for Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[foreign]-for-fundamental[t].rs:16:1 + | +LL | impl<'a, T> Remote1 for &'a T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.rs b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.rs new file mode 100644 index 0000000000000..0a67ebcbba44c --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.stderr b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.stderr new file mode 100644 index 0000000000000..5c28406f113fc --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.stderr @@ -0,0 +1,11 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[foreign]-for-t.rs:12:1 + | +LL | impl Remote1 for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.rs new file mode 100644 index 0000000000000..71598dae96ab3 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.rs @@ -0,0 +1,20 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1> for u32 { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +impl<'a, T> Remote1<&'a T> for u32 { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.stderr b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.stderr new file mode 100644 index 0000000000000..dd9702650795e --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-foreign.rs:12:1 + | +LL | impl Remote1> for u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-foreign.rs:16:1 + | +LL | impl<'a, T> Remote1<&'a T> for u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].rs b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].rs new file mode 100644 index 0000000000000..7bf0306f29ba4 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].rs @@ -0,0 +1,19 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl<'a, T> Remote1> for &'a T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} +impl<'a, T> Remote1<&'a T> for Box { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].stderr new file mode 100644 index 0000000000000..eec57fccea762 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-fundamental[t].rs:12:1 + | +LL | impl<'a, T> Remote1> for &'a T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-fundamental[t].rs:15:1 + | +LL | impl<'a, T> Remote1<&'a T> for Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-local.rs b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-local.rs new file mode 100644 index 0000000000000..54d577c749248 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-local.rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1> for Local {} + +impl<'a, T> Remote1<&'a T> for Local {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.rs b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.rs new file mode 100644 index 0000000000000..7af929006ef7f --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.rs @@ -0,0 +1,19 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1> for T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} +impl<'a, T> Remote1<&'a T> for T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.stderr b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.stderr new file mode 100644 index 0000000000000..e017c3ffe6c05 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-t.rs:12:1 + | +LL | impl Remote1> for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]]-for-t.rs:15:1 + | +LL | impl<'a, T> Remote1<&'a T> for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.rs new file mode 100644 index 0000000000000..24e0f309c4555 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.rs @@ -0,0 +1,20 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote2, Local> for u32 { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +impl<'a, T> Remote2<&'a T, Local> for u32 { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.stderr b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.stderr new file mode 100644 index 0000000000000..3d8561956ae7f --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]_local]-for-foreign.rs:12:1 + | +LL | impl Remote2, Local> for u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[fundamental[t]_local]-for-foreign.rs:16:1 + | +LL | impl<'a, T> Remote2<&'a T, Local> for u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign.rs new file mode 100644 index 0000000000000..81cf3c3f6eca9 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Rc {} +impl Remote1 for Vec> {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].rs new file mode 100644 index 0000000000000..54425b6d708aa --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].rs @@ -0,0 +1,20 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Box { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +impl Remote1 for &T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].stderr new file mode 100644 index 0000000000000..7859665a7bb58 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[local]-for-fundamental[t].rs:12:1 + | +LL | impl Remote1 for Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[local]-for-fundamental[t].rs:16:1 + | +LL | impl Remote1 for &T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-local.rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-local.rs new file mode 100644 index 0000000000000..6b1d93cd94442 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-local.rs @@ -0,0 +1,15 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Local {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-t.rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-t.rs new file mode 100644 index 0000000000000..6f35c6c9dbc88 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-t.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-t.stderr b/src/test/ui/coherence/impl[t]-foreign[local]-for-t.stderr new file mode 100644 index 0000000000000..be7de8cccb467 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-t.stderr @@ -0,0 +1,11 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[local]-for-t.rs:12:1 + | +LL | impl Remote1 for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[local_fundamental[t]]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[local_fundamental[t]]-for-foreign.rs new file mode 100644 index 0000000000000..be0875d0110fd --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local_fundamental[t]]-for-foreign.rs @@ -0,0 +1,19 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local2(Rc); + +impl Remote2> for u32 {} +impl<'a, T> Remote2 for u32 {} +impl Remote2, Box> for u32 {} +impl<'a, T> Remote2, &'a T> for u32 {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.rs b/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.rs new file mode 100644 index 0000000000000..5e89c2077330a --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for u32 { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.stderr b/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.stderr new file mode 100644 index 0000000000000..5544729b5d640 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.stderr @@ -0,0 +1,11 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[t]-for-foreign.rs:12:1 + | +LL | impl Remote1 for u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.rs b/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.rs new file mode 100644 index 0000000000000..300a2c4d48a9c --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.rs @@ -0,0 +1,20 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Box { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +impl<'a, A, B> Remote1 for &'a B { + //~^ ERROR type parameter `B` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.stderr b/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.stderr new file mode 100644 index 0000000000000..be8cc29a6e5b0 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[t]-for-fundamental.rs:12:1 + | +LL | impl Remote1 for Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `B` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[t]-for-fundamental.rs:16:1 + | +LL | impl<'a, A, B> Remote1 for &'a B { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `B` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-local.rs b/src/test/ui/coherence/impl[t]-foreign[t]-for-local.rs new file mode 100644 index 0000000000000..769147ea7eabd --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-local.rs @@ -0,0 +1,15 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for Local {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-t.rs b/src/test/ui/coherence/impl[t]-foreign[t]-for-t.rs new file mode 100644 index 0000000000000..c8513380ff73e --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-t.rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1 for T { + //~^ ERROR type parameter `T` must be used as the type parameter for some local type +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-t.stderr b/src/test/ui/coherence/impl[t]-foreign[t]-for-t.stderr new file mode 100644 index 0000000000000..de857afd20b15 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-t.stderr @@ -0,0 +1,11 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign[t]-for-t.rs:12:1 + | +LL | impl Remote1 for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/re-rebalance-coherence-rpass.rs b/src/test/ui/coherence/re-rebalance-coherence-rpass.rs deleted file mode 100644 index bacd3b89fad29..0000000000000 --- a/src/test/ui/coherence/re-rebalance-coherence-rpass.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![allow(dead_code)] -#![feature(re_rebalance_coherence)] - -// run-pass -// aux-build:re_rebalance_coherence_lib.rs - -extern crate re_rebalance_coherence_lib as lib; -use lib::*; - -struct Oracle; -impl Backend for Oracle {} -impl<'a, T:'a, Tab> QueryFragment for BatchInsert<'a, T, Tab> {} - -fn main() {} diff --git a/src/test/ui/collections-const-new.rs b/src/test/ui/collections-const-new.rs index e01b0dfa14d6e..a93f9a136db23 100644 --- a/src/test/ui/collections-const-new.rs +++ b/src/test/ui/collections-const-new.rs @@ -1,15 +1,11 @@ -// run-pass +// check-pass -#![allow(dead_code)] // Test several functions can be used for constants // 1. Vec::new() // 2. String::new() -#![feature(const_vec_new)] -#![feature(const_string_new)] - const MY_VEC: Vec = Vec::new(); const MY_STRING: String = String::new(); -pub fn main() {} +fn main() {} diff --git a/src/test/ui/commandline-argfile-badutf8.args b/src/test/ui/commandline-argfile-badutf8.args new file mode 100644 index 0000000000000..c070b0c2400d8 --- /dev/null +++ b/src/test/ui/commandline-argfile-badutf8.args @@ -0,0 +1,2 @@ +--cfg +unbroken� \ No newline at end of file diff --git a/src/test/ui/commandline-argfile-badutf8.rs b/src/test/ui/commandline-argfile-badutf8.rs new file mode 100644 index 0000000000000..161715685b57f --- /dev/null +++ b/src/test/ui/commandline-argfile-badutf8.rs @@ -0,0 +1,13 @@ +// Check to see if we can get parameters from an @argsfile file +// +// build-fail +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-badutf8.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/ui/commandline-argfile-badutf8.stderr b/src/test/ui/commandline-argfile-badutf8.stderr new file mode 100644 index 0000000000000..9af6fc0a518df --- /dev/null +++ b/src/test/ui/commandline-argfile-badutf8.stderr @@ -0,0 +1,2 @@ +error: Failed to load argument file: Utf8 error in $DIR/commandline-argfile-badutf8.args + diff --git a/src/test/ui/commandline-argfile-missing.rs b/src/test/ui/commandline-argfile-missing.rs new file mode 100644 index 0000000000000..a29b4ab062de3 --- /dev/null +++ b/src/test/ui/commandline-argfile-missing.rs @@ -0,0 +1,16 @@ +// Check to see if we can get parameters from an @argsfile file +// +// ignore-tidy-linelength +// build-fail +// normalize-stderr-test: "os error \d+" -> "os error $$ERR" +// normalize-stderr-test: "commandline-argfile-missing.args:[^(]*" -> "commandline-argfile-missing.args: $$FILE_MISSING " +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-missing.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/ui/commandline-argfile-missing.stderr b/src/test/ui/commandline-argfile-missing.stderr new file mode 100644 index 0000000000000..179ad83100419 --- /dev/null +++ b/src/test/ui/commandline-argfile-missing.stderr @@ -0,0 +1,2 @@ +error: Failed to load argument file: IO Error: $DIR/commandline-argfile-missing.args: $FILE_MISSING (os error $ERR) + diff --git a/src/test/ui/commandline-argfile.args b/src/test/ui/commandline-argfile.args new file mode 100644 index 0000000000000..972938bf6c8dd --- /dev/null +++ b/src/test/ui/commandline-argfile.args @@ -0,0 +1,2 @@ +--cfg +unbroken \ No newline at end of file diff --git a/src/test/ui/commandline-argfile.rs b/src/test/ui/commandline-argfile.rs new file mode 100644 index 0000000000000..fc1ba0c8d677d --- /dev/null +++ b/src/test/ui/commandline-argfile.rs @@ -0,0 +1,13 @@ +// Check to see if we can get parameters from an @argsfile file +// +// build-pass +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/ui/compare-method/reordered-type-param.stderr b/src/test/ui/compare-method/reordered-type-param.stderr index a33908c01c842..8176e96d6de1f 100644 --- a/src/test/ui/compare-method/reordered-type-param.stderr +++ b/src/test/ui/compare-method/reordered-type-param.stderr @@ -9,6 +9,8 @@ LL | fn b(&self, _x: G) -> G { panic!() } | = note: expected type `fn(&E, F) -> F` found type `fn(&E, G) -> G` + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error: aborting due to previous error diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-6.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-6.rs new file mode 100644 index 0000000000000..9fa726f93e3ea --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-6.rs @@ -0,0 +1,3 @@ +// compile-flags: --cfg a{ +// error-pattern: invalid `--cfg` argument: `a{` (expected `key` or `key="value"`) +fn main() {} diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-6.stderr b/src/test/ui/conditional-compilation/cfg-arg-invalid-6.stderr new file mode 100644 index 0000000000000..7d2087b4b71f7 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-6.stderr @@ -0,0 +1,2 @@ +error: invalid `--cfg` argument: `a{` (expected `key` or `key="value"`) + diff --git a/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr index db3c7acff151c..e9df780def5df 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr @@ -1,6 +1,9 @@ error[E0601]: `main` function not found in crate `cfg_attr_cfg_2` + --> $DIR/cfg-attr-cfg-2.rs:8:1 | - = note: consider adding a `main` function to `$DIR/cfg-attr-cfg-2.rs` +LL | / #[cfg_attr(foo, cfg(bar))] +LL | | fn main() { } + | |_____________^ consider adding a `main` function to `$DIR/cfg-attr-cfg-2.rs` error: aborting due to previous error diff --git a/src/test/ui/conditional-compilation/cfg-attr-crate-2.rs b/src/test/ui/conditional-compilation/cfg-attr-crate-2.rs index 0dceba28b6ec3..7dbeba53afcfe 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-crate-2.rs +++ b/src/test/ui/conditional-compilation/cfg-attr-crate-2.rs @@ -3,6 +3,6 @@ // compile-flags: --cfg broken #![crate_type = "lib"] -#![cfg_attr(broken, no_core)] //~ ERROR no_core is experimental +#![cfg_attr(broken, no_core)] //~ ERROR the `#[no_core]` attribute is an experimental feature pub struct S {} diff --git a/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr index 5a70a5efc7f2a..7b77701ee190f 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr @@ -1,4 +1,4 @@ -error[E0658]: no_core is experimental +error[E0658]: the `#[no_core]` attribute is an experimental feature --> $DIR/cfg-attr-crate-2.rs:6:21 | LL | #![cfg_attr(broken, no_core)] diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs index be762c56048d4..42ffb71e3d7b9 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs @@ -1,6 +1,7 @@ // compile-flags: --cfg broken #![crate_type = "lib"] -#![cfg_attr(broken, no_core, no_std)] //~ ERROR no_core is experimental +#![cfg_attr(broken, no_core, no_std)] +//~^ ERROR the `#[no_core]` attribute is an experimental feature pub struct S {} diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr index 5e9adf1780737..ab7e1eb96032d 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr @@ -1,4 +1,4 @@ -error[E0658]: no_core is experimental +error[E0658]: the `#[no_core]` attribute is an experimental feature --> $DIR/cfg-attr-multi-invalid-1.rs:4:21 | LL | #![cfg_attr(broken, no_core, no_std)] diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs index 8a9e99d703c70..29690e2848f2d 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs @@ -1,6 +1,7 @@ // compile-flags: --cfg broken #![crate_type = "lib"] -#![cfg_attr(broken, no_std, no_core)] //~ ERROR no_core is experimental +#![cfg_attr(broken, no_std, no_core)] +//~^ ERROR the `#[no_core]` attribute is an experimental feature pub struct S {} diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr index 06b67156651cc..8126affbd36cd 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr @@ -1,4 +1,4 @@ -error[E0658]: no_core is experimental +error[E0658]: the `#[no_core]` attribute is an experimental feature --> $DIR/cfg-attr-multi-invalid-2.rs:4:29 | LL | #![cfg_attr(broken, no_std, no_core)] diff --git a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs index 22dbac766707d..45b757e928302 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs +++ b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs @@ -1,7 +1,7 @@ macro_rules! foo { () => { #[cfg_attr(all(), unknown)] - //~^ ERROR cannot find attribute macro `unknown` in this scope + //~^ ERROR cannot find attribute `unknown` in this scope fn foo() {} } } diff --git a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr index c7c52a2923a59..ef434ec82610e 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr @@ -1,4 +1,4 @@ -error: cannot find attribute macro `unknown` in this scope +error: cannot find attribute `unknown` in this scope --> $DIR/cfg-attr-unknown-attribute-macro-expansion.rs:3:27 | LL | #[cfg_attr(all(), unknown)] diff --git a/src/test/ui/conditional-compilation/cfg-generic-params.rs b/src/test/ui/conditional-compilation/cfg-generic-params.rs index d80d3ea7b7fe9..53aa3556362f9 100644 --- a/src/test/ui/conditional-compilation/cfg-generic-params.rs +++ b/src/test/ui/conditional-compilation/cfg-generic-params.rs @@ -16,21 +16,23 @@ struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy; //~^ ERROR only lifetime parameters can be used in this context fn f_lt_no<#[cfg_attr(no, unknown)] 'a>() {} // OK -fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {} //~ ERROR attribute `unknown` is currently unknown +fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {} +//~^ ERROR cannot find attribute `unknown` in this scope fn f_ty_no<#[cfg_attr(no, unknown)] T>() {} // OK -fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {} //~ ERROR attribute `unknown` is currently unknown +fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {} +//~^ ERROR cannot find attribute `unknown` in this scope type FnNo = for<#[cfg_attr(no, unknown)] 'a> fn(); // OK type FnYes = for<#[cfg_attr(yes, unknown)] 'a> fn(); -//~^ ERROR attribute `unknown` is currently unknown +//~^ ERROR cannot find attribute `unknown` in this scope type PolyNo = dyn for<#[cfg_attr(no, unknown)] 'a> Copy; // OK type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy; -//~^ ERROR attribute `unknown` is currently unknown +//~^ ERROR cannot find attribute `unknown` in this scope struct WhereNo where for<#[cfg_attr(no, unknown)] 'a> u8: Copy; // OK struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy; -//~^ ERROR attribute `unknown` is currently unknown +//~^ ERROR cannot find attribute `unknown` in this scope fn main() { f_lt::<'static>(); diff --git a/src/test/ui/conditional-compilation/cfg-generic-params.stderr b/src/test/ui/conditional-compilation/cfg-generic-params.stderr index 1f9731fcfbefb..d9e29c8262c63 100644 --- a/src/test/ui/conditional-compilation/cfg-generic-params.stderr +++ b/src/test/ui/conditional-compilation/cfg-generic-params.stderr @@ -16,51 +16,35 @@ error: only lifetime parameters can be used in this context LL | struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy; | ^ -error[E0658]: the attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/cfg-generic-params.rs:19:29 - | -LL | fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {} - | ^^^^^^^ +error: cannot find attribute `unknown` in this scope + --> $DIR/cfg-generic-params.rs:34:43 | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy; + | ^^^^^^^ -error[E0658]: the attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/cfg-generic-params.rs:21:29 +error: cannot find attribute `unknown` in this scope + --> $DIR/cfg-generic-params.rs:30:40 | -LL | fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {} - | ^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy; + | ^^^^^^^ -error[E0658]: the attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/cfg-generic-params.rs:24:34 +error: cannot find attribute `unknown` in this scope + --> $DIR/cfg-generic-params.rs:26:34 | LL | type FnYes = for<#[cfg_attr(yes, unknown)] 'a> fn(); | ^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable -error[E0658]: the attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/cfg-generic-params.rs:28:40 +error: cannot find attribute `unknown` in this scope + --> $DIR/cfg-generic-params.rs:22:29 | -LL | type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy; - | ^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {} + | ^^^^^^^ -error[E0658]: the attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/cfg-generic-params.rs:32:43 - | -LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy; - | ^^^^^^^ +error: cannot find attribute `unknown` in this scope + --> $DIR/cfg-generic-params.rs:19:29 | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {} + | ^^^^^^^ error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr b/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr index c6d42c732c934..0b5c3e0335586 100644 --- a/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr +++ b/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr @@ -1,6 +1,8 @@ error[E0601]: `main` function not found in crate `cfg_in_crate_1` + --> $DIR/cfg-in-crate-1.rs:3:1 | - = note: consider adding a `main` function to `$DIR/cfg-in-crate-1.rs` +LL | #![cfg(bar)] + | ^^^^^^^^^^^^ consider adding a `main` function to `$DIR/cfg-in-crate-1.rs` error: aborting due to previous error diff --git a/src/test/ui/conflicting-repr-hints.stderr b/src/test/ui/conflicting-repr-hints.stderr index 6b15b7ebbe9ee..832f5c3ac2bb7 100644 --- a/src/test/ui/conflicting-repr-hints.stderr +++ b/src/test/ui/conflicting-repr-hints.stderr @@ -66,3 +66,4 @@ LL | | } error: aborting due to 8 previous errors +For more information about this error, try `rustc --explain E0566`. diff --git a/src/test/ui/const-generics/apit-with-const-param.rs b/src/test/ui/const-generics/apit-with-const-param.rs index 70e718d889029..7acc50819a6ad 100644 --- a/src/test/ui/const-generics/apit-with-const-param.rs +++ b/src/test/ui/const-generics/apit-with-const-param.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash diff --git a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr index 09652d99e8ea5..594a0d4b5d844 100644 --- a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr +++ b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr @@ -8,10 +8,10 @@ LL | println!("{:?}", [0_usize; 33]); = note: required by `std::fmt::Debug::fmt` error[E0277]: arrays only have std trait implementations for lengths 0..=32 - --> $DIR/core-traits-no-impls-length-33.rs:9:9 + --> $DIR/core-traits-no-impls-length-33.rs:9:16 | LL | set.insert([0_usize; 33]); - | ^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[usize; 33]` + | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[usize; 33]` | = note: required because of the requirements on the impl of `std::cmp::Eq` for `[usize; 33]` diff --git a/src/test/ui/const-generics/array-wrapper-struct-ctor.rs b/src/test/ui/const-generics/array-wrapper-struct-ctor.rs index d83846fcf88d4..2d1a405ebdd80 100644 --- a/src/test/ui/const-generics/array-wrapper-struct-ctor.rs +++ b/src/test/ui/const-generics/array-wrapper-struct-ctor.rs @@ -3,6 +3,8 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash +#![allow(dead_code)] + struct ArrayStruct { data: [T; N], } diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr index 142efe45ac2d7..db14f9c9bf695 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr @@ -18,7 +18,7 @@ error[E0392]: parameter `T` is never used LL | pub struct Dependent([(); X]); | ^ unused parameter | - = help: consider removing `T` or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/const-types.rs b/src/test/ui/const-generics/const-types.rs index 11757cd588dab..bc5188133d7f1 100644 --- a/src/test/ui/const-generics/const-types.rs +++ b/src/test/ui/const-generics/const-types.rs @@ -3,7 +3,7 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash -#[allow(dead_code)] +#![allow(dead_code, unused_variables)] struct ConstArray { array: [T; LEN], diff --git a/src/test/ui/const-generics/fn-const-param-call.rs b/src/test/ui/const-generics/fn-const-param-call.rs new file mode 100644 index 0000000000000..84615386d2995 --- /dev/null +++ b/src/test/ui/const-generics/fn-const-param-call.rs @@ -0,0 +1,20 @@ +// run-pass + +#![feature(const_generics, const_compare_raw_pointers)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +fn function() -> u32 { + 17 +} + +struct Wrapper u32>; + +impl u32> Wrapper<{F}> { + fn call() -> u32 { + F() + } +} + +fn main() { + assert_eq!(Wrapper::<{function}>::call(), 17); +} diff --git a/src/test/ui/const-generics/fn-const-param-call.stderr b/src/test/ui/const-generics/fn-const-param-call.stderr new file mode 100644 index 0000000000000..c677d70374931 --- /dev/null +++ b/src/test/ui/const-generics/fn-const-param-call.stderr @@ -0,0 +1,8 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/fn-const-param-call.rs:3:12 + | +LL | #![feature(const_generics, const_compare_raw_pointers)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + diff --git a/src/test/ui/const-generics/fn-const-param-infer.rs b/src/test/ui/const-generics/fn-const-param-infer.rs new file mode 100644 index 0000000000000..78fb10e8cb904 --- /dev/null +++ b/src/test/ui/const-generics/fn-const-param-infer.rs @@ -0,0 +1,26 @@ +#![feature(const_generics, const_compare_raw_pointers)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct Checked bool>; + +fn not_one(val: usize) -> bool { val != 1 } +fn not_two(val: usize) -> bool { val != 2 } + +fn generic_arg(val: T) -> bool { true } + +fn generic(val: usize) -> bool { val != 1 } + +fn main() { + let _: Option> = None; + let _: Checked<{not_one}> = Checked::<{not_one}>; + let _: Checked<{not_one}> = Checked::<{not_two}>; //~ mismatched types + + let _ = Checked::<{generic_arg}>; + let _ = Checked::<{generic_arg::}>; + let _ = Checked::<{generic_arg::}>; //~ mismatched types + + let _ = Checked::<{generic}>; //~ type annotations needed + let _ = Checked::<{generic::}>; + let _: Checked<{generic::}> = Checked::<{generic::}>; + let _: Checked<{generic::}> = Checked::<{generic::}>; //~ mismatched types +} diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr new file mode 100644 index 0000000000000..de0916b26bfef --- /dev/null +++ b/src/test/ui/const-generics/fn-const-param-infer.stderr @@ -0,0 +1,45 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/fn-const-param-infer.rs:1:12 + | +LL | #![feature(const_generics, const_compare_raw_pointers)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/fn-const-param-infer.rs:16:33 + | +LL | let _: Checked<{not_one}> = Checked::<{not_two}>; + | ^^^^^^^^^^^^^^^^^^^^ expected `not_one`, found `not_two` + | + = note: expected type `Checked` + found type `Checked` + +error[E0308]: mismatched types + --> $DIR/fn-const-param-infer.rs:20:24 + | +LL | let _ = Checked::<{generic_arg::}>; + | ^^^^^^^^^^^^^^^^^^ expected usize, found u32 + | + = note: expected type `fn(usize) -> bool` + found type `fn(u32) -> bool {generic_arg::}` + +error[E0282]: type annotations needed + --> $DIR/fn-const-param-infer.rs:22:24 + | +LL | let _ = Checked::<{generic}>; + | ^^^^^^^ cannot infer type for `T` + +error[E0308]: mismatched types + --> $DIR/fn-const-param-infer.rs:25:40 + | +LL | let _: Checked<{generic::}> = Checked::<{generic::}>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `generic::`, found `generic::` + | + = note: expected type `Checked>` + found type `Checked>` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0282, E0308. +For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/foreign-item-const-parameter.rs b/src/test/ui/const-generics/foreign-item-const-parameter.rs new file mode 100644 index 0000000000000..4673c8606c393 --- /dev/null +++ b/src/test/ui/const-generics/foreign-item-const-parameter.rs @@ -0,0 +1,10 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +extern "C" { + fn foo(); //~ ERROR foreign items may not have const parameters + + fn bar(_: T); //~ ERROR foreign items may not have type or const parameters +} + +fn main() {} diff --git a/src/test/ui/const-generics/foreign-item-const-parameter.stderr b/src/test/ui/const-generics/foreign-item-const-parameter.stderr new file mode 100644 index 0000000000000..999feed2d3b20 --- /dev/null +++ b/src/test/ui/const-generics/foreign-item-const-parameter.stderr @@ -0,0 +1,27 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/foreign-item-const-parameter.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0044]: foreign items may not have const parameters + --> $DIR/foreign-item-const-parameter.rs:5:5 + | +LL | fn foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't have const parameters + | + = help: replace the const parameters with concrete consts + +error[E0044]: foreign items may not have type or const parameters + --> $DIR/foreign-item-const-parameter.rs:7:5 + | +LL | fn bar(_: T); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't have type or const parameters + | + = help: replace the type or const parameters with concrete types or consts + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0044`. diff --git a/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr b/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr index 8f3f91651edfb..47b090cb88678 100644 --- a/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr +++ b/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr @@ -11,7 +11,7 @@ LL | struct S; | --------- method `f` not found for this ... LL | S.f::<0>(); - | ^ + | ^ method not found in `S` error[E0107]: wrong number of const arguments: expected 0, found 1 --> $DIR/invalid-const-arg-for-type-param.rs:8:9 diff --git a/src/test/ui/const-generics/issue-60263.rs b/src/test/ui/const-generics/issues/issue-60263.rs similarity index 100% rename from src/test/ui/const-generics/issue-60263.rs rename to src/test/ui/const-generics/issues/issue-60263.rs diff --git a/src/test/ui/const-generics/issue-60263.stderr b/src/test/ui/const-generics/issues/issue-60263.stderr similarity index 100% rename from src/test/ui/const-generics/issue-60263.stderr rename to src/test/ui/const-generics/issues/issue-60263.stderr diff --git a/src/test/ui/const-generics/issue-60818-struct-constructors.rs b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.rs similarity index 100% rename from src/test/ui/const-generics/issue-60818-struct-constructors.rs rename to src/test/ui/const-generics/issues/issue-60818-struct-constructors.rs diff --git a/src/test/ui/const-generics/issue-60818-struct-constructors.stderr b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.stderr similarity index 100% rename from src/test/ui/const-generics/issue-60818-struct-constructors.stderr rename to src/test/ui/const-generics/issues/issue-60818-struct-constructors.stderr diff --git a/src/test/ui/const-generics/issue-61336-1.rs b/src/test/ui/const-generics/issues/issue-61336-1.rs similarity index 100% rename from src/test/ui/const-generics/issue-61336-1.rs rename to src/test/ui/const-generics/issues/issue-61336-1.rs diff --git a/src/test/ui/const-generics/issue-61336-1.stderr b/src/test/ui/const-generics/issues/issue-61336-1.stderr similarity index 100% rename from src/test/ui/const-generics/issue-61336-1.stderr rename to src/test/ui/const-generics/issues/issue-61336-1.stderr diff --git a/src/test/ui/const-generics/issue-61336-2.rs b/src/test/ui/const-generics/issues/issue-61336-2.rs similarity index 100% rename from src/test/ui/const-generics/issue-61336-2.rs rename to src/test/ui/const-generics/issues/issue-61336-2.rs diff --git a/src/test/ui/const-generics/issue-61336-2.stderr b/src/test/ui/const-generics/issues/issue-61336-2.stderr similarity index 100% rename from src/test/ui/const-generics/issue-61336-2.stderr rename to src/test/ui/const-generics/issues/issue-61336-2.stderr diff --git a/src/test/ui/const-generics/issue-61336.rs b/src/test/ui/const-generics/issues/issue-61336.rs similarity index 100% rename from src/test/ui/const-generics/issue-61336.rs rename to src/test/ui/const-generics/issues/issue-61336.rs diff --git a/src/test/ui/const-generics/issue-61336.stderr b/src/test/ui/const-generics/issues/issue-61336.stderr similarity index 100% rename from src/test/ui/const-generics/issue-61336.stderr rename to src/test/ui/const-generics/issues/issue-61336.stderr diff --git a/src/test/ui/const-generics/issue-61422.rs b/src/test/ui/const-generics/issues/issue-61422.rs similarity index 79% rename from src/test/ui/const-generics/issue-61422.rs rename to src/test/ui/const-generics/issues/issue-61422.rs index 68e5a52e0ac5c..45d37b6a2f3c5 100644 --- a/src/test/ui/const-generics/issue-61422.rs +++ b/src/test/ui/const-generics/issues/issue-61422.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash @@ -8,7 +8,7 @@ use std::mem; fn foo() { let arr: [u8; SIZE] = unsafe { #[allow(deprecated)] - let mut array: [u8; SIZE] = mem::uninitialized(); + let array: [u8; SIZE] = mem::uninitialized(); array }; } diff --git a/src/test/ui/const-generics/issue-61422.stderr b/src/test/ui/const-generics/issues/issue-61422.stderr similarity index 100% rename from src/test/ui/const-generics/issue-61422.stderr rename to src/test/ui/const-generics/issues/issue-61422.stderr diff --git a/src/test/ui/const-generics/issues/issue-61432.rs b/src/test/ui/const-generics/issues/issue-61432.rs new file mode 100644 index 0000000000000..832095ce54206 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61432.rs @@ -0,0 +1,17 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +fn promote() { + // works: + // + // let n = N; + // &n; + + &N; +} + +fn main() { + promote::<0>(); +} diff --git a/src/test/ui/const-generics/issues/issue-61432.stderr b/src/test/ui/const-generics/issues/issue-61432.stderr new file mode 100644 index 0000000000000..33f77b028104e --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61432.stderr @@ -0,0 +1,8 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-61432.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs new file mode 100644 index 0000000000000..4dc46eb0ef65a --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs @@ -0,0 +1,16 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +pub trait BitLen: Sized { + const BIT_LEN: usize; +} + +impl BitLen for [u8; L] { + const BIT_LEN: usize = 8 * L; +} + +fn main() { + let foo = <[u8; 2]>::BIT_LEN; +} diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr new file mode 100644 index 0000000000000..20347ac4b7dac --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr @@ -0,0 +1,16 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-62187-encountered-polymorphic-const.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +warning: unused variable: `foo` + --> $DIR/issue-62187-encountered-polymorphic-const.rs:15:9 + | +LL | let foo = <[u8; 2]>::BIT_LEN; + | ^^^ help: consider prefixing with an underscore: `_foo` + | + = note: `#[warn(unused_variables)]` on by default + diff --git a/src/test/ui/const-generics/issues/issue-64519.rs b/src/test/ui/const-generics/issues/issue-64519.rs new file mode 100644 index 0000000000000..72cce9b4843d7 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-64519.rs @@ -0,0 +1,21 @@ +// check-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct Foo { + state: Option<[u8; D]>, +} + +impl Iterator for Foo<{D}> { + type Item = [u8; D]; + fn next(&mut self) -> Option { + if true { + return Some(self.state.unwrap().clone()); + } else { + return Some(self.state.unwrap().clone()); + } + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-64519.stderr b/src/test/ui/const-generics/issues/issue-64519.stderr new file mode 100644 index 0000000000000..d368f39d903a0 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-64519.stderr @@ -0,0 +1,8 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-64519.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.rs b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs new file mode 100644 index 0000000000000..d26ab8be4c3fe --- /dev/null +++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs @@ -0,0 +1,19 @@ +// run-pass +#![feature(const_generics, const_compare_raw_pointers)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +const A: u32 = 3; + +struct Const; + +impl Const<{P}> { + fn get() -> u32 { + unsafe { + *P + } + } +} + +fn main() { + assert_eq!(Const::<{&A as *const _}>::get(), 3) +} diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr b/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr new file mode 100644 index 0000000000000..73221596c8e87 --- /dev/null +++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr @@ -0,0 +1,8 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/raw-ptr-const-param-deref.rs:2:12 + | +LL | #![feature(const_generics, const_compare_raw_pointers)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + diff --git a/src/test/ui/const-generics/raw-ptr-const-param.rs b/src/test/ui/const-generics/raw-ptr-const-param.rs new file mode 100644 index 0000000000000..f69c37fbb8f3d --- /dev/null +++ b/src/test/ui/const-generics/raw-ptr-const-param.rs @@ -0,0 +1,9 @@ +#![feature(const_generics, const_compare_raw_pointers)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct Const; + +fn main() { + let _: Const<{15 as *const _}> = Const::<{10 as *const _}>; //~ mismatched types + let _: Const<{10 as *const _}> = Const::<{10 as *const _}>; +} diff --git a/src/test/ui/const-generics/raw-ptr-const-param.stderr b/src/test/ui/const-generics/raw-ptr-const-param.stderr new file mode 100644 index 0000000000000..75b4c0a0a3de3 --- /dev/null +++ b/src/test/ui/const-generics/raw-ptr-const-param.stderr @@ -0,0 +1,20 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/raw-ptr-const-param.rs:1:12 + | +LL | #![feature(const_generics, const_compare_raw_pointers)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/raw-ptr-const-param.rs:7:38 + | +LL | let _: Const<{15 as *const _}> = Const::<{10 as *const _}>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{pointer}`, found `{pointer}` + | + = note: expected type `Const<{pointer}>` + found type `Const<{pointer}>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/slice-const-param-mismatch.rs b/src/test/ui/const-generics/slice-const-param-mismatch.rs new file mode 100644 index 0000000000000..73c75ae666805 --- /dev/null +++ b/src/test/ui/const-generics/slice-const-param-mismatch.rs @@ -0,0 +1,14 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct ConstString; +struct ConstBytes; + +pub fn main() { + let _: ConstString<"Hello"> = ConstString::<"Hello">; + let _: ConstString<"Hello"> = ConstString::<"World">; //~ ERROR mismatched types + let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↦">; + let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; //~ ERROR mismatched types + let _: ConstBytes = ConstBytes::<{&[0x41, 0x41, 0x41]}>; + let _: ConstBytes = ConstBytes::; //~ ERROR mismatched types +} diff --git a/src/test/ui/const-generics/slice-const-param-mismatch.stderr b/src/test/ui/const-generics/slice-const-param-mismatch.stderr new file mode 100644 index 0000000000000..380a70d664e05 --- /dev/null +++ b/src/test/ui/const-generics/slice-const-param-mismatch.stderr @@ -0,0 +1,38 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/slice-const-param-mismatch.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/slice-const-param-mismatch.rs:9:35 + | +LL | let _: ConstString<"Hello"> = ConstString::<"World">; + | ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"` + | + = note: expected type `ConstString<"Hello">` + found type `ConstString<"World">` + +error[E0308]: mismatched types + --> $DIR/slice-const-param-mismatch.rs:11:33 + | +LL | let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; + | ^^^^^^^^^^^^^^^^^^^^^ expected `"ℇ㇈↦"`, found `"ℇ㇈↥"` + | + = note: expected type `ConstString<"ℇ㇈↦">` + found type `ConstString<"ℇ㇈↥">` + +error[E0308]: mismatched types + --> $DIR/slice-const-param-mismatch.rs:13:33 + | +LL | let _: ConstBytes = ConstBytes::; + | ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"` + | + = note: expected type `ConstBytes` + found type `ConstBytes` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/slice-const-param.rs b/src/test/ui/const-generics/slice-const-param.rs new file mode 100644 index 0000000000000..2629caa392106 --- /dev/null +++ b/src/test/ui/const-generics/slice-const-param.rs @@ -0,0 +1,19 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +pub fn function_with_str() -> &'static str { + STRING +} + +pub fn function_with_bytes() -> &'static [u8] { + BYTES +} + +pub fn main() { + assert_eq!(function_with_str::<"Rust">(), "Rust"); + assert_eq!(function_with_str::<"ℇ㇈↦">(), "ℇ㇈↦"); + assert_eq!(function_with_bytes::(), &[0x41, 0x41, 0x41, 0x41]); + assert_eq!(function_with_bytes::<{&[0x41, 0x41, 0x41, 0x41]}>(), b"AAAA"); +} diff --git a/src/test/ui/const-generics/slice-const-param.stderr b/src/test/ui/const-generics/slice-const-param.stderr new file mode 100644 index 0000000000000..79214a34fdba0 --- /dev/null +++ b/src/test/ui/const-generics/slice-const-param.stderr @@ -0,0 +1,8 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/slice-const-param.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + diff --git a/src/test/ui/const-generics/types-mismatch-const-args.rs b/src/test/ui/const-generics/types-mismatch-const-args.rs new file mode 100644 index 0000000000000..b25b7331017e7 --- /dev/null +++ b/src/test/ui/const-generics/types-mismatch-const-args.rs @@ -0,0 +1,19 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +// tests the diagnostic output of type mismatches for types that have const generics arguments. + +use std::marker::PhantomData; + +struct A<'a, T, const X: u32, const Y: u32> { + data: PhantomData<&'a T> +} + +fn a<'a, 'b>() { + let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData }; + //~^ ERROR mismatched types + let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData }; + //~^ ERROR mismatched types +} + +pub fn main() {} diff --git a/src/test/ui/const-generics/types-mismatch-const-args.stderr b/src/test/ui/const-generics/types-mismatch-const-args.stderr new file mode 100644 index 0000000000000..805a3067d3b6b --- /dev/null +++ b/src/test/ui/const-generics/types-mismatch-const-args.stderr @@ -0,0 +1,29 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/types-mismatch-const-args.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/types-mismatch-const-args.rs:13:41 + | +LL | let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2u32`, found `4u32` + | + = note: expected type `A<'_, _, 2u32, _>` + found type `A<'_, _, 4u32, _>` + +error[E0308]: mismatched types + --> $DIR/types-mismatch-const-args.rs:15:41 + | +LL | let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u16, found u32 + | + = note: expected type `A<'a, u16, _, _>` + found type `A<'b, u32, _, _>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/unused-const-param.rs b/src/test/ui/const-generics/unused-const-param.rs index ee98e5eb4a01f..8025b3af8f1bf 100644 --- a/src/test/ui/const-generics/unused-const-param.rs +++ b/src/test/ui/const-generics/unused-const-param.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash diff --git a/src/test/ui/consts/array-literal-index-oob.rs b/src/test/ui/consts/array-literal-index-oob.rs index 76013c77de0c2..492182921ba34 100644 --- a/src/test/ui/consts/array-literal-index-oob.rs +++ b/src/test/ui/consts/array-literal-index-oob.rs @@ -2,5 +2,4 @@ fn main() { &{[1, 2, 3][4]}; //~^ ERROR index out of bounds //~| ERROR reaching this expression at runtime will panic or abort - //~| ERROR this expression will panic at runtime } diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr index 18a09fdda7be4..0ddc2a0e79cd3 100644 --- a/src/test/ui/consts/array-literal-index-oob.stderr +++ b/src/test/ui/consts/array-literal-index-oob.stderr @@ -6,12 +6,6 @@ LL | &{[1, 2, 3][4]}; | = note: `#[deny(const_err)]` on by default -error: this expression will panic at runtime - --> $DIR/array-literal-index-oob.rs:2:5 - | -LL | &{[1, 2, 3][4]}; - | ^^^^^^^^^^^^^^^ index out of bounds: the len is 3 but the index is 4 - error: reaching this expression at runtime will panic or abort --> $DIR/array-literal-index-oob.rs:2:7 | @@ -20,5 +14,5 @@ LL | &{[1, 2, 3][4]}; | | | index out of bounds: the len is 3 but the index is 4 -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/auxiliary/issue-63226.rs b/src/test/ui/consts/auxiliary/issue-63226.rs new file mode 100644 index 0000000000000..39cc01a415e9a --- /dev/null +++ b/src/test/ui/consts/auxiliary/issue-63226.rs @@ -0,0 +1,14 @@ +pub struct VTable{ + state:extern fn(), +} + +impl VTable{ + pub const fn vtable()->&'static VTable{ + Self::VTABLE + } + + const VTABLE: &'static VTable = + &VTable{state}; +} + +extern fn state() {} diff --git a/src/test/ui/consts/const-err2.rs b/src/test/ui/consts/const-err2.rs index a5f685a159b39..ecbcc2a4b496f 100644 --- a/src/test/ui/consts/const-err2.rs +++ b/src/test/ui/consts/const-err2.rs @@ -5,6 +5,7 @@ #![feature(rustc_attrs)] #![allow(exceeding_bitshifts)] + #![deny(const_err)] fn black_box(_: T) { @@ -21,7 +22,7 @@ fn main() { let d = 42u8 - (42u8 + 1); //~^ ERROR const_err let _e = [5u8][1]; - //~^ ERROR const_err + //~^ ERROR index out of bounds black_box(a); black_box(b); black_box(c); diff --git a/src/test/ui/consts/const-err2.stderr b/src/test/ui/consts/const-err2.stderr index 659c3afc618a9..1d84d44dc27b3 100644 --- a/src/test/ui/consts/const-err2.stderr +++ b/src/test/ui/consts/const-err2.stderr @@ -1,35 +1,35 @@ error: this expression will panic at runtime - --> $DIR/const-err2.rs:15:13 + --> $DIR/const-err2.rs:16:13 | LL | let a = -std::i8::MIN; | ^^^^^^^^^^^^^ attempt to negate with overflow | note: lint level defined here - --> $DIR/const-err2.rs:8:9 + --> $DIR/const-err2.rs:9:9 | LL | #![deny(const_err)] | ^^^^^^^^^ error: this expression will panic at runtime - --> $DIR/const-err2.rs:17:13 + --> $DIR/const-err2.rs:18:13 | LL | let b = 200u8 + 200u8 + 200u8; | ^^^^^^^^^^^^^ attempt to add with overflow error: this expression will panic at runtime - --> $DIR/const-err2.rs:19:13 + --> $DIR/const-err2.rs:20:13 | LL | let c = 200u8 * 4; | ^^^^^^^^^ attempt to multiply with overflow error: this expression will panic at runtime - --> $DIR/const-err2.rs:21:13 + --> $DIR/const-err2.rs:22:13 | LL | let d = 42u8 - (42u8 + 1); | ^^^^^^^^^^^^^^^^^ attempt to subtract with overflow error: index out of bounds: the len is 1 but the index is 1 - --> $DIR/const-err2.rs:23:14 + --> $DIR/const-err2.rs:24:14 | LL | let _e = [5u8][1]; | ^^^^^^^^ diff --git a/src/test/ui/consts/const-err3.rs b/src/test/ui/consts/const-err3.rs new file mode 100644 index 0000000000000..a9cf04cda7a5a --- /dev/null +++ b/src/test/ui/consts/const-err3.rs @@ -0,0 +1,30 @@ +// needed because negating int::MIN will behave differently between +// optimized compilation and unoptimized compilation and thus would +// lead to different lints being emitted +// compile-flags: -C overflow-checks=on -O + +#![feature(rustc_attrs)] +#![allow(exceeding_bitshifts)] + +#![deny(const_err)] + +fn black_box(_: T) { + unimplemented!() +} + +fn main() { + let a = -std::i8::MIN; + //~^ ERROR const_err + let b = 200u8 + 200u8 + 200u8; + //~^ ERROR const_err + let c = 200u8 * 4; + //~^ ERROR const_err + let d = 42u8 - (42u8 + 1); + //~^ ERROR const_err + let _e = [5u8][1]; + //~^ ERROR const_err + black_box(a); + black_box(b); + black_box(c); + black_box(d); +} diff --git a/src/test/ui/consts/const-err3.stderr b/src/test/ui/consts/const-err3.stderr new file mode 100644 index 0000000000000..0602707be7040 --- /dev/null +++ b/src/test/ui/consts/const-err3.stderr @@ -0,0 +1,38 @@ +error: attempt to negate with overflow + --> $DIR/const-err3.rs:16:13 + | +LL | let a = -std::i8::MIN; + | ^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/const-err3.rs:9:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + +error: attempt to add with overflow + --> $DIR/const-err3.rs:18:13 + | +LL | let b = 200u8 + 200u8 + 200u8; + | ^^^^^^^^^^^^^ + +error: attempt to multiply with overflow + --> $DIR/const-err3.rs:20:13 + | +LL | let c = 200u8 * 4; + | ^^^^^^^^^ + +error: attempt to subtract with overflow + --> $DIR/const-err3.rs:22:13 + | +LL | let d = 42u8 - (42u8 + 1); + | ^^^^^^^^^^^^^^^^^ + +error: index out of bounds: the len is 1 but the index is 1 + --> $DIR/const-err3.rs:24:14 + | +LL | let _e = [5u8][1]; + | ^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/consts/const-err4.stderr b/src/test/ui/consts/const-err4.stderr index 1feec3c21c0a5..081b09e33006f 100644 --- a/src/test/ui/consts/const-err4.stderr +++ b/src/test/ui/consts/const-err4.stderr @@ -4,7 +4,7 @@ error[E0080]: it is undefined behavior to use this value LL | Boo = [unsafe { Foo { b: () }.a }; 4][3], | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.rs b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.rs index cc5ddb4401644..a2196db780ce0 100644 --- a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.rs +++ b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.rs @@ -1,5 +1,6 @@ // only-x86_64 +#[repr(C)] union Nonsense { u: usize, int_32_ref: &'static i32, diff --git a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr index 73aca911531f1..e0df787f80a44 100644 --- a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr +++ b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr @@ -1,13 +1,13 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:24:5 + --> $DIR/const-pointer-values-in-various-types.rs:25:5 | LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:27:43 + --> $DIR/const-pointer-values-in-various-types.rs:28:43 | LL | const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -17,7 +17,7 @@ LL | const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_ = note: `#[deny(const_err)]` on by default error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:30:45 + --> $DIR/const-pointer-values-in-various-types.rs:31:45 | LL | const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 }; | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -25,7 +25,7 @@ LL | const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uin | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:33:45 + --> $DIR/const-pointer-values-in-various-types.rs:34:45 | LL | const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 }; | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -33,23 +33,23 @@ LL | const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uin | a raw memory access tried to access part of a pointer value as raw bytes error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:36:5 + --> $DIR/const-pointer-values-in-various-types.rs:37:5 | LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:39:5 + --> $DIR/const-pointer-values-in-various-types.rs:40:5 | LL | const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:42:43 + --> $DIR/const-pointer-values-in-various-types.rs:43:43 | LL | const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -57,7 +57,7 @@ LL | const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:45:45 + --> $DIR/const-pointer-values-in-various-types.rs:46:45 | LL | const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 }; | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -65,7 +65,7 @@ LL | const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:48:45 + --> $DIR/const-pointer-values-in-various-types.rs:49:45 | LL | const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 }; | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -73,23 +73,23 @@ LL | const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int | a raw memory access tried to access part of a pointer value as raw bytes error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:51:5 + --> $DIR/const-pointer-values-in-various-types.rs:52:5 | LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:54:5 + --> $DIR/const-pointer-values-in-various-types.rs:55:5 | LL | const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:57:45 + --> $DIR/const-pointer-values-in-various-types.rs:58:45 | LL | const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 }; | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -97,15 +97,15 @@ LL | const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.flo | a raw memory access tried to access part of a pointer value as raw bytes error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:60:5 + --> $DIR/const-pointer-values-in-various-types.rs:61:5 | LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:63:47 + --> $DIR/const-pointer-values-in-various-types.rs:64:47 | LL | const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey }; | ------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -113,7 +113,7 @@ LL | const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.t | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:66:47 + --> $DIR/const-pointer-values-in-various-types.rs:67:47 | LL | const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character }; | ------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -121,7 +121,7 @@ LL | const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.c | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:69:39 + --> $DIR/const-pointer-values-in-various-types.rs:70:39 | LL | const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 }; | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -129,7 +129,7 @@ LL | const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 }; | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:72:41 + --> $DIR/const-pointer-values-in-various-types.rs:73:41 | LL | const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 }; | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -137,7 +137,7 @@ LL | const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 } | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:75:41 + --> $DIR/const-pointer-values-in-various-types.rs:76:41 | LL | const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 }; | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -145,15 +145,15 @@ LL | const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 } | a raw memory access tried to access part of a pointer value as raw bytes error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:78:5 + --> $DIR/const-pointer-values-in-various-types.rs:79:5 | LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:81:43 + --> $DIR/const-pointer-values-in-various-types.rs:82:43 | LL | const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -161,7 +161,7 @@ LL | const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_12 | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:84:39 + --> $DIR/const-pointer-values-in-various-types.rs:85:39 | LL | const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 }; | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -169,7 +169,7 @@ LL | const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 }; | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:87:41 + --> $DIR/const-pointer-values-in-various-types.rs:88:41 | LL | const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 }; | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -177,7 +177,7 @@ LL | const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 }; | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:90:41 + --> $DIR/const-pointer-values-in-various-types.rs:91:41 | LL | const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 }; | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -185,15 +185,15 @@ LL | const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 }; | a raw memory access tried to access part of a pointer value as raw bytes error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:93:5 + --> $DIR/const-pointer-values-in-various-types.rs:94:5 | LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:96:43 + --> $DIR/const-pointer-values-in-various-types.rs:97:43 | LL | const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -201,7 +201,7 @@ LL | const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:99:41 + --> $DIR/const-pointer-values-in-various-types.rs:100:41 | LL | const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 }; | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -209,15 +209,15 @@ LL | const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 | a raw memory access tried to access part of a pointer value as raw bytes error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:102:5 + --> $DIR/const-pointer-values-in-various-types.rs:103:5 | LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:105:43 + --> $DIR/const-pointer-values-in-various-types.rs:106:43 | LL | const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -225,7 +225,7 @@ LL | const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_ | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:108:43 + --> $DIR/const-pointer-values-in-various-types.rs:109:43 | LL | const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- diff --git a/src/test/ui/consts/const-eval/const_fn_ptr.rs b/src/test/ui/consts/const-eval/const_fn_ptr.rs new file mode 100644 index 0000000000000..498f801db81b8 --- /dev/null +++ b/src/test/ui/consts/const-eval/const_fn_ptr.rs @@ -0,0 +1,37 @@ +// run-pass +// compile-flags: -Zunleash-the-miri-inside-of-you +#![feature(const_fn)] + +fn double(x: usize) -> usize { x * 2 } +const fn double_const(x: usize) -> usize { x * 2 } + +const X: fn(usize) -> usize = double; +const X_const: fn(usize) -> usize = double_const; + +const fn bar(x: usize) -> usize { + X(x) +} + +const fn bar_const(x: usize) -> usize { + X_const(x) +} + +const fn foo(x: fn(usize) -> usize, y: usize) -> usize { + x(y) +} + +fn main() { + const Y: usize = bar_const(2); + assert_eq!(Y, 4); + let y = bar_const(2); + assert_eq!(y, 4); + let y = bar(2); + assert_eq!(y, 4); + + const Z: usize = foo(double_const, 2); + assert_eq!(Z, 4); + let z = foo(double_const, 2); + assert_eq!(z, 4); + let z = foo(double, 2); + assert_eq!(z, 4); +} diff --git a/src/test/ui/consts/const-eval/const_fn_ptr.stderr b/src/test/ui/consts/const-eval/const_fn_ptr.stderr new file mode 100644 index 0000000000000..2fbb19322442b --- /dev/null +++ b/src/test/ui/consts/const-eval/const_fn_ptr.stderr @@ -0,0 +1,26 @@ +warning: skipping const checks + --> $DIR/const_fn_ptr.rs:12:5 + | +LL | X(x) + | ^^^^ + +warning: skipping const checks + --> $DIR/const_fn_ptr.rs:16:5 + | +LL | X_const(x) + | ^^^^^^^^^^ + +warning: skipping const checks + --> $DIR/const_fn_ptr.rs:20:5 + | +LL | x(y) + | ^^^^ + +warning: constant `X_const` should have an upper case name + --> $DIR/const_fn_ptr.rs:9:7 + | +LL | const X_const: fn(usize) -> usize = double_const; + | ^^^^^^^ help: convert the identifier to upper case: `X_CONST` + | + = note: `#[warn(non_upper_case_globals)]` on by default + diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail.rs b/src/test/ui/consts/const-eval/const_fn_ptr_fail.rs new file mode 100644 index 0000000000000..90d3cba07a598 --- /dev/null +++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail.rs @@ -0,0 +1,14 @@ +// run-pass +// compile-flags: -Zunleash-the-miri-inside-of-you +#![feature(const_fn)] +#![allow(unused)] + +fn double(x: usize) -> usize { x * 2 } +const X: fn(usize) -> usize = double; + +const fn bar(x: usize) -> usize { + X(x) // FIXME: this should error someday + //~^ WARN: skipping const checks +} + +fn main() {} diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr new file mode 100644 index 0000000000000..e80f363ff8be4 --- /dev/null +++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr @@ -0,0 +1,6 @@ +warning: skipping const checks + --> $DIR/const_fn_ptr_fail.rs:10:5 + | +LL | X(x) // FIXME: this should error someday + | ^^^^ + diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs new file mode 100644 index 0000000000000..b300119509ce4 --- /dev/null +++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs @@ -0,0 +1,20 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +#![feature(const_fn)] +#![allow(const_err)] + +fn double(x: usize) -> usize { x * 2 } +const X: fn(usize) -> usize = double; + +const fn bar(x: fn(usize) -> usize, y: usize) -> usize { + x(y) //~ WARN skipping const checks +} + +const Y: usize = bar(X, 2); // FIXME: should fail to typeck someday +const Z: usize = bar(double, 2); // FIXME: should fail to typeck someday + +fn main() { + assert_eq!(Y, 4); + //~^ ERROR evaluation of constant expression failed + assert_eq!(Z, 4); + //~^ ERROR evaluation of constant expression failed +} diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr new file mode 100644 index 0000000000000..9d74d3b0bf229 --- /dev/null +++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr @@ -0,0 +1,29 @@ +warning: skipping const checks + --> $DIR/const_fn_ptr_fail2.rs:9:5 + | +LL | x(y) + | ^^^^ + +error[E0080]: evaluation of constant expression failed + --> $DIR/const_fn_ptr_fail2.rs:16:5 + | +LL | assert_eq!(Y, 4); + | ^^^^^^^^^^^-^^^^^ + | | + | referenced constant has errors + | + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error[E0080]: evaluation of constant expression failed + --> $DIR/const_fn_ptr_fail2.rs:18:5 + | +LL | assert_eq!(Z, 4); + | ^^^^^^^^^^^-^^^^^ + | | + | referenced constant has errors + | + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/const_let.stderr b/src/test/ui/consts/const-eval/const_let.stderr index 0a6a222ae2963..4753222a7c07d 100644 --- a/src/test/ui/consts/const-eval/const_let.stderr +++ b/src/test/ui/consts/const-eval/const_let.stderr @@ -24,3 +24,4 @@ LL | const Z2: () = { let mut x; x = None; x = Some(FakeNeedsDrop); }; error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/const-eval/const_transmute.rs b/src/test/ui/consts/const-eval/const_transmute.rs index 0e0e003dcf476..f0e1d8263022b 100644 --- a/src/test/ui/consts/const-eval/const_transmute.rs +++ b/src/test/ui/consts/const-eval/const_transmute.rs @@ -1,7 +1,9 @@ // run-pass #![feature(const_fn_union)] +#![allow(dead_code)] +#[repr(C)] union Transmute { t: T, u: U, diff --git a/src/test/ui/consts/const-eval/dangling.rs b/src/test/ui/consts/const-eval/dangling.rs new file mode 100644 index 0000000000000..b5d72d46f2861 --- /dev/null +++ b/src/test/ui/consts/const-eval/dangling.rs @@ -0,0 +1,13 @@ +#![feature(const_transmute, const_raw_ptr_deref)] + +use std::{mem, usize}; + +// Make sure we error with the right kind of error on a too large slice. +const TEST: () = { unsafe { //~ NOTE + let slice: *const [u8] = mem::transmute((1usize, usize::MAX)); + let _val = &*slice; //~ ERROR: any use of this value will cause an error + //~^ NOTE: total size is bigger than largest supported object + //~^^ on by default +} }; + +fn main() {} diff --git a/src/test/ui/consts/const-eval/dangling.stderr b/src/test/ui/consts/const-eval/dangling.stderr new file mode 100644 index 0000000000000..286de08009754 --- /dev/null +++ b/src/test/ui/consts/const-eval/dangling.stderr @@ -0,0 +1,16 @@ +error: any use of this value will cause an error + --> $DIR/dangling.rs:8:16 + | +LL | / const TEST: () = { unsafe { +LL | | let slice: *const [u8] = mem::transmute((1usize, usize::MAX)); +LL | | let _val = &*slice; + | | ^^^^^^^ invalid slice: total size is bigger than largest supported object +LL | | +LL | | +LL | | } }; + | |____- + | + = note: `#[deny(const_err)]` on by default + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-eval/double_check.rs b/src/test/ui/consts/const-eval/double_check.rs index 2cf6a5494dd8d..ff2fff7fb790e 100644 --- a/src/test/ui/consts/const-eval/double_check.rs +++ b/src/test/ui/consts/const-eval/double_check.rs @@ -8,6 +8,7 @@ enum Bar { C = 42, D = 99, } +#[repr(C)] union Union { foo: &'static Foo, bar: &'static Bar, diff --git a/src/test/ui/consts/const-eval/double_check2.rs b/src/test/ui/consts/const-eval/double_check2.rs index dc2b58faf9215..7c222b113cd7d 100644 --- a/src/test/ui/consts/const-eval/double_check2.rs +++ b/src/test/ui/consts/const-eval/double_check2.rs @@ -6,6 +6,7 @@ enum Bar { C = 42, D = 99, } +#[repr(C)] union Union { foo: &'static Foo, bar: &'static Bar, diff --git a/src/test/ui/consts/const-eval/double_check2.stderr b/src/test/ui/consts/const-eval/double_check2.stderr index 2b61d33852c98..28e0922ecafa6 100644 --- a/src/test/ui/consts/const-eval/double_check2.stderr +++ b/src/test/ui/consts/const-eval/double_check2.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/double_check2.rs:15:1 + --> $DIR/double_check2.rs:16:1 | LL | / static FOO: (&Foo, &Bar) = unsafe {( LL | | Union { u8: &BAR }.foo, @@ -7,7 +7,7 @@ LL | | Union { u8: &BAR }.bar, LL | | )}; | |___^ type validation failed: encountered 5 at .1., but expected a valid enum discriminant | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs index b0ae746ace58d..3f7bab065869a 100644 --- a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs +++ b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs @@ -2,6 +2,7 @@ fn main() {} +#[repr(C)] union Foo { u: u32, i: i32, diff --git a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr index 5bf43cb8b6add..6899b7b82c532 100644 --- a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr +++ b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr @@ -1,5 +1,5 @@ error[E0658]: unions in const fn are unstable - --> $DIR/feature-gate-const_fn_union.rs:11:5 + --> $DIR/feature-gate-const_fn_union.rs:12:5 | LL | Foo { u }.i | ^^^^^^^^^^^ diff --git a/src/test/ui/consts/const-eval/generic-slice.rs b/src/test/ui/consts/const-eval/generic-slice.rs new file mode 100644 index 0000000000000..21360a1c471f6 --- /dev/null +++ b/src/test/ui/consts/const-eval/generic-slice.rs @@ -0,0 +1,31 @@ +// Several variants of #64945. + +// This struct is not important, we just use it to put `T` and `'a` in scope for our associated +// consts. +struct Generic<'a, T>(std::marker::PhantomData<&'a T>); + +impl<'a, T: 'static> Generic<'a, T> { + const EMPTY_SLICE: &'a [T] = { + let x: &'a [T] = &[]; + x + }; + + const EMPTY_SLICE_REF: &'a &'static [T] = { + let x: &'static [T] = &[]; + &x + //~^ ERROR `x` does not live long enough + }; +} + +static mut INTERIOR_MUT_AND_DROP: &'static [std::cell::RefCell>] = { + let x: &[_] = &[]; + x +}; + +static mut INTERIOR_MUT_AND_DROP_REF: &'static &'static [std::cell::RefCell>] = { + let x: &[_] = &[]; + &x + //~^ ERROR `x` does not live long enough +}; + +fn main() {} diff --git a/src/test/ui/consts/const-eval/generic-slice.stderr b/src/test/ui/consts/const-eval/generic-slice.stderr new file mode 100644 index 0000000000000..c38088df4d8e6 --- /dev/null +++ b/src/test/ui/consts/const-eval/generic-slice.stderr @@ -0,0 +1,30 @@ +error[E0597]: `x` does not live long enough + --> $DIR/generic-slice.rs:15:9 + | +LL | impl<'a, T: 'static> Generic<'a, T> { + | -- lifetime `'a` defined here +... +LL | &x + | ^^ + | | + | borrowed value does not live long enough + | using this value as a constant requires that `x` is borrowed for `'a` +LL | +LL | }; + | - `x` dropped here while still borrowed + +error[E0597]: `x` does not live long enough + --> $DIR/generic-slice.rs:27:5 + | +LL | &x + | ^^ + | | + | borrowed value does not live long enough + | using this value as a static requires that `x` is borrowed for `'static` +LL | +LL | }; + | - `x` dropped here while still borrowed + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/consts/const-eval/issue-43197.stderr b/src/test/ui/consts/const-eval/issue-43197.stderr index 478e453fe0834..d971d825f278c 100644 --- a/src/test/ui/consts/const-eval/issue-43197.stderr +++ b/src/test/ui/consts/const-eval/issue-43197.stderr @@ -21,16 +21,16 @@ LL | const Y: u32 = foo(0-1); | attempt to subtract with overflow error[E0080]: evaluation of constant expression failed - --> $DIR/issue-43197.rs:12:26 + --> $DIR/issue-43197.rs:12:23 | LL | println!("{} {}", X, Y); - | ^ referenced constant has errors + | ^ referenced constant has errors error[E0080]: evaluation of constant expression failed - --> $DIR/issue-43197.rs:12:23 + --> $DIR/issue-43197.rs:12:26 | LL | println!("{} {}", X, Y); - | ^ referenced constant has errors + | ^ referenced constant has errors error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-eval/issue-49296.rs b/src/test/ui/consts/const-eval/issue-49296.rs index a7c3c5318d430..c6caeeffd22dd 100644 --- a/src/test/ui/consts/const-eval/issue-49296.rs +++ b/src/test/ui/consts/const-eval/issue-49296.rs @@ -4,6 +4,7 @@ #![feature(const_fn_union)] const unsafe fn transmute(t: T) -> U { + #[repr(C)] union Transmute { from: T, to: U, diff --git a/src/test/ui/consts/const-eval/issue-49296.stderr b/src/test/ui/consts/const-eval/issue-49296.stderr index 7a4bba8daa70b..48809e0ae649c 100644 --- a/src/test/ui/consts/const-eval/issue-49296.stderr +++ b/src/test/ui/consts/const-eval/issue-49296.stderr @@ -1,5 +1,5 @@ error: any use of this value will cause an error - --> $DIR/issue-49296.rs:18:16 + --> $DIR/issue-49296.rs:19:16 | LL | const X: u64 = *wat(42); | ---------------^^^^^^^^- diff --git a/src/test/ui/consts/const-eval/issue-64908.rs b/src/test/ui/consts/const-eval/issue-64908.rs new file mode 100644 index 0000000000000..d2e095072844f --- /dev/null +++ b/src/test/ui/consts/const-eval/issue-64908.rs @@ -0,0 +1,20 @@ +// run-pass + +// This test verifies that the `ConstProp` pass doesn't cause an ICE when evaluating polymorphic +// promoted MIR. + +pub trait ArrowPrimitiveType { + type Native; +} + +pub fn new() { + assert_eq!(0, std::mem::size_of::()); +} + +impl ArrowPrimitiveType for () { + type Native = (); +} + +fn main() { + new::<()>(); +} diff --git a/src/test/ui/consts/const-eval/issue-64970.rs b/src/test/ui/consts/const-eval/issue-64970.rs new file mode 100644 index 0000000000000..ede5081c8a5c2 --- /dev/null +++ b/src/test/ui/consts/const-eval/issue-64970.rs @@ -0,0 +1,15 @@ +// run-pass + +fn main() { + foo(10); +} + +fn foo(mut n: i32) { + if false { + n = 0i32; + } + + if n > 0i32 { + 1i32 / n; + } +} diff --git a/src/test/ui/consts/const-eval/issue-64970.stderr b/src/test/ui/consts/const-eval/issue-64970.stderr new file mode 100644 index 0000000000000..2c44b68cbd1d1 --- /dev/null +++ b/src/test/ui/consts/const-eval/issue-64970.stderr @@ -0,0 +1,8 @@ +warning: unused arithmetic operation that must be used + --> $DIR/issue-64970.rs:13:9 + | +LL | 1i32 / n; + | ^^^^^^^^ + | + = note: `#[warn(unused_must_use)]` on by default + diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs b/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs index 88181cb86100f..3edd4e086867b 100644 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs @@ -2,6 +2,7 @@ #![allow(const_err)] +#[repr(C)] union Bar { a: &'static u8, b: usize, diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr b/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr index 519ba7d84b087..6618f1cd1c0b5 100644 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted_const_fn_fail.rs:20:27 + --> $DIR/promoted_const_fn_fail.rs:21:27 | LL | let x: &'static u8 = &(bar() + 1); | ----------- ^^^^^^^^^^^ creates a temporary which is freed while still in use diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs index 061ab7eeb029d..7887e42653464 100644 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs @@ -2,6 +2,7 @@ #![deny(const_err)] +#[repr(C)] union Bar { a: &'static u8, b: usize, diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr index 987d2304ae871..5f9f3bda87b15 100644 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted_const_fn_fail_deny_const_err.rs:21:27 + --> $DIR/promoted_const_fn_fail_deny_const_err.rs:22:27 | LL | let x: &'static u8 = &(bar() + 1); | ----------- ^^^^^^^^^^^ creates a temporary which is freed while still in use diff --git a/src/test/ui/consts/const-eval/promoted_errors.rs b/src/test/ui/consts/const-eval/promoted_errors.rs index fa8859cbb3bb6..45941398f4b66 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.rs +++ b/src/test/ui/consts/const-eval/promoted_errors.rs @@ -5,17 +5,15 @@ fn main() { println!("{}", 0u32 - 1); let _x = 0u32 - 1; - //~^ ERROR this expression will panic at runtime [const_err] + //~^ ERROR const_err println!("{}", 1/(1-1)); - //~^ ERROR this expression will panic at runtime [const_err] - //~| ERROR attempt to divide by zero [const_err] + //~^ ERROR attempt to divide by zero [const_err] //~| ERROR reaching this expression at runtime will panic or abort [const_err] let _x = 1/(1-1); //~^ ERROR const_err //~| ERROR const_err println!("{}", 1/(false as u32)); - //~^ ERROR this expression will panic at runtime [const_err] - //~| ERROR attempt to divide by zero [const_err] + //~^ ERROR attempt to divide by zero [const_err] //~| ERROR reaching this expression at runtime will panic or abort [const_err] let _x = 1/(false as u32); //~^ ERROR const_err diff --git a/src/test/ui/consts/const-eval/promoted_errors.stderr b/src/test/ui/consts/const-eval/promoted_errors.stderr index 12407accf096f..40d5c73e86679 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.stderr @@ -16,59 +16,47 @@ error: attempt to divide by zero LL | println!("{}", 1/(1-1)); | ^^^^^^^ -error: this expression will panic at runtime +error: reaching this expression at runtime will panic or abort --> $DIR/promoted_errors.rs:9:20 | LL | println!("{}", 1/(1-1)); | ^^^^^^^ attempt to divide by zero error: attempt to divide by zero - --> $DIR/promoted_errors.rs:13:14 + --> $DIR/promoted_errors.rs:12:14 | LL | let _x = 1/(1-1); | ^^^^^^^ error: this expression will panic at runtime - --> $DIR/promoted_errors.rs:13:14 + --> $DIR/promoted_errors.rs:12:14 | LL | let _x = 1/(1-1); | ^^^^^^^ attempt to divide by zero error: attempt to divide by zero - --> $DIR/promoted_errors.rs:16:20 + --> $DIR/promoted_errors.rs:15:20 | LL | println!("{}", 1/(false as u32)); | ^^^^^^^^^^^^^^^^ -error: this expression will panic at runtime - --> $DIR/promoted_errors.rs:16:20 +error: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors.rs:15:20 | LL | println!("{}", 1/(false as u32)); | ^^^^^^^^^^^^^^^^ attempt to divide by zero error: attempt to divide by zero - --> $DIR/promoted_errors.rs:20:14 + --> $DIR/promoted_errors.rs:18:14 | LL | let _x = 1/(false as u32); | ^^^^^^^^^^^^^^^^ error: this expression will panic at runtime - --> $DIR/promoted_errors.rs:20:14 + --> $DIR/promoted_errors.rs:18:14 | LL | let _x = 1/(false as u32); | ^^^^^^^^^^^^^^^^ attempt to divide by zero -error: reaching this expression at runtime will panic or abort - --> $DIR/promoted_errors.rs:16:20 - | -LL | println!("{}", 1/(false as u32)); - | ^^^^^^^^^^^^^^^^ attempt to divide by zero - -error: reaching this expression at runtime will panic or abort - --> $DIR/promoted_errors.rs:9:20 - | -LL | println!("{}", 1/(1-1)); - | ^^^^^^^ attempt to divide by zero - -error: aborting due to 11 previous errors +error: aborting due to 9 previous errors diff --git a/src/test/ui/consts/const-eval/promoted_errors2.rs b/src/test/ui/consts/const-eval/promoted_errors2.rs new file mode 100644 index 0000000000000..7adb394144bdd --- /dev/null +++ b/src/test/ui/consts/const-eval/promoted_errors2.rs @@ -0,0 +1,22 @@ +// compile-flags: -C overflow-checks=on -O + +#![deny(const_err)] + +fn main() { + println!("{}", 0u32 - 1); + //~^ ERROR attempt to subtract with overflow + let _x = 0u32 - 1; + //~^ ERROR attempt to subtract with overflow + println!("{}", 1/(1-1)); + //~^ ERROR attempt to divide by zero [const_err] + //~| ERROR reaching this expression at runtime will panic or abort [const_err] + let _x = 1/(1-1); + //~^ ERROR const_err + //~| ERROR const_err + println!("{}", 1/(false as u32)); + //~^ ERROR attempt to divide by zero [const_err] + //~| ERROR reaching this expression at runtime will panic or abort [const_err] + let _x = 1/(false as u32); + //~^ ERROR const_err + //~| ERROR const_err +} diff --git a/src/test/ui/consts/const-eval/promoted_errors2.stderr b/src/test/ui/consts/const-eval/promoted_errors2.stderr new file mode 100644 index 0000000000000..2819e6e8fdbe0 --- /dev/null +++ b/src/test/ui/consts/const-eval/promoted_errors2.stderr @@ -0,0 +1,68 @@ +error: attempt to subtract with overflow + --> $DIR/promoted_errors2.rs:6:20 + | +LL | println!("{}", 0u32 - 1); + | ^^^^^^^^ + | +note: lint level defined here + --> $DIR/promoted_errors2.rs:3:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + +error: attempt to subtract with overflow + --> $DIR/promoted_errors2.rs:8:14 + | +LL | let _x = 0u32 - 1; + | ^^^^^^^^ + +error: attempt to divide by zero + --> $DIR/promoted_errors2.rs:10:20 + | +LL | println!("{}", 1/(1-1)); + | ^^^^^^^ + +error: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors2.rs:10:20 + | +LL | println!("{}", 1/(1-1)); + | ^^^^^^^ attempt to divide by zero + +error: attempt to divide by zero + --> $DIR/promoted_errors2.rs:13:14 + | +LL | let _x = 1/(1-1); + | ^^^^^^^ + +error: this expression will panic at runtime + --> $DIR/promoted_errors2.rs:13:14 + | +LL | let _x = 1/(1-1); + | ^^^^^^^ attempt to divide by zero + +error: attempt to divide by zero + --> $DIR/promoted_errors2.rs:16:20 + | +LL | println!("{}", 1/(false as u32)); + | ^^^^^^^^^^^^^^^^ + +error: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors2.rs:16:20 + | +LL | println!("{}", 1/(false as u32)); + | ^^^^^^^^^^^^^^^^ attempt to divide by zero + +error: attempt to divide by zero + --> $DIR/promoted_errors2.rs:19:14 + | +LL | let _x = 1/(false as u32); + | ^^^^^^^^^^^^^^^^ + +error: this expression will panic at runtime + --> $DIR/promoted_errors2.rs:19:14 + | +LL | let _x = 1/(false as u32); + | ^^^^^^^^^^^^^^^^ attempt to divide by zero + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/consts/const-eval/ref_to_int_match.rs b/src/test/ui/consts/const-eval/ref_to_int_match.rs index b6a2ed1f9bcf4..45ce040fb9eef 100644 --- a/src/test/ui/consts/const-eval/ref_to_int_match.rs +++ b/src/test/ui/consts/const-eval/ref_to_int_match.rs @@ -9,6 +9,7 @@ fn main() { } } +#[repr(C)] union Foo { f: Int, r: &'static u32, diff --git a/src/test/ui/consts/const-eval/ref_to_int_match.stderr b/src/test/ui/consts/const-eval/ref_to_int_match.stderr index f8eafed68e43d..b72a5b80afa8d 100644 --- a/src/test/ui/consts/const-eval/ref_to_int_match.stderr +++ b/src/test/ui/consts/const-eval/ref_to_int_match.stderr @@ -1,10 +1,10 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/ref_to_int_match.rs:23:1 + --> $DIR/ref_to_int_match.rs:24:1 | LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: could not evaluate constant pattern --> $DIR/ref_to_int_match.rs:7:14 diff --git a/src/test/ui/consts/const-eval/simd/insert_extract.rs b/src/test/ui/consts/const-eval/simd/insert_extract.rs new file mode 100644 index 0000000000000..d3462d802ea4e --- /dev/null +++ b/src/test/ui/consts/const-eval/simd/insert_extract.rs @@ -0,0 +1,53 @@ +// run-pass +#![feature(const_fn)] +#![feature(repr_simd)] +#![feature(platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] struct i8x1(i8); +#[repr(simd)] struct u16x2(u16, u16); +#[repr(simd)] struct f32x3(f32, f32, f32); + +extern "platform-intrinsic" { + fn simd_insert(x: T, idx: u32, val: U) -> T; + fn simd_extract(x: T, idx: u32) -> U; +} + +fn main() { + { + const U: i8x1 = i8x1(13); + const V: i8x1 = unsafe { simd_insert(U, 0_u32, 42_i8) }; + const X0: i8 = V.0; + const Y0: i8 = unsafe { simd_extract(V, 0) }; + assert_eq!(X0, 42); + assert_eq!(Y0, 42); + } + { + const U: u16x2 = u16x2(13, 14); + const V: u16x2 = unsafe { simd_insert(U, 1_u32, 42_u16) }; + const X0: u16 = V.0; + const X1: u16 = V.1; + const Y0: u16 = unsafe { simd_extract(V, 0) }; + const Y1: u16 = unsafe { simd_extract(V, 1) }; + assert_eq!(X0, 13); + assert_eq!(X1, 42); + assert_eq!(Y0, 13); + assert_eq!(Y1, 42); + } + { + const U: f32x3 = f32x3(13., 14., 15.); + const V: f32x3 = unsafe { simd_insert(U, 1_u32, 42_f32) }; + const X0: f32 = V.0; + const X1: f32 = V.1; + const X2: f32 = V.2; + const Y0: f32 = unsafe { simd_extract(V, 0) }; + const Y1: f32 = unsafe { simd_extract(V, 1) }; + const Y2: f32 = unsafe { simd_extract(V, 2) }; + assert_eq!(X0, 13.); + assert_eq!(X1, 42.); + assert_eq!(X2, 15.); + assert_eq!(Y0, 13.); + assert_eq!(Y1, 42.); + assert_eq!(Y2, 15.); + } +} diff --git a/src/test/ui/consts/const-eval/strlen.rs b/src/test/ui/consts/const-eval/strlen.rs index 6a5cad82c3aa3..7b14a52354348 100644 --- a/src/test/ui/consts/const-eval/strlen.rs +++ b/src/test/ui/consts/const-eval/strlen.rs @@ -1,9 +1,11 @@ // run-pass -#![feature(const_str_len, const_str_as_bytes)] - const S: &str = "foo"; pub const B: &[u8] = S.as_bytes(); +pub const C: usize = B.len(); +pub const D: bool = B.is_empty(); +pub const E: bool = S.is_empty(); +pub const F: usize = S.len(); pub fn foo() -> [u8; S.len()] { let mut buf = [0; S.len()]; @@ -20,4 +22,10 @@ fn main() { assert_eq!(LEN, S.len()); assert_eq!(B, foo()); assert_eq!(B, b"foo"); + assert_eq!(C, 3); + assert_eq!(F, 3); + assert!(!D); + assert!(!E); + const EMPTY: bool = "".is_empty(); + assert!(EMPTY); } diff --git a/src/test/ui/consts/const-eval/transmute-const.stderr b/src/test/ui/consts/const-eval/transmute-const.stderr index cacf86364796f..47f89fccf7a81 100644 --- a/src/test/ui/consts/const-eval/transmute-const.stderr +++ b/src/test/ui/consts/const-eval/transmute-const.stderr @@ -4,7 +4,7 @@ error[E0080]: it is undefined behavior to use this value LL | static FOO: bool = unsafe { mem::transmute(3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3, but expected something less or equal to 1 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/ub-enum.rs b/src/test/ui/consts/const-eval/ub-enum.rs index d4b2220695102..483285aa4e123 100644 --- a/src/test/ui/consts/const-eval/ub-enum.rs +++ b/src/test/ui/consts/const-eval/ub-enum.rs @@ -10,6 +10,7 @@ struct Wrap(T); enum Enum { A = 0, } +#[repr(C)] union TransmuteEnum { in1: &'static u8, in2: usize, @@ -35,6 +36,7 @@ enum Enum2 { A = 2, } +#[repr(C)] union TransmuteEnum2 { in1: usize, in2: &'static u8, @@ -60,6 +62,7 @@ const BAD_ENUM2_OPTION_PTR: Option = unsafe { TransmuteEnum2 { in2: &0 }. // Invalid enum field content (mostly to test printing of paths for enum tuple // variants and tuples). +#[repr(C)] union TransmuteChar { a: u32, b: char, diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index 8ecb1aabdd0f7..8ebc9dbec8ab2 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -1,74 +1,74 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:22:1 + --> $DIR/ub-enum.rs:23:1 | LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { in2: 1 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 1, but expected a valid enum discriminant | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:25:1 + --> $DIR/ub-enum.rs:26:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { TransmuteEnum { in1: &1 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:28:1 + --> $DIR/ub-enum.rs:29:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { TransmuteEnum { in1: &1 }.out2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be equal to 0 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:46:1 + --> $DIR/ub-enum.rs:48:1 | LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:48:1 + --> $DIR/ub-enum.rs:50:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:50:1 + --> $DIR/ub-enum.rs:52:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { TransmuteEnum2 { in2: &0 }.out2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be equal to 2 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:54:1 + --> $DIR/ub-enum.rs:56:1 | LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { TransmuteEnum2 { in3: () }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid enum discriminant | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:58:1 + --> $DIR/ub-enum.rs:60:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { TransmuteEnum2 { in2: &0 }.out3 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:68:1 + --> $DIR/ub-enum.rs:71:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at ..0.1, but expected something less or equal to 1114111 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: aborting due to 9 previous errors diff --git a/src/test/ui/consts/const-eval/ub-nonnull.rs b/src/test/ui/consts/const-eval/ub-nonnull.rs index bcbb4358aec03..8ce64ced7dff4 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.rs +++ b/src/test/ui/consts/const-eval/ub-nonnull.rs @@ -1,5 +1,5 @@ #![feature(rustc_attrs, const_transmute)] -#![allow(const_err)] // make sure we cannot allow away the errors tested here +#![allow(const_err, invalid_value)] // make sure we cannot allow away the errors tested here use std::mem; use std::ptr::NonNull; @@ -11,10 +11,11 @@ const NON_NULL_PTR: NonNull = unsafe { mem::transmute(&1) }; const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; //~^ ERROR it is undefined behavior to use this value +#[deny(const_err)] // this triggers a `const_err` so validation does not even happen const OUT_OF_BOUNDS_PTR: NonNull = { unsafe { -//~^ ERROR it is undefined behavior to use this value - let ptr: &(u8, u8, u8) = mem::transmute(&0u8); // &0 gets promoted so it does not dangle - let out_of_bounds_ptr = &ptr.2; // use address-of-field for pointer arithmetic + let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle + // Use address-of-element for pointer arithmetic. This could wrap around to NULL! + let out_of_bounds_ptr = &ptr[255]; //~ ERROR any use of this value will cause an error mem::transmute(out_of_bounds_ptr) } }; @@ -23,6 +24,7 @@ const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; //~^ ERROR it is undefined behavior to use this value +#[repr(C)] union Transmute { uninit: (), out: NonZeroU8, diff --git a/src/test/ui/consts/const-eval/ub-nonnull.stderr b/src/test/ui/consts/const-eval/ub-nonnull.stderr index 2f9423fed3530..80d80a986751e 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.stderr +++ b/src/test/ui/consts/const-eval/ub-nonnull.stderr @@ -4,60 +4,65 @@ error[E0080]: it is undefined behavior to use this value LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:14:1 +error: any use of this value will cause an error + --> $DIR/ub-nonnull.rs:18:29 | LL | / const OUT_OF_BOUNDS_PTR: NonNull = { unsafe { -LL | | -LL | | let ptr: &(u8, u8, u8) = mem::transmute(&0u8); // &0 gets promoted so it does not dangle -LL | | let out_of_bounds_ptr = &ptr.2; // use address-of-field for pointer arithmetic +LL | | let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle +LL | | // Use address-of-element for pointer arithmetic. This could wrap around to NULL! +LL | | let out_of_bounds_ptr = &ptr[255]; + | | ^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of allocation 6 which has size 1 LL | | mem::transmute(out_of_bounds_ptr) LL | | } }; - | |____^ type validation failed: encountered a potentially NULL pointer, but expected something that cannot possibly fail to be greater or equal to 1 + | |____- + | +note: lint level defined here + --> $DIR/ub-nonnull.rs:14:8 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior +LL | #[deny(const_err)] // this triggers a `const_err` so validation does not even happen + | ^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:21:1 + --> $DIR/ub-nonnull.rs:22:1 | LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:23:1 + --> $DIR/ub-nonnull.rs:24:1 | LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:30:1 + --> $DIR/ub-nonnull.rs:32:1 | LL | const UNINIT: NonZeroU8 = unsafe { Transmute { uninit: () }.out }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected something greater or equal to 1 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:38:1 + --> $DIR/ub-nonnull.rs:40:1 | LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something in the range 10..=30 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:44:1 + --> $DIR/ub-nonnull.rs:46:1 | LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 20, but expected something less or equal to 10, or greater or equal to 30 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: aborting due to 7 previous errors diff --git a/src/test/ui/consts/const-eval/ub-ref.rs b/src/test/ui/consts/const-eval/ub-ref.rs index 0d8f30159b316..03ac12c8b1ac1 100644 --- a/src/test/ui/consts/const-eval/ub-ref.rs +++ b/src/test/ui/consts/const-eval/ub-ref.rs @@ -1,6 +1,6 @@ // ignore-tidy-linelength #![feature(const_transmute)] -#![allow(const_err)] // make sure we cannot allow away the errors tested here +#![allow(const_err, invalid_value)] // make sure we cannot allow away the errors tested here use std::mem; @@ -11,6 +11,9 @@ const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; const NULL: &u16 = unsafe { mem::transmute(0usize) }; //~^ ERROR it is undefined behavior to use this value +// It is very important that we reject this: We do promote `&(4 * REF_AS_USIZE)`, +// but that would fail to compile; so we ended up breaking user code that would +// have worked fine had we not promoted. const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; //~^ ERROR it is undefined behavior to use this value diff --git a/src/test/ui/consts/const-eval/ub-ref.stderr b/src/test/ui/consts/const-eval/ub-ref.stderr index f1702955ed7b1..01bde413c0d9c 100644 --- a/src/test/ui/consts/const-eval/ub-ref.stderr +++ b/src/test/ui/consts/const-eval/ub-ref.stderr @@ -4,7 +4,7 @@ error[E0080]: it is undefined behavior to use this value LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned reference (required 2 byte alignment but found 1) | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref.rs:11:1 @@ -12,31 +12,31 @@ error[E0080]: it is undefined behavior to use this value LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref.rs:14:1 + --> $DIR/ub-ref.rs:17:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref.rs:17:1 + --> $DIR/ub-ref.rs:20:1 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected plain (non-pointer) bytes | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref.rs:20:1 + --> $DIR/ub-ref.rs:23:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling reference (created from integer) | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: aborting due to 5 previous errors diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.rs b/src/test/ui/consts/const-eval/ub-uninhabit.rs index 42cba02f579b7..d2745d71bdb2f 100644 --- a/src/test/ui/consts/const-eval/ub-uninhabit.rs +++ b/src/test/ui/consts/const-eval/ub-uninhabit.rs @@ -6,6 +6,7 @@ use std::mem; #[derive(Copy, Clone)] enum Bar {} +#[repr(C)] union TransmuteUnion { a: A, b: B, diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.stderr b/src/test/ui/consts/const-eval/ub-uninhabit.stderr index c8842ecc23ca2..3877f3cab6d44 100644 --- a/src/test/ui/consts/const-eval/ub-uninhabit.stderr +++ b/src/test/ui/consts/const-eval/ub-uninhabit.stderr @@ -1,26 +1,26 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-uninhabit.rs:14:1 + --> $DIR/ub-uninhabit.rs:15:1 | LL | const BAD_BAD_BAD: Bar = unsafe { (TransmuteUnion::<(), Bar> { a: () }).b }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-uninhabit.rs:17:1 + --> $DIR/ub-uninhabit.rs:18:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at . | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-uninhabit.rs:20:1 + --> $DIR/ub-uninhabit.rs:21:1 | LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { (TransmuteUnion::<(), [Bar; 1]> { a: () }).b }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: aborting due to 3 previous errors diff --git a/src/test/ui/consts/const-eval/ub-upvars.rs b/src/test/ui/consts/const-eval/ub-upvars.rs index 0a427cd8857e8..baab14dc16141 100644 --- a/src/test/ui/consts/const-eval/ub-upvars.rs +++ b/src/test/ui/consts/const-eval/ub-upvars.rs @@ -1,5 +1,5 @@ #![feature(const_transmute)] -#![allow(const_err)] // make sure we cannot allow away the errors tested here +#![allow(const_err, invalid_value)] // make sure we cannot allow away the errors tested here use std::mem; diff --git a/src/test/ui/consts/const-eval/ub-upvars.stderr b/src/test/ui/consts/const-eval/ub-upvars.stderr index f8273ba902a88..ea6ab3ae5b5ba 100644 --- a/src/test/ui/consts/const-eval/ub-upvars.stderr +++ b/src/test/ui/consts/const-eval/ub-upvars.stderr @@ -8,7 +8,7 @@ LL | | move || { let _ = bad_ref; let _ = another_var; } LL | | }; | |__^ type validation failed: encountered 0 at ..., but expected something greater or equal to 1 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.rs b/src/test/ui/consts/const-eval/ub-wide-ptr.rs new file mode 100644 index 0000000000000..1f810c40572c0 --- /dev/null +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.rs @@ -0,0 +1,159 @@ +// ignore-tidy-linelength +#![allow(unused)] +#![allow(const_err)] // make sure we cannot allow away the errors tested here + +// normalize-stderr-test "alignment \d+" -> "alignment N" +// normalize-stderr-test "offset \d+" -> "offset N" +// normalize-stderr-test "allocation \d+" -> "allocation N" +// normalize-stderr-test "size \d+" -> "size N" + +#[repr(C)] +union BoolTransmute { + val: u8, + bl: bool, +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct SliceRepr { + ptr: *const u8, + len: usize, +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct BadSliceRepr { + ptr: *const u8, + len: &'static u8, +} + +#[repr(C)] +union SliceTransmute { + repr: SliceRepr, + bad: BadSliceRepr, + addr: usize, + slice: &'static [u8], + raw_slice: *const [u8], + str: &'static str, + my_str: &'static MyStr, + my_slice: &'static MySliceBool, +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct DynRepr { + ptr: *const u8, + vtable: *const u8, +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct DynRepr2 { + ptr: *const u8, + vtable: *const u64, +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct BadDynRepr { + ptr: *const u8, + vtable: usize, +} + +#[repr(C)] +union DynTransmute { + repr: DynRepr, + repr2: DynRepr2, + bad: BadDynRepr, + addr: usize, + rust: &'static dyn Trait, + raw_rust: *const dyn Trait, +} + +trait Trait {} +impl Trait for bool {} + +// custom unsized type +struct MyStr(str); + +// custom unsized type with sized fields +struct MySlice(bool, T); +type MySliceBool = MySlice<[bool]>; + +// # str +// OK +const STR_VALID: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.str}; +// bad str +const STR_TOO_LONG: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str}; +//~^ ERROR it is undefined behavior to use this value +// bad str +const STR_LENGTH_PTR: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str}; +//~^ ERROR it is undefined behavior to use this value +// bad str in user-defined unsized type +const MY_STR_LENGTH_PTR: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str}; +//~^ ERROR it is undefined behavior to use this value + +// invalid UTF-8 +const STR_NO_UTF8: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str }; +//~^ ERROR it is undefined behavior to use this value +// invalid UTF-8 in user-defined str-like +const MYSTR_NO_UTF8: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str }; +//~^ ERROR it is undefined behavior to use this value + +// # slice +// OK +const SLICE_VALID: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.slice}; +// bad slice: length uninit +const SLICE_LENGTH_UNINIT: &[u8] = unsafe { SliceTransmute { addr: 42 }.slice}; +//~^ ERROR it is undefined behavior to use this value +// bad slice: length too big +const SLICE_TOO_LONG: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice}; +//~^ ERROR it is undefined behavior to use this value +// bad slice: length not an int +const SLICE_LENGTH_PTR: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice}; +//~^ ERROR it is undefined behavior to use this value + +// bad data *inside* the slice +const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }]; +//~^ ERROR it is undefined behavior to use this value + +// good MySliceBool +const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]); +// bad: sized field is not okay +const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]); +//~^ ERROR it is undefined behavior to use this value +// bad: unsized part is not okay +const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]); +//~^ ERROR it is undefined behavior to use this value + +// # raw slice +const RAW_SLICE_VALID: *const [u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.raw_slice}; // ok +const RAW_SLICE_TOO_LONG: *const [u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.raw_slice}; // ok because raw +const RAW_SLICE_MUCH_TOO_LONG: *const [u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: usize::max_value() } }.raw_slice}; // ok because raw +const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { SliceTransmute { addr: 42 }.raw_slice}; +//~^ ERROR it is undefined behavior to use this value + +// # trait object +// bad trait object +const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; +//~^ ERROR it is undefined behavior to use this value +// bad trait object +const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; +//~^ ERROR it is undefined behavior to use this value +// bad trait object +const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; +//~^ ERROR it is undefined behavior to use this value + +// bad data *inside* the trait object +const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl }; +//~^ ERROR it is undefined behavior to use this value + +// # raw trait object +const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.rust}; +//~^ ERROR it is undefined behavior to use this value +const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.raw_rust}; +//~^ ERROR it is undefined behavior to use this value +const RAW_TRAIT_OBJ_CONTENT_INVALID: *const dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl } as *const _; // ok because raw + +fn main() { +} diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr new file mode 100644 index 0000000000000..9134ef5a31ad9 --- /dev/null +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr @@ -0,0 +1,147 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:87:1 + | +LL | const STR_TOO_LONG: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling reference (not entirely in bounds) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:90:1 + | +LL | const STR_LENGTH_PTR: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:93:1 + | +LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:97:1 + | +LL | const STR_NO_UTF8: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at . + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:100:1 + | +LL | const MYSTR_NO_UTF8: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at ..0 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:107:1 + | +LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { SliceTransmute { addr: 42 }.slice}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in wide pointer metadata + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:110:1 + | +LL | const SLICE_TOO_LONG: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling reference (not entirely in bounds) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:113:1 + | +LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:117:1 + | +LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .[0], but expected something less or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:123:1 + | +LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..0, but expected something less or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:126:1 + | +LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..1[0], but expected something less or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:133:1 + | +LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { SliceTransmute { addr: 42 }.raw_slice}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in wide pointer metadata + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:138:1 + | +LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:141:1 + | +LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:144:1 + | +LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:148:1 + | +LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .., but expected something less or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:152:1 + | +LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.rust}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:154:1 + | +LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.raw_rust}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: aborting due to 18 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/union-const-eval-field.rs b/src/test/ui/consts/const-eval/union-const-eval-field.rs index 56f3ef3db25d1..7f29a5bc24e4e 100644 --- a/src/test/ui/consts/const-eval/union-const-eval-field.rs +++ b/src/test/ui/consts/const-eval/union-const-eval-field.rs @@ -4,6 +4,7 @@ type Field1 = i32; type Field2 = f32; type Field3 = i64; +#[repr(C)] union DummyUnion { field1: Field1, field2: Field2, diff --git a/src/test/ui/consts/const-eval/union-const-eval-field.stderr b/src/test/ui/consts/const-eval/union-const-eval-field.stderr index 4a53337341e67..9193bd9dea189 100644 --- a/src/test/ui/consts/const-eval/union-const-eval-field.stderr +++ b/src/test/ui/consts/const-eval/union-const-eval-field.stderr @@ -1,10 +1,10 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/union-const-eval-field.rs:27:5 + --> $DIR/union-const-eval-field.rs:28:5 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/union-ice.rs b/src/test/ui/consts/const-eval/union-ice.rs index 33736b360d33a..5a14c7fd99345 100644 --- a/src/test/ui/consts/const-eval/union-ice.rs +++ b/src/test/ui/consts/const-eval/union-ice.rs @@ -3,6 +3,7 @@ type Field1 = i32; type Field3 = i64; +#[repr(C)] union DummyUnion { field1: Field1, field3: Field3, diff --git a/src/test/ui/consts/const-eval/union-ice.stderr b/src/test/ui/consts/const-eval/union-ice.stderr index b25cb8c5aa021..476f3651740ab 100644 --- a/src/test/ui/consts/const-eval/union-ice.stderr +++ b/src/test/ui/consts/const-eval/union-ice.stderr @@ -1,13 +1,13 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ice.rs:13:1 + --> $DIR/union-ice.rs:14:1 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ice.rs:15:1 + --> $DIR/union-ice.rs:16:1 | LL | / const FIELD_PATH: Struct = Struct { LL | | a: 42, @@ -15,10 +15,10 @@ LL | | b: unsafe { UNION.field3 }, LL | | }; | |__^ type validation failed: encountered uninitialized bytes at .b, but expected initialized plain (non-pointer) bytes | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ice.rs:25:1 + --> $DIR/union-ice.rs:26:1 | LL | / const FIELD_PATH2: Struct2 = Struct2 { LL | | b: [ @@ -29,7 +29,7 @@ LL | | a: 42, LL | | }; | |__^ type validation failed: encountered undefined bytes at .b[1] | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: aborting due to 3 previous errors diff --git a/src/test/ui/consts/const-eval/union-ub-fat-ptr.rs b/src/test/ui/consts/const-eval/union-ub-fat-ptr.rs deleted file mode 100644 index d5405f3441fec..0000000000000 --- a/src/test/ui/consts/const-eval/union-ub-fat-ptr.rs +++ /dev/null @@ -1,131 +0,0 @@ -#![allow(unused)] -#![allow(const_err)] // make sure we cannot allow away the errors tested here - -// normalize-stderr-test "alignment \d+" -> "alignment N" -// normalize-stderr-test "offset \d+" -> "offset N" -// normalize-stderr-test "allocation \d+" -> "allocation N" -// normalize-stderr-test "size \d+" -> "size N" - -union BoolTransmute { - val: u8, - bl: bool, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct SliceRepr { - ptr: *const u8, - len: usize, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct BadSliceRepr { - ptr: *const u8, - len: &'static u8, -} - -union SliceTransmute { - repr: SliceRepr, - bad: BadSliceRepr, - slice: &'static [u8], - str: &'static str, - my_str: &'static MyStr, - my_slice: &'static MySliceBool, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct DynRepr { - ptr: *const u8, - vtable: *const u8, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct DynRepr2 { - ptr: *const u8, - vtable: *const u64, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct BadDynRepr { - ptr: *const u8, - vtable: usize, -} - -union DynTransmute { - repr: DynRepr, - repr2: DynRepr2, - bad: BadDynRepr, - rust: &'static dyn Trait, -} - -trait Trait {} -impl Trait for bool {} - -// custom unsized type -struct MyStr(str); - -// custom unsized type with sized fields -struct MySlice(bool, T); -type MySliceBool = MySlice<[bool]>; - -// OK -const A: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.str}; -// bad str -const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str}; -//~^ ERROR it is undefined behavior to use this value -// bad str -const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str}; -//~^ ERROR it is undefined behavior to use this value -// bad str in user-defined unsized type -const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str}; -//~^ ERROR it is undefined behavior to use this value - -// OK -const A2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.slice}; -// bad slice -const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice}; -//~^ ERROR it is undefined behavior to use this value -// bad slice -const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice}; -//~^ ERROR it is undefined behavior to use this value - -// bad trait object -const D: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; -//~^ ERROR it is undefined behavior to use this value -// bad trait object -const E: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; -//~^ ERROR it is undefined behavior to use this value -// bad trait object -const F: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; -//~^ ERROR it is undefined behavior to use this value - -// bad data *inside* the trait object -const G: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl }; -//~^ ERROR it is undefined behavior to use this value - -// bad data *inside* the slice -const H: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }]; -//~^ ERROR it is undefined behavior to use this value - -// good MySliceBool -const I1: &MySliceBool = &MySlice(true, [false]); -// bad: sized field is not okay -const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]); -//~^ ERROR it is undefined behavior to use this value -// bad: unsized part is not okay -const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]); -//~^ ERROR it is undefined behavior to use this value - -// invalid UTF-8 -const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str }; -//~^ ERROR it is undefined behavior to use this value -// invalid UTF-8 in user-defined str-like -const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str }; -//~^ ERROR it is undefined behavior to use this value - -fn main() { -} diff --git a/src/test/ui/consts/const-eval/union-ub-fat-ptr.stderr b/src/test/ui/consts/const-eval/union-ub-fat-ptr.stderr deleted file mode 100644 index aac32ecc5b747..0000000000000 --- a/src/test/ui/consts/const-eval/union-ub-fat-ptr.stderr +++ /dev/null @@ -1,115 +0,0 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:78:1 - | -LL | const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling reference (not entirely in bounds) - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:81:1 - | -LL | const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:84:1 - | -LL | const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:90:1 - | -LL | const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling reference (not entirely in bounds) - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:93:1 - | -LL | const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:97:1 - | -LL | const D: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer or too small vtable - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:100:1 - | -LL | const E: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer or too small vtable - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:103:1 - | -LL | const F: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer or too small vtable - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:107:1 - | -LL | const G: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .., but expected something less or equal to 1 - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:111:1 - | -LL | const H: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .[0], but expected something less or equal to 1 - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:117:1 - | -LL | const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..0, but expected something less or equal to 1 - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:120:1 - | -LL | const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..1[0], but expected something less or equal to 1 - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:124:1 - | -LL | const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at . - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:127:1 - | -LL | const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at ..0 - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error: aborting due to 14 previous errors - -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/union-ub.rs b/src/test/ui/consts/const-eval/union-ub.rs index cf436141c5a02..848826e6ef7f2 100644 --- a/src/test/ui/consts/const-eval/union-ub.rs +++ b/src/test/ui/consts/const-eval/union-ub.rs @@ -1,5 +1,6 @@ #![allow(const_err)] // make sure we cannot allow away the errors tested here +#[repr(C)] union DummyUnion { u8: u8, bool: bool, @@ -14,11 +15,13 @@ enum Enum { } #[derive(Copy, Clone)] +#[repr(C)] union Foo { a: bool, b: Enum, } +#[repr(C)] union Bar { foo: Foo, u8: u8, diff --git a/src/test/ui/consts/const-eval/union-ub.stderr b/src/test/ui/consts/const-eval/union-ub.stderr index 7baa55be6e11e..fa67bc0d8e7b5 100644 --- a/src/test/ui/consts/const-eval/union-ub.stderr +++ b/src/test/ui/consts/const-eval/union-ub.stderr @@ -1,10 +1,10 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub.rs:28:1 + --> $DIR/union-ub.rs:31:1 | LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something less or equal to 1 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/union_promotion.rs b/src/test/ui/consts/const-eval/union_promotion.rs index d3566511ef8ee..7167f88a1185b 100644 --- a/src/test/ui/consts/const-eval/union_promotion.rs +++ b/src/test/ui/consts/const-eval/union_promotion.rs @@ -1,5 +1,6 @@ #![allow(const_err)] +#[repr(C)] union Foo { a: &'static u32, b: usize, diff --git a/src/test/ui/consts/const-eval/union_promotion.stderr b/src/test/ui/consts/const-eval/union_promotion.stderr index b530c02f2fb93..ed186e3ebd2f5 100644 --- a/src/test/ui/consts/const-eval/union_promotion.stderr +++ b/src/test/ui/consts/const-eval/union_promotion.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/union_promotion.rs:9:29 + --> $DIR/union_promotion.rs:10:29 | LL | let x: &'static bool = &unsafe { | ____________-------------____^ diff --git a/src/test/ui/consts/const-eval/valid-const.rs b/src/test/ui/consts/const-eval/valid-const.rs index 30bd47219239e..65c642d750b51 100644 --- a/src/test/ui/consts/const-eval/valid-const.rs +++ b/src/test/ui/consts/const-eval/valid-const.rs @@ -1,7 +1,8 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass // Some constants that *are* valid #![feature(const_transmute)] +#![deny(const_err)] use std::mem; use std::ptr::NonNull; diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs new file mode 100644 index 0000000000000..7c6a574a2110f --- /dev/null +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs @@ -0,0 +1,23 @@ +#![feature(const_extern_fn)] + +extern "C" { + fn regular_in_block(); +} + +const extern fn bar() { + unsafe { + regular_in_block(); + //~^ ERROR: cannot call functions with `"C"` abi in `min_const_fn` + } +} + +extern fn regular() {} + +const extern fn foo() { + unsafe { + regular(); + //~^ ERROR: cannot call functions with `"C"` abi in `min_const_fn` + } +} + +fn main() {} diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr new file mode 100644 index 0000000000000..d8bdf0a57cf66 --- /dev/null +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr @@ -0,0 +1,21 @@ +error[E0723]: cannot call functions with `"C"` abi in `min_const_fn` + --> $DIR/const-extern-fn-call-extern-fn.rs:9:9 + | +LL | regular_in_block(); + | ^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error[E0723]: cannot call functions with `"C"` abi in `min_const_fn` + --> $DIR/const-extern-fn-call-extern-fn.rs:18:9 + | +LL | regular(); + | ^^^^^^^^^ + | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs new file mode 100644 index 0000000000000..5619811768801 --- /dev/null +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs @@ -0,0 +1,13 @@ +#![feature(const_extern_fn)] + +const extern fn unsize(x: &[u8; 3]) -> &[u8] { x } +//~^ ERROR unsizing casts are not allowed in const fn +const unsafe extern "C" fn closure() -> fn() { || {} } +//~^ ERROR function pointers in const fn are unstable +const unsafe extern fn use_float() { 1.0 + 1.0; } +//~^ ERROR only int, `bool` and `char` operations are stable in const fn +const extern "C" fn ptr_cast(val: *const u8) { val as usize; } +//~^ ERROR casting pointers to ints is unstable in const fn + + +fn main() {} diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr new file mode 100644 index 0000000000000..0ab1ddd8d5225 --- /dev/null +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr @@ -0,0 +1,39 @@ +error[E0723]: unsizing casts are not allowed in const fn + --> $DIR/const-extern-fn-min-const-fn.rs:3:48 + | +LL | const extern fn unsize(x: &[u8; 3]) -> &[u8] { x } + | ^ + | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error[E0723]: function pointers in const fn are unstable + --> $DIR/const-extern-fn-min-const-fn.rs:5:41 + | +LL | const unsafe extern "C" fn closure() -> fn() { || {} } + | ^^^^ + | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error[E0723]: only int, `bool` and `char` operations are stable in const fn + --> $DIR/const-extern-fn-min-const-fn.rs:7:38 + | +LL | const unsafe extern fn use_float() { 1.0 + 1.0; } + | ^^^^^^^^^ + | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error[E0723]: casting pointers to ints is unstable in const fn + --> $DIR/const-extern-fn-min-const-fn.rs:9:48 + | +LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; } + | ^^^^^^^^^^^^ + | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs new file mode 100644 index 0000000000000..cab175bbfa818 --- /dev/null +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs @@ -0,0 +1,10 @@ +#![feature(const_extern_fn)] + +const unsafe extern fn foo() -> usize { 5 } + +fn main() { + let a: [u8; foo()]; + //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block + foo(); + //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block +} diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.stderr new file mode 100644 index 0000000000000..5196b8ee0a21d --- /dev/null +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.stderr @@ -0,0 +1,19 @@ +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/const-extern-fn-requires-unsafe.rs:8:5 + | +LL | foo(); + | ^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/const-extern-fn-requires-unsafe.rs:6:17 + | +LL | let a: [u8; foo()]; + | ^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn.rs new file mode 100644 index 0000000000000..1dc0f83cadf7d --- /dev/null +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn.rs @@ -0,0 +1,35 @@ +// run-pass +#![feature(const_extern_fn)] + +const extern fn foo1(val: u8) -> u8 { + val + 1 +} + +const extern "C" fn foo2(val: u8) -> u8 { + val + 1 +} + +const unsafe extern fn bar1(val: bool) -> bool { + !val +} + +const unsafe extern "C" fn bar2(val: bool) -> bool { + !val +} + + +fn main() { + let a: [u8; foo1(25) as usize] = [0; 26]; + let b: [u8; foo2(25) as usize] = [0; 26]; + assert_eq!(a, b); + + let bar1_res = unsafe { bar1(false) }; + let bar2_res = unsafe { bar2(false) }; + assert!(bar1_res); + assert_eq!(bar1_res, bar2_res); + + let _foo1_cast: extern fn(u8) -> u8 = foo1; + let _foo2_cast: extern fn(u8) -> u8 = foo2; + let _bar1_cast: unsafe extern fn(bool) -> bool = bar1; + let _bar2_cast: unsafe extern fn(bool) -> bool = bar2; +} diff --git a/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs b/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs new file mode 100644 index 0000000000000..d39f2c1fe277e --- /dev/null +++ b/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs @@ -0,0 +1,12 @@ +// Check that `const extern fn` and `const unsafe extern fn` are feature-gated. + +#[cfg(FALSE)] const extern fn foo1() {} //~ ERROR `const extern fn` definitions are unstable +#[cfg(FALSE)] const extern "C" fn foo2() {} //~ ERROR `const extern fn` definitions are unstable +#[cfg(FALSE)] const extern "Rust" fn foo3() {} //~ ERROR `const extern fn` definitions are unstable +#[cfg(FALSE)] const unsafe extern fn bar1() {} //~ ERROR `const extern fn` definitions are unstable +#[cfg(FALSE)] const unsafe extern "C" fn bar2() {} +//~^ ERROR `const extern fn` definitions are unstable +#[cfg(FALSE)] const unsafe extern "Rust" fn bar3() {} +//~^ ERROR `const extern fn` definitions are unstable + +fn main() {} diff --git a/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr b/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr new file mode 100644 index 0000000000000..f138620ffefba --- /dev/null +++ b/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr @@ -0,0 +1,57 @@ +error[E0658]: `const extern fn` definitions are unstable + --> $DIR/feature-gate-const_extern_fn.rs:3:15 + | +LL | #[cfg(FALSE)] const extern fn foo1() {} + | ^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/64926 + = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable + +error[E0658]: `const extern fn` definitions are unstable + --> $DIR/feature-gate-const_extern_fn.rs:4:15 + | +LL | #[cfg(FALSE)] const extern "C" fn foo2() {} + | ^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/64926 + = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable + +error[E0658]: `const extern fn` definitions are unstable + --> $DIR/feature-gate-const_extern_fn.rs:5:15 + | +LL | #[cfg(FALSE)] const extern "Rust" fn foo3() {} + | ^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/64926 + = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable + +error[E0658]: `const extern fn` definitions are unstable + --> $DIR/feature-gate-const_extern_fn.rs:6:15 + | +LL | #[cfg(FALSE)] const unsafe extern fn bar1() {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/64926 + = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable + +error[E0658]: `const extern fn` definitions are unstable + --> $DIR/feature-gate-const_extern_fn.rs:7:15 + | +LL | #[cfg(FALSE)] const unsafe extern "C" fn bar2() {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/64926 + = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable + +error[E0658]: `const extern fn` definitions are unstable + --> $DIR/feature-gate-const_extern_fn.rs:9:15 + | +LL | #[cfg(FALSE)] const unsafe extern "Rust" fn bar3() {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/64926 + = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-if.rs b/src/test/ui/consts/const-if.rs new file mode 100644 index 0000000000000..9bb5bcc499e61 --- /dev/null +++ b/src/test/ui/consts/const-if.rs @@ -0,0 +1,5 @@ +const _X: i32 = if true { 5 } else { 6 }; +//~^ ERROR constant contains unimplemented expression type +//~| ERROR constant contains unimplemented expression type + +fn main() {} diff --git a/src/test/ui/consts/const-if.stderr b/src/test/ui/consts/const-if.stderr new file mode 100644 index 0000000000000..655fcdae58748 --- /dev/null +++ b/src/test/ui/consts/const-if.stderr @@ -0,0 +1,15 @@ +error[E0019]: constant contains unimplemented expression type + --> $DIR/const-if.rs:1:20 + | +LL | const _X: i32 = if true { 5 } else { 6 }; + | ^^^^ + +error[E0019]: constant contains unimplemented expression type + --> $DIR/const-if.rs:1:17 + | +LL | const _X: i32 = if true { 5 } else { 6 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/const-int-overflowing-rpass.rs b/src/test/ui/consts/const-int-overflowing-rpass.rs index b619c7908aa22..9be87a6447cda 100644 --- a/src/test/ui/consts/const-int-overflowing-rpass.rs +++ b/src/test/ui/consts/const-int-overflowing-rpass.rs @@ -18,6 +18,10 @@ const SHR_B: (u32, bool) = 0x10u32.overflowing_shr(132); const NEG_A: (u32, bool) = 0u32.overflowing_neg(); const NEG_B: (u32, bool) = core::u32::MAX.overflowing_neg(); +const ABS_POS: (i32, bool) = 10i32.overflowing_abs(); +const ABS_NEG: (i32, bool) = (-10i32).overflowing_abs(); +const ABS_MIN: (i32, bool) = i32::min_value().overflowing_abs(); + fn main() { assert_eq!(ADD_A, (7, false)); assert_eq!(ADD_B, (0, true)); @@ -36,4 +40,8 @@ fn main() { assert_eq!(NEG_A, (0, false)); assert_eq!(NEG_B, (1, true)); + + assert_eq!(ABS_POS, (10, false)); + assert_eq!(ABS_NEG, (10, false)); + assert_eq!(ABS_MIN, (i32::min_value(), true)); } diff --git a/src/test/ui/consts/const-int-sign-rpass.rs b/src/test/ui/consts/const-int-sign-rpass.rs index 05726cb228647..dc46fce39a93c 100644 --- a/src/test/ui/consts/const-int-sign-rpass.rs +++ b/src/test/ui/consts/const-int-sign-rpass.rs @@ -11,6 +11,9 @@ const SIGNUM_POS: i32 = 10i32.signum(); const SIGNUM_NIL: i32 = 0i32.signum(); const SIGNUM_NEG: i32 = (-42i32).signum(); +const ABS_A: i32 = 10i32.abs(); +const ABS_B: i32 = (-10i32).abs(); + fn main() { assert!(NEGATIVE_A); assert!(!NEGATIVE_B); @@ -20,4 +23,7 @@ fn main() { assert_eq!(SIGNUM_POS, 1); assert_eq!(SIGNUM_NIL, 0); assert_eq!(SIGNUM_NEG, -1); + + assert_eq!(ABS_A, 10); + assert_eq!(ABS_B, 10); } diff --git a/src/test/ui/consts/const-int-wrapping-rpass.rs b/src/test/ui/consts/const-int-wrapping-rpass.rs index 73147d7912d19..2bbad99a52a90 100644 --- a/src/test/ui/consts/const-int-wrapping-rpass.rs +++ b/src/test/ui/consts/const-int-wrapping-rpass.rs @@ -18,6 +18,10 @@ const SHR_B: u32 = 128u32.wrapping_shr(128); const NEG_A: u32 = 5u32.wrapping_neg(); const NEG_B: u32 = 1234567890u32.wrapping_neg(); +const ABS_POS: i32 = 10i32.wrapping_abs(); +const ABS_NEG: i32 = (-10i32).wrapping_abs(); +const ABS_MIN: i32 = i32::min_value().wrapping_abs(); + fn main() { assert_eq!(ADD_A, 255); assert_eq!(ADD_B, 199); @@ -36,4 +40,8 @@ fn main() { assert_eq!(NEG_A, 4294967291); assert_eq!(NEG_B, 3060399406); + + assert_eq!(ABS_POS, 10); + assert_eq!(ABS_NEG, 10); + assert_eq!(ABS_MIN, i32::min_value()); } diff --git a/src/test/ui/consts/const-labeled-break.rs b/src/test/ui/consts/const-labeled-break.rs index 36e308ade9c54..7cdbb22f92459 100644 --- a/src/test/ui/consts/const-labeled-break.rs +++ b/src/test/ui/consts/const-labeled-break.rs @@ -1,4 +1,4 @@ -// run-pass +// build-pass // Using labeled break in a while loop has caused an illegal instruction being // generated, and an ICE later. diff --git a/src/test/ui/consts/const-match-check.eval1.stderr b/src/test/ui/consts/const-match-check.eval1.stderr index 3bcb50c6dcf6f..24d2e3ce53937 100644 --- a/src/test/ui/consts/const-match-check.eval1.stderr +++ b/src/test/ui/consts/const-match-check.eval1.stderr @@ -1,8 +1,8 @@ -error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered +error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered --> $DIR/const-match-check.rs:25:15 | LL | A = { let 0 = 0; 0 }, - | ^ pattern `std::i32::MIN..=-1i32` not covered + | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered error: aborting due to previous error diff --git a/src/test/ui/consts/const-match-check.eval2.stderr b/src/test/ui/consts/const-match-check.eval2.stderr index e292e1cc16585..5d59d06f7982a 100644 --- a/src/test/ui/consts/const-match-check.eval2.stderr +++ b/src/test/ui/consts/const-match-check.eval2.stderr @@ -1,8 +1,8 @@ -error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered +error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered --> $DIR/const-match-check.rs:31:24 | LL | let x: [i32; { let 0 = 0; 0 }] = []; - | ^ pattern `std::i32::MIN..=-1i32` not covered + | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered error: aborting due to previous error diff --git a/src/test/ui/consts/const-match-check.matchck.stderr b/src/test/ui/consts/const-match-check.matchck.stderr index 8a9fbde8537bf..6d74c26f9f7a5 100644 --- a/src/test/ui/consts/const-match-check.matchck.stderr +++ b/src/test/ui/consts/const-match-check.matchck.stderr @@ -1,26 +1,26 @@ -error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered +error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered --> $DIR/const-match-check.rs:4:22 | LL | const X: i32 = { let 0 = 0; 0 }; - | ^ pattern `std::i32::MIN..=-1i32` not covered + | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered -error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered +error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered --> $DIR/const-match-check.rs:8:23 | LL | static Y: i32 = { let 0 = 0; 0 }; - | ^ pattern `std::i32::MIN..=-1i32` not covered + | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered -error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered +error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered --> $DIR/const-match-check.rs:13:26 | LL | const X: i32 = { let 0 = 0; 0 }; - | ^ pattern `std::i32::MIN..=-1i32` not covered + | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered -error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered +error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered --> $DIR/const-match-check.rs:19:26 | LL | const X: i32 = { let 0 = 0; 0 }; - | ^ pattern `std::i32::MIN..=-1i32` not covered + | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered error: aborting due to 4 previous errors diff --git a/src/test/ui/consts/const-multi-ref.rs b/src/test/ui/consts/const-multi-ref.rs new file mode 100644 index 0000000000000..498e99e668b43 --- /dev/null +++ b/src/test/ui/consts/const-multi-ref.rs @@ -0,0 +1,11 @@ +const _X: i32 = { + let mut a = 5; + let p = &mut a; //~ ERROR references in constants may only refer to immutable values + + let reborrow = {p}; //~ ERROR references in constants may only refer to immutable values + let pp = &reborrow; + let ppp = &pp; + ***ppp +}; + +fn main() {} diff --git a/src/test/ui/consts/const-multi-ref.stderr b/src/test/ui/consts/const-multi-ref.stderr new file mode 100644 index 0000000000000..9e525ef9aac75 --- /dev/null +++ b/src/test/ui/consts/const-multi-ref.stderr @@ -0,0 +1,15 @@ +error[E0017]: references in constants may only refer to immutable values + --> $DIR/const-multi-ref.rs:3:13 + | +LL | let p = &mut a; + | ^^^^^^ constants require immutable values + +error[E0017]: references in constants may only refer to immutable values + --> $DIR/const-multi-ref.rs:5:21 + | +LL | let reborrow = {p}; + | ^ constants require immutable values + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0017`. diff --git a/src/test/ui/consts/const-pattern-irrefutable.rs b/src/test/ui/consts/const-pattern-irrefutable.rs index d3f7be18a9839..60e16aaf89532 100644 --- a/src/test/ui/consts/const-pattern-irrefutable.rs +++ b/src/test/ui/consts/const-pattern-irrefutable.rs @@ -9,8 +9,8 @@ use foo::d; const a: u8 = 2; fn main() { - let a = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered - let c = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered - let d = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered + let a = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX + let c = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX + let d = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115). } diff --git a/src/test/ui/consts/const-pattern-irrefutable.stderr b/src/test/ui/consts/const-pattern-irrefutable.stderr index 48fe24df4d044..4814aa9a5b2ca 100644 --- a/src/test/ui/consts/const-pattern-irrefutable.stderr +++ b/src/test/ui/consts/const-pattern-irrefutable.stderr @@ -1,20 +1,38 @@ -error[E0005]: refutable pattern in local binding: `0u8..=1u8` not covered +error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX` not covered --> $DIR/const-pattern-irrefutable.rs:12:9 | +LL | const a: u8 = 2; + | ---------------- constant defined here +... LL | let a = 4; - | ^ interpreted as a constant pattern, not new variable + | ^ + | | + | interpreted as a constant pattern, not a new variable + | help: introduce a variable instead: `a_var` -error[E0005]: refutable pattern in local binding: `0u8..=1u8` not covered +error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX` not covered --> $DIR/const-pattern-irrefutable.rs:13:9 | +LL | pub const b: u8 = 2; + | -------------------- constant defined here +... LL | let c = 4; - | ^ interpreted as a constant pattern, not new variable + | ^ + | | + | interpreted as a constant pattern, not a new variable + | help: introduce a variable instead: `c_var` -error[E0005]: refutable pattern in local binding: `0u8..=1u8` not covered +error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX` not covered --> $DIR/const-pattern-irrefutable.rs:14:9 | +LL | pub const d: u8 = 2; + | -------------------- constant defined here +... LL | let d = 4; - | ^ interpreted as a constant pattern, not new variable + | ^ + | | + | interpreted as a constant pattern, not a new variable + | help: introduce a variable instead: `d_var` error: aborting due to 3 previous errors diff --git a/src/test/ui/consts/const-prop-read-static-in-const.rs b/src/test/ui/consts/const-prop-read-static-in-const.rs new file mode 100644 index 0000000000000..7504fd525955a --- /dev/null +++ b/src/test/ui/consts/const-prop-read-static-in-const.rs @@ -0,0 +1,12 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +// run-pass + +#![allow(dead_code)] + +const TEST: u8 = MY_STATIC; +//~^ skipping const checks + +static MY_STATIC: u8 = 4; + +fn main() { +} diff --git a/src/test/ui/consts/const-prop-read-static-in-const.stderr b/src/test/ui/consts/const-prop-read-static-in-const.stderr new file mode 100644 index 0000000000000..bbd5b12ed7dfc --- /dev/null +++ b/src/test/ui/consts/const-prop-read-static-in-const.stderr @@ -0,0 +1,6 @@ +warning: skipping const checks + --> $DIR/const-prop-read-static-in-const.rs:6:18 + | +LL | const TEST: u8 = MY_STATIC; + | ^^^^^^^^^ + diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index 113ec29239616..1ae39e7563a82 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -4,18 +4,23 @@ error[E0391]: cycle detected when const-evaluating + checking `Foo::bytes::{{con LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | +note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`... + --> $DIR/const-size_of-cycle.rs:6:17 + | +LL | bytes: [u8; std::mem::size_of::()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating `Foo::bytes::{{constant}}#0`... --> $SRC_DIR/libcore/mem/mod.rs:LL:COL | LL | intrinsics::size_of::() | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `std::intrinsics::size_of`... + --> $SRC_DIR/libcore/intrinsics.rs:LL:COL + | +LL | pub fn size_of() -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... = note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`... -note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`... - --> $DIR/const-size_of-cycle.rs:6:17 - | -LL | bytes: [u8; std::mem::size_of::()] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle note: cycle used when processing `Foo` --> $DIR/const-size_of-cycle.rs:5:1 diff --git a/src/test/ui/consts/const_let_refutable.rs b/src/test/ui/consts/const_let_refutable.rs index 7b3a591223025..d48d5945e7da9 100644 --- a/src/test/ui/consts/const_let_refutable.rs +++ b/src/test/ui/consts/const_let_refutable.rs @@ -2,6 +2,6 @@ fn main() {} const fn slice([a, b]: &[i32]) -> i32 { //~ ERROR refutable pattern in function argument a + b //~ ERROR can only call other `const fn` within a `const fn` - //~^ ERROR use of possibly uninitialized variable: `a` - //~| ERROR use of possibly uninitialized variable: `b` + //~^ ERROR use of possibly-uninitialized variable: `a` + //~| ERROR use of possibly-uninitialized variable: `b` } diff --git a/src/test/ui/consts/const_let_refutable.stderr b/src/test/ui/consts/const_let_refutable.stderr index a61c9b0c9fef9..7f15f02d4d37b 100644 --- a/src/test/ui/consts/const_let_refutable.stderr +++ b/src/test/ui/consts/const_let_refutable.stderr @@ -1,8 +1,8 @@ -error[E0005]: refutable pattern in function argument: `&[]` not covered +error[E0005]: refutable pattern in function argument: `&[]`, `&[_]` and `&[_, _, _]` not covered --> $DIR/const_let_refutable.rs:3:16 | LL | const fn slice([a, b]: &[i32]) -> i32 { - | ^^^^^^ pattern `&[]` not covered + | ^^^^^^ patterns `&[]`, `&[_]` and `&[_, _, _]` not covered error[E0723]: can only call other `const fn` within a `const fn`, but `const <&i32 as std::ops::Add>::add` is not stable as `const fn` --> $DIR/const_let_refutable.rs:4:5 @@ -13,17 +13,17 @@ LL | a + b = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0381]: use of possibly uninitialized variable: `a` +error[E0381]: use of possibly-uninitialized variable: `a` --> $DIR/const_let_refutable.rs:4:5 | LL | a + b - | ^ use of possibly uninitialized `a` + | ^ use of possibly-uninitialized `a` -error[E0381]: use of possibly uninitialized variable: `b` +error[E0381]: use of possibly-uninitialized variable: `b` --> $DIR/const_let_refutable.rs:4:9 | LL | a + b - | ^ use of possibly uninitialized `b` + | ^ use of possibly-uninitialized `b` error: aborting due to 4 previous errors diff --git a/src/test/ui/consts/issue-63226.rs b/src/test/ui/consts/issue-63226.rs new file mode 100644 index 0000000000000..deec44990086f --- /dev/null +++ b/src/test/ui/consts/issue-63226.rs @@ -0,0 +1,12 @@ +// aux-build:issue-63226.rs +// compile-flags:--extern issue_63226 +// edition:2018 +// build-pass +// A regression test for issue #63226. +// Checks if `const fn` is marked as reachable. + +use issue_63226::VTable; + +static ICE_ICE:&'static VTable=VTable::vtable(); + +fn main() {} diff --git a/src/test/ui/consts/issue-64059-2.rs b/src/test/ui/consts/issue-64059-2.rs new file mode 100644 index 0000000000000..38911c3dcf692 --- /dev/null +++ b/src/test/ui/consts/issue-64059-2.rs @@ -0,0 +1,6 @@ +// compile-flags: -C overflow-checks=on -O +// run-pass + +fn main() { + let _ = -(-0.0); +} diff --git a/src/test/ui/consts/issue-64059.rs b/src/test/ui/consts/issue-64059.rs new file mode 100644 index 0000000000000..c4c895fef66cf --- /dev/null +++ b/src/test/ui/consts/issue-64059.rs @@ -0,0 +1,5 @@ +// run-pass + +fn main() { + let _ = -(-0.0); +} diff --git a/src/test/ui/consts/issue-64662.rs b/src/test/ui/consts/issue-64662.rs new file mode 100644 index 0000000000000..e3a8c85830f73 --- /dev/null +++ b/src/test/ui/consts/issue-64662.rs @@ -0,0 +1,10 @@ +enum Foo { + A = foo(), //~ ERROR: type annotations needed + B = foo(), //~ ERROR: type annotations needed +} + +const fn foo() -> isize { + 0 +} + +fn main() {} diff --git a/src/test/ui/consts/issue-64662.stderr b/src/test/ui/consts/issue-64662.stderr new file mode 100644 index 0000000000000..b81daae330bfa --- /dev/null +++ b/src/test/ui/consts/issue-64662.stderr @@ -0,0 +1,15 @@ +error[E0282]: type annotations needed + --> $DIR/issue-64662.rs:2:9 + | +LL | A = foo(), + | ^^^ cannot infer type for `T` + +error[E0282]: type annotations needed + --> $DIR/issue-64662.rs:3:9 + | +LL | B = foo(), + | ^^^ cannot infer type for `T` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/consts/match_ice.stderr b/src/test/ui/consts/match_ice.stderr index 158581fcb1599..bf0bd3aca97a4 100644 --- a/src/test/ui/consts/match_ice.stderr +++ b/src/test/ui/consts/match_ice.stderr @@ -7,6 +7,9 @@ LL | C => {} error[E0004]: non-exhaustive patterns: `&T` not covered --> $DIR/match_ice.rs:15:11 | +LL | struct T; + | --------- `T` defined here +... LL | match K { | ^ pattern `&T` not covered | diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr deleted file mode 100644 index 4b43a0d0a1a1b..0000000000000 --- a/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr +++ /dev/null @@ -1,328 +0,0 @@ -error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/min_const_fn.rs:37:25 - | -LL | const fn into_inner(self) -> T { self.0 } - | ^^^^ constant functions cannot evaluate destructors - -error[E0723]: mutable references in const fn are unstable - --> $DIR/min_const_fn.rs:39:36 - | -LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 } - | ^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/min_const_fn.rs:44:28 - | -LL | const fn into_inner_lt(self) -> T { self.0 } - | ^^^^ constant functions cannot evaluate destructors - -error[E0723]: mutable references in const fn are unstable - --> $DIR/min_const_fn.rs:46:42 - | -LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } - | ^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/min_const_fn.rs:51:27 - | -LL | const fn into_inner_s(self) -> T { self.0 } - | ^^^^ constant functions cannot evaluate destructors - -error[E0723]: mutable references in const fn are unstable - --> $DIR/min_const_fn.rs:53:38 - | -LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } - | ^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: mutable references in const fn are unstable - --> $DIR/min_const_fn.rs:58:39 - | -LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } - | ^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:76:16 - | -LL | const fn foo11(t: T) -> T { t } - | ^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:78:18 - | -LL | const fn foo11_2(t: T) -> T { t } - | ^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: only int, `bool` and `char` operations are stable in const fn - --> $DIR/min_const_fn.rs:80:33 - | -LL | const fn foo19(f: f32) -> f32 { f * 2.0 } - | ^^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: only int, `bool` and `char` operations are stable in const fn - --> $DIR/min_const_fn.rs:82:35 - | -LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f } - | ^^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: only int and `bool` operations are stable in const fn - --> $DIR/min_const_fn.rs:84:35 - | -LL | const fn foo19_3(f: f32) -> f32 { -f } - | ^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: only int, `bool` and `char` operations are stable in const fn - --> $DIR/min_const_fn.rs:86:43 - | -LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g } - | ^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: cannot access `static` items in const fn - --> $DIR/min_const_fn.rs:90:27 - | -LL | const fn foo25() -> u32 { BAR } - | ^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: cannot access `static` items in const fn - --> $DIR/min_const_fn.rs:91:36 - | -LL | const fn foo26() -> &'static u32 { &BAR } - | ^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: casting pointers to ints is unstable in const fn - --> $DIR/min_const_fn.rs:92:42 - | -LL | const fn foo30(x: *const u32) -> usize { x as usize } - | ^^^^^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: casting pointers to ints is unstable in const fn - --> $DIR/min_const_fn.rs:94:63 - | -LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } - | ^^^^^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: casting pointers to ints is unstable in const fn - --> $DIR/min_const_fn.rs:96:42 - | -LL | const fn foo30_2(x: *mut u32) -> usize { x as usize } - | ^^^^^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: casting pointers to ints is unstable in const fn - --> $DIR/min_const_fn.rs:98:63 - | -LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } - | ^^^^^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: loops and conditional expressions are not stable in const fn - --> $DIR/min_const_fn.rs:100:38 - | -LL | const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } } - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: loops are not allowed in const fn - --> $DIR/min_const_fn.rs:102:29 - | -LL | const fn foo30_5(b: bool) { while b { } } - | ^^^^^^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: loops and conditional expressions are not stable in const fn - --> $DIR/min_const_fn.rs:105:44 - | -LL | const fn foo36(a: bool, b: bool) -> bool { a && b } - | ^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: loops and conditional expressions are not stable in const fn - --> $DIR/min_const_fn.rs:107:44 - | -LL | const fn foo37(a: bool, b: bool) -> bool { a || b } - | ^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: mutable references in const fn are unstable - --> $DIR/min_const_fn.rs:109:14 - | -LL | const fn inc(x: &mut i32) { *x += 1 } - | ^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:114:6 - | -LL | impl Foo { - | ^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:119:6 - | -LL | impl Foo { - | ^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:124:6 - | -LL | impl Foo { - | ^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: `impl Trait` in const fn is unstable - --> $DIR/min_const_fn.rs:130:24 - | -LL | const fn no_rpit2() -> AlanTuring { AlanTuring(0) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:132:34 - | -LL | const fn no_apit2(_x: AlanTuring) {} - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:134:22 - | -LL | const fn no_apit(_x: impl std::fmt::Debug) {} - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: `impl Trait` in const fn is unstable - --> $DIR/min_const_fn.rs:135:23 - | -LL | const fn no_rpit() -> impl std::fmt::Debug {} - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:136:23 - | -LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} - | ^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:137:32 - | -LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0515]: cannot return reference to temporary value - --> $DIR/min_const_fn.rs:137:63 - | -LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } - | ^-- - | || - | |temporary value created here - | returns a reference to data owned by the current function - -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:145:41 - | -LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn.rs:148:21 - | -LL | const fn no_fn_ptrs(_x: fn()) {} - | ^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn.rs:150:27 - | -LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } - | ^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error: aborting due to 37 previous errors - -Some errors have detailed explanations: E0515, E0723. -For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs index 8b423da788292..d0f63b148ff2b 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -136,9 +136,7 @@ const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized` const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } //~^ ERROR trait bounds other than `Sized` -//~| WARNING cannot return reference to temporary value -//~| WARNING this error has been downgraded to a warning -//~| WARNING this warning will become a hard error in the future +//~| ERROR cannot return reference to temporary value const fn no_unsafe() { unsafe {} } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index 211902b687b1b..3158b6284db94 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -286,7 +286,7 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add `#![feature(const_fn)]` to the crate attributes to enable -warning[E0515]: cannot return reference to temporary value +error[E0515]: cannot return reference to temporary value --> $DIR/min_const_fn.rs:137:63 | LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } @@ -294,13 +294,9 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } | || | |temporary value created here | returns a reference to data owned by the current function - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future - = note: for more information, try `rustc --explain E0729` error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:145:41 + --> $DIR/min_const_fn.rs:143:41 | LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -309,7 +305,7 @@ LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn.rs:148:21 + --> $DIR/min_const_fn.rs:146:21 | LL | const fn no_fn_ptrs(_x: fn()) {} | ^^ @@ -318,7 +314,7 @@ LL | const fn no_fn_ptrs(_x: fn()) {} = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn.rs:150:27 + --> $DIR/min_const_fn.rs:148:27 | LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } | ^^^^ @@ -326,7 +322,7 @@ LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add `#![feature(const_fn)]` to the crate attributes to enable -error: aborting due to 36 previous errors +error: aborting due to 37 previous errors -Some errors have detailed explanations: E0515, E0723. -For more information about an error, try `rustc --explain E0515`. +Some errors have detailed explanations: E0493, E0515, E0723. +For more information about an error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr deleted file mode 100644 index 0ea950d678f87..0000000000000 --- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn_dyn.rs:9:5 - | -LL | x.0.field; - | ^^^^^^^^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn_dyn.rs:12:66 - | -LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } - | ^^ - | - = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0716]: temporary value dropped while borrowed - --> $DIR/min_const_fn_dyn.rs:12:67 - | -LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } - | -^ - temporary value is freed at the end of this statement - | || - | |creates a temporary which is freed while still in use - | cast requires that borrow lasts for `'static` - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0716, E0723. -For more information about an error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs index 75b67192f0081..3833510c0b3b5 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs @@ -11,8 +11,6 @@ const fn no_inner_dyn_trait2(x: Hide) { } const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } //~^ ERROR trait bounds other than `Sized` -//~| WARNING temporary value dropped while borrowed -//~| WARNING this error has been downgraded to a warning -//~| WARNING this warning will become a hard error in the future +//~| ERROR temporary value dropped while borrowed fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr index 02ddb0395296c..0ea950d678f87 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr @@ -16,7 +16,7 @@ LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add `#![feature(const_fn)]` to the crate attributes to enable -warning[E0716]: temporary value dropped while borrowed +error[E0716]: temporary value dropped while borrowed --> $DIR/min_const_fn_dyn.rs:12:67 | LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } @@ -24,12 +24,8 @@ LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } | || | |creates a temporary which is freed while still in use | cast requires that borrow lasts for `'static` - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future - = note: for more information, try `rustc --explain E0729` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0716, E0723. For more information about an error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs new file mode 100644 index 0000000000000..0b1ab1c34ff2f --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs @@ -0,0 +1,16 @@ +const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe +//~^ dereferencing raw pointers in constant functions + +const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x } +//~^ dereferencing raw pointers in constant functions + +const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static usize { &*x } +//~^ dereferencing raw pointers in constant functions + +fn main() {} + +const unsafe fn no_union() { + union Foo { x: (), y: () } + Foo { x: () }.y + //~^ accessing union fields is unstable +} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr similarity index 79% rename from src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr rename to src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr index d3f2ece1f9294..2a4c627438d61 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr @@ -1,5 +1,5 @@ error[E0658]: dereferencing raw pointers in constant functions is unstable - --> $DIR/min_const_fn_unsafe.rs:50:77 + --> $DIR/min_const_fn_unsafe_bad.rs:1:77 | LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } | ^^^ @@ -8,7 +8,7 @@ LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable error[E0658]: dereferencing raw pointers in constant functions is unstable - --> $DIR/min_const_fn_unsafe.rs:53:70 + --> $DIR/min_const_fn_unsafe_bad.rs:4:70 | LL | const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x } | ^^ @@ -17,7 +17,7 @@ LL | const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x } = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable error[E0658]: dereferencing raw pointers in constant functions is unstable - --> $DIR/min_const_fn_unsafe.rs:56:83 + --> $DIR/min_const_fn_unsafe_bad.rs:7:83 | LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static usize { &*x } | ^^^ @@ -25,17 +25,17 @@ LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static u = note: for more information, see https://github.com/rust-lang/rust/issues/51911 = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable -error[E0658]: unions in const fn are unstable - --> $DIR/min_const_fn_unsafe.rs:63:5 +error[E0723]: accessing union fields is unstable + --> $DIR/min_const_fn_unsafe_bad.rs:14:5 | LL | Foo { x: () }.y | ^^^^^^^^^^^^^^^ | - = note: for more information, see https://github.com/rust-lang/rust/issues/51909 - = help: add `#![feature(const_fn_union)]` to the crate attributes to enable + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 + = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/min_const_fn_unsafe.rs:50:77 + --> $DIR/min_const_fn_unsafe_bad.rs:1:77 | LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } | ^^^ dereference of raw pointer @@ -44,5 +44,5 @@ LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { error: aborting due to 5 previous errors -Some errors have detailed explanations: E0133, E0658. +Some errors have detailed explanations: E0133, E0658, E0723. For more information about an error, try `rustc --explain E0133`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_ok.rs similarity index 61% rename from src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs rename to src/test/ui/consts/min_const_fn/min_const_fn_unsafe_ok.rs index 0152561aefcb2..02c7970deca64 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_ok.rs @@ -1,6 +1,4 @@ -//------------------------------------------------------------------------------ -// OK -//------------------------------------------------------------------------------ +// check-pass const unsafe fn ret_i32_no_unsafe() -> i32 { 42 } const unsafe fn ret_null_ptr_no_unsafe() -> *const T { std::ptr::null() } @@ -43,23 +41,4 @@ const unsafe fn call_unsafe_generic_cell_const_unsafe_fn_immediate() ret_null_mut_ptr_no_unsafe::>>() } -//------------------------------------------------------------------------------ -// NOT OK -//------------------------------------------------------------------------------ - -const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe -//~^ dereferencing raw pointers in constant functions - -const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x } -//~^ dereferencing raw pointers in constant functions - -const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static usize { &*x } -//~^ dereferencing raw pointers in constant functions - fn main() {} - -const unsafe fn no_union() { - union Foo { x: (), y: () } - Foo { x: () }.y - //~^ unions in const fn -} diff --git a/src/test/ui/consts/miri_unleashed/assoc_const.stderr b/src/test/ui/consts/miri_unleashed/assoc_const.stderr index e814303923e18..6a6cb343f17d5 100644 --- a/src/test/ui/consts/miri_unleashed/assoc_const.stderr +++ b/src/test/ui/consts/miri_unleashed/assoc_const.stderr @@ -1,8 +1,8 @@ warning: skipping const checks - --> $DIR/assoc_const.rs:12:31 + --> $DIR/assoc_const.rs:12:20 | LL | const F: u32 = (U::X, 42).1; - | ^ + | ^^^^^^^^^^ error[E0080]: erroneous constant used --> $DIR/assoc_const.rs:29:13 diff --git a/src/test/ui/consts/miri_unleashed/enum_discriminants.rs b/src/test/ui/consts/miri_unleashed/enum_discriminants.rs new file mode 100644 index 0000000000000..9f34fc73953a4 --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/enum_discriminants.rs @@ -0,0 +1,110 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +// run-pass + +//! Make sure that we read and write enum discriminants correctly for corner cases caused +//! by layout optimizations. + +const OVERFLOW: usize = { + // Tests for https://github.com/rust-lang/rust/issues/62138. + #[repr(u8)] + #[allow(dead_code)] + enum WithWraparoundInvalidValues { + X = 1, + Y = 254, + } + + #[allow(dead_code)] + enum Foo { + A, + B, + C(WithWraparoundInvalidValues), + } + + let x = Foo::B; + match x { + Foo::B => 0, + _ => panic!(), + } +}; + +const MORE_OVERFLOW: usize = { + pub enum Infallible {} + + // The check that the `bool` field of `V1` is encoding a "niche variant" + // (i.e. not `V1`, so `V3` or `V4`) used to be mathematically incorrect, + // causing valid `V1` values to be interpreted as other variants. + #[allow(dead_code)] + pub enum E1 { + V1 { f: bool }, + V2 { f: Infallible }, + V3, + V4, + } + + // Computing the discriminant used to be done using the niche type (here `u8`, + // from the `bool` field of `V1`), overflowing for variants with large enough + // indices (`V3` and `V4`), causing them to be interpreted as other variants. + #[allow(dead_code)] + pub enum E2 { + V1 { f: bool }, + + /*_00*/ _01(X), _02(X), _03(X), _04(X), _05(X), _06(X), _07(X), + _08(X), _09(X), _0A(X), _0B(X), _0C(X), _0D(X), _0E(X), _0F(X), + _10(X), _11(X), _12(X), _13(X), _14(X), _15(X), _16(X), _17(X), + _18(X), _19(X), _1A(X), _1B(X), _1C(X), _1D(X), _1E(X), _1F(X), + _20(X), _21(X), _22(X), _23(X), _24(X), _25(X), _26(X), _27(X), + _28(X), _29(X), _2A(X), _2B(X), _2C(X), _2D(X), _2E(X), _2F(X), + _30(X), _31(X), _32(X), _33(X), _34(X), _35(X), _36(X), _37(X), + _38(X), _39(X), _3A(X), _3B(X), _3C(X), _3D(X), _3E(X), _3F(X), + _40(X), _41(X), _42(X), _43(X), _44(X), _45(X), _46(X), _47(X), + _48(X), _49(X), _4A(X), _4B(X), _4C(X), _4D(X), _4E(X), _4F(X), + _50(X), _51(X), _52(X), _53(X), _54(X), _55(X), _56(X), _57(X), + _58(X), _59(X), _5A(X), _5B(X), _5C(X), _5D(X), _5E(X), _5F(X), + _60(X), _61(X), _62(X), _63(X), _64(X), _65(X), _66(X), _67(X), + _68(X), _69(X), _6A(X), _6B(X), _6C(X), _6D(X), _6E(X), _6F(X), + _70(X), _71(X), _72(X), _73(X), _74(X), _75(X), _76(X), _77(X), + _78(X), _79(X), _7A(X), _7B(X), _7C(X), _7D(X), _7E(X), _7F(X), + _80(X), _81(X), _82(X), _83(X), _84(X), _85(X), _86(X), _87(X), + _88(X), _89(X), _8A(X), _8B(X), _8C(X), _8D(X), _8E(X), _8F(X), + _90(X), _91(X), _92(X), _93(X), _94(X), _95(X), _96(X), _97(X), + _98(X), _99(X), _9A(X), _9B(X), _9C(X), _9D(X), _9E(X), _9F(X), + _A0(X), _A1(X), _A2(X), _A3(X), _A4(X), _A5(X), _A6(X), _A7(X), + _A8(X), _A9(X), _AA(X), _AB(X), _AC(X), _AD(X), _AE(X), _AF(X), + _B0(X), _B1(X), _B2(X), _B3(X), _B4(X), _B5(X), _B6(X), _B7(X), + _B8(X), _B9(X), _BA(X), _BB(X), _BC(X), _BD(X), _BE(X), _BF(X), + _C0(X), _C1(X), _C2(X), _C3(X), _C4(X), _C5(X), _C6(X), _C7(X), + _C8(X), _C9(X), _CA(X), _CB(X), _CC(X), _CD(X), _CE(X), _CF(X), + _D0(X), _D1(X), _D2(X), _D3(X), _D4(X), _D5(X), _D6(X), _D7(X), + _D8(X), _D9(X), _DA(X), _DB(X), _DC(X), _DD(X), _DE(X), _DF(X), + _E0(X), _E1(X), _E2(X), _E3(X), _E4(X), _E5(X), _E6(X), _E7(X), + _E8(X), _E9(X), _EA(X), _EB(X), _EC(X), _ED(X), _EE(X), _EF(X), + _F0(X), _F1(X), _F2(X), _F3(X), _F4(X), _F5(X), _F6(X), _F7(X), + _F8(X), _F9(X), _FA(X), _FB(X), _FC(X), _FD(X), _FE(X), _FF(X), + + V3, + V4, + } + + if let E1::V2 { .. } = (E1::V1 { f: true }) { + unreachable!() + } + if let E1::V1 { .. } = (E1::V1 { f: true }) { + } else { + unreachable!() + } + + if let E2::V1 { .. } = E2::V3:: { + unreachable!() + } + if let E2::V3 { .. } = E2::V3:: { + } else { + unreachable!() + } + + 0 +}; + +fn main() { + assert_eq!(OVERFLOW, 0); + assert_eq!(MORE_OVERFLOW, 0); +} diff --git a/src/test/ui/consts/miri_unleashed/enum_discriminants.stderr b/src/test/ui/consts/miri_unleashed/enum_discriminants.stderr new file mode 100644 index 0000000000000..df366ba22e4d1 --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/enum_discriminants.stderr @@ -0,0 +1,24 @@ +warning: skipping const checks + --> $DIR/enum_discriminants.rs:23:13 + | +LL | let x = Foo::B; + | ^^^^^^ + +warning: skipping const checks + --> $DIR/enum_discriminants.rs:25:9 + | +LL | Foo::B => 0, + | ^^^^^^ + +warning: skipping const checks + --> $DIR/enum_discriminants.rs:88:28 + | +LL | if let E1::V2 { .. } = (E1::V1 { f: true }) { + | ^^^^^^^^^^^^^^^^^^^^ + +warning: skipping const checks + --> $DIR/enum_discriminants.rs:88:12 + | +LL | if let E1::V2 { .. } = (E1::V1 { f: true }) { + | ^^^^^^^^^^^^^ + diff --git a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs index 5fb92535502a5..8b17f6885ad3e 100644 --- a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs +++ b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs @@ -14,8 +14,9 @@ trait Bar> { impl Foo for () { const X: u32 = 42; } + impl Foo> for String { - const X: Vec = Vec::new(); //~ ERROR not yet stable as a const fn + const X: Vec = Vec::new(); } impl Bar for () {} diff --git a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr index c56ebf60df481..37016664ac58f 100644 --- a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr +++ b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr @@ -4,13 +4,6 @@ error[E0493]: destructors cannot be evaluated at compile-time LL | const F: u32 = (U::X, 42).1; | ^^^^^^^^^^ constants cannot evaluate destructors -error: `std::vec::Vec::::new` is not yet stable as a const fn - --> $DIR/feature-gate-unleash_the_miri_inside_of_you.rs:18:25 - | -LL | const X: Vec = Vec::new(); - | ^^^^^^^^^^ - | - = help: add `#![feature(const_vec_new)]` to the crate attributes to enable - -error: aborting due to 2 previous errors +error: aborting due to previous error +For more information about this error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.rs b/src/test/ui/consts/miri_unleashed/mutable_const.rs new file mode 100644 index 0000000000000..44b408494679c --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/mutable_const.rs @@ -0,0 +1,21 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you + +#![feature(const_raw_ptr_deref)] +#![deny(const_err)] + +use std::cell::UnsafeCell; + +// make sure we do not just intern this as mutable +const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; +//~^ WARN: skipping const checks + +const MUTATING_BEHIND_RAW: () = { + // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time. + unsafe { + *MUTABLE_BEHIND_RAW = 99 //~ WARN skipping const checks + //~^ ERROR any use of this value will cause an error + //~^^ tried to modify constant memory + } +}; + +fn main() {} diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.stderr b/src/test/ui/consts/miri_unleashed/mutable_const.stderr new file mode 100644 index 0000000000000..757f0ffb59ff7 --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/mutable_const.stderr @@ -0,0 +1,33 @@ +warning: skipping const checks + --> $DIR/mutable_const.rs:9:38 + | +LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; + | ^^^^^^^^^^^^^^^^^^^^ + +warning: skipping const checks + --> $DIR/mutable_const.rs:15:9 + | +LL | *MUTABLE_BEHIND_RAW = 99 + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: any use of this value will cause an error + --> $DIR/mutable_const.rs:15:9 + | +LL | / const MUTATING_BEHIND_RAW: () = { +LL | | // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time. +LL | | unsafe { +LL | | *MUTABLE_BEHIND_RAW = 99 + | | ^^^^^^^^^^^^^^^^^^^^^^^^ tried to modify constant memory +... | +LL | | } +LL | | }; + | |__- + | +note: lint level defined here + --> $DIR/mutable_const.rs:4:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.rs b/src/test/ui/consts/miri_unleashed/mutable_references.rs index 5f9888053a196..59dafcbf4d50c 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references.rs +++ b/src/test/ui/consts/miri_unleashed/mutable_references.rs @@ -6,12 +6,15 @@ use std::cell::UnsafeCell; // a test demonstrating what things we could allow with a smarter const qualification static FOO: &&mut u32 = &&mut 42; +//~^ WARN: skipping const checks static BAR: &mut () = &mut (); +//~^ WARN: skipping const checks struct Foo(T); static BOO: &mut Foo<()> = &mut Foo(()); +//~^ WARN: skipping const checks struct Meh { x: &'static UnsafeCell, @@ -21,15 +24,15 @@ unsafe impl Sync for Meh {} static MEH: Meh = Meh { x: &UnsafeCell::new(42), + //~^ WARN: skipping const checks }; static OH_YES: &mut i32 = &mut 42; +//~^ WARN: skipping const checks fn main() { unsafe { - *MEH.x.get() = 99; //~ WARN skipping const checks - //~^ WARN skipping const checks + *MEH.x.get() = 99; } *OH_YES = 99; //~ ERROR cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item - //~^ WARN skipping const checks } diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.stderr b/src/test/ui/consts/miri_unleashed/mutable_references.stderr index b870aca640a0a..e8a867307ce19 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references.stderr @@ -1,23 +1,35 @@ warning: skipping const checks - --> $DIR/mutable_references.rs:30:10 + --> $DIR/mutable_references.rs:8:26 | -LL | *MEH.x.get() = 99; - | ^^^^^ +LL | static FOO: &&mut u32 = &&mut 42; + | ^^^^^^^ warning: skipping const checks - --> $DIR/mutable_references.rs:30:9 + --> $DIR/mutable_references.rs:11:23 | -LL | *MEH.x.get() = 99; - | ^^^^^^^^^^^^^^^^^ +LL | static BAR: &mut () = &mut (); + | ^^^^^^^ warning: skipping const checks - --> $DIR/mutable_references.rs:33:5 + --> $DIR/mutable_references.rs:16:28 | -LL | *OH_YES = 99; - | ^^^^^^^^^^^^ +LL | static BOO: &mut Foo<()> = &mut Foo(()); + | ^^^^^^^^^^^^ + +warning: skipping const checks + --> $DIR/mutable_references.rs:26:8 + | +LL | x: &UnsafeCell::new(42), + | ^^^^^^^^^^^^^^^^^^^^ + +warning: skipping const checks + --> $DIR/mutable_references.rs:30:27 + | +LL | static OH_YES: &mut i32 = &mut 42; + | ^^^^^^^ error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item - --> $DIR/mutable_references.rs:33:5 + --> $DIR/mutable_references.rs:37:5 | LL | *OH_YES = 99; | ^^^^^^^^^^^^ cannot assign diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_ice.rs b/src/test/ui/consts/miri_unleashed/mutable_references_ice.rs index 4fcd89a74db61..635cad81c9798 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_ice.rs +++ b/src/test/ui/consts/miri_unleashed/mutable_references_ice.rs @@ -19,11 +19,11 @@ unsafe impl Sync for Meh {} // the following will never be ok! const MUH: Meh = Meh { - x: &UnsafeCell::new(42), + x: &UnsafeCell::new(42), //~ WARN: skipping const checks }; fn main() { unsafe { - *MUH.x.get() = 99; //~ WARN skipping const checks + *MUH.x.get() = 99; } } diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_ice.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_ice.stderr index 82569e260143c..c148842bcbc66 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_ice.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references_ice.stderr @@ -1,12 +1,12 @@ warning: skipping const checks - --> $DIR/mutable_references_ice.rs:27:9 + --> $DIR/mutable_references_ice.rs:22:8 | -LL | *MUH.x.get() = 99; - | ^^^^^^^^^^^^^^^^^ +LL | x: &UnsafeCell::new(42), + | ^^^^^^^^^^^^^^^^^^^^ thread 'rustc' panicked at 'assertion failed: `(left != right)` left: `Const`, - right: `Const`: UnsafeCells are not allowed behind references in constants. This should have been prevented statically by const qualification. If this were allowed one would be able to change a constant at one use site and other use sites may arbitrarily decide to change, too.', src/librustc_mir/interpret/intern.rs:LL:CC + right: `Const`: UnsafeCells are not allowed behind references in constants. This should have been prevented statically by const qualification. If this were allowed one would be able to change a constant at one use site and other use sites could observe that mutation.', src/librustc_mir/interpret/intern.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. error: internal compiler error: unexpected panic diff --git a/src/test/ui/consts/packed_pattern.stderr b/src/test/ui/consts/packed_pattern.stderr new file mode 100644 index 0000000000000..9b7daf2e674fb --- /dev/null +++ b/src/test/ui/consts/packed_pattern.stderr @@ -0,0 +1,8 @@ +warning: unreachable pattern + --> $DIR/packed_pattern.rs:16:9 + | +LL | FOO => unreachable!(), + | ^^^ + | + = note: `#[warn(unreachable_patterns)]` on by default + diff --git a/src/test/ui/consts/packed_pattern2.stderr b/src/test/ui/consts/packed_pattern2.stderr new file mode 100644 index 0000000000000..6cc0225d3043d --- /dev/null +++ b/src/test/ui/consts/packed_pattern2.stderr @@ -0,0 +1,8 @@ +warning: unreachable pattern + --> $DIR/packed_pattern2.rs:24:9 + | +LL | FOO => unreachable!(), + | ^^^ + | + = note: `#[warn(unreachable_patterns)]` on by default + diff --git a/src/test/ui/consts/promote_const_let.polonius.stderr b/src/test/ui/consts/promote_const_let.polonius.stderr deleted file mode 100644 index cf41bd7bdb1eb..0000000000000 --- a/src/test/ui/consts/promote_const_let.polonius.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0597]: `y` does not live long enough - --> $DIR/promote_const_let.rs:4:9 - | -LL | let x: &'static u32 = { - | - borrow later stored here -LL | let y = 42; -LL | &y - | ^^ borrowed value does not live long enough -LL | }; - | - `y` dropped here while still borrowed - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promote_const_let.rs:6:28 - | -LL | let x: &'static u32 = &{ - | ____________------------____^ - | | | - | | type annotation requires that borrow lasts for `'static` -LL | | let y = 42; -LL | | y -LL | | }; - | |_____^ creates a temporary which is freed while still in use -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0597, E0716. -For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/consts/std/alloc.stderr b/src/test/ui/consts/std/alloc.stderr index 74a8f3daf6aaa..26b7a24ebfa6f 100644 --- a/src/test/ui/consts/std/alloc.stderr +++ b/src/test/ui/consts/std/alloc.stderr @@ -4,7 +4,7 @@ error[E0080]: it is undefined behavior to use this value LL | const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0 at .align_, but expected something greater or equal to 1 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: aborting due to previous error diff --git a/src/test/ui/consts/too_generic_eval_ice.rs b/src/test/ui/consts/too_generic_eval_ice.rs new file mode 100644 index 0000000000000..7a299169bc4e1 --- /dev/null +++ b/src/test/ui/consts/too_generic_eval_ice.rs @@ -0,0 +1,13 @@ +pub struct Foo(A, B); + +impl Foo { + const HOST_SIZE: usize = std::mem::size_of::(); + + pub fn crash() -> bool { + [5; Self::HOST_SIZE] == [6; 0] //~ ERROR no associated item named `HOST_SIZE` + //~^ the size for values of type `A` cannot be known + //~| the size for values of type `B` cannot be known + } +} + +fn main() {} diff --git a/src/test/ui/consts/too_generic_eval_ice.stderr b/src/test/ui/consts/too_generic_eval_ice.stderr new file mode 100644 index 0000000000000..0733a51233e33 --- /dev/null +++ b/src/test/ui/consts/too_generic_eval_ice.stderr @@ -0,0 +1,43 @@ +error[E0599]: no associated item named `HOST_SIZE` found for type `Foo` in the current scope + --> $DIR/too_generic_eval_ice.rs:7:19 + | +LL | pub struct Foo(A, B); + | --------------------------- associated item `HOST_SIZE` not found for this +... +LL | [5; Self::HOST_SIZE] == [6; 0] + | ^^^^^^^^^ associated item not found in `Foo` + | + = note: the method `HOST_SIZE` exists but the following trait bounds were not satisfied: + `A : std::marker::Sized` + `B : std::marker::Sized` + +error[E0277]: the size for values of type `A` cannot be known at compilation time + --> $DIR/too_generic_eval_ice.rs:7:13 + | +LL | pub struct Foo(A, B); + | --------------------------- required by `Foo` +... +LL | [5; Self::HOST_SIZE] == [6; 0] + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `A` + = note: to learn more, visit + = help: consider adding a `where A: std::marker::Sized` bound + +error[E0277]: the size for values of type `B` cannot be known at compilation time + --> $DIR/too_generic_eval_ice.rs:7:13 + | +LL | pub struct Foo(A, B); + | --------------------------- required by `Foo` +... +LL | [5; Self::HOST_SIZE] == [6; 0] + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `B` + = note: to learn more, visit + = help: consider adding a `where B: std::marker::Sized` bound + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0599. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.rs b/src/test/ui/consts/uninhabited-const-issue-61744.rs index 21fbbf8cfb5a8..4509ebc6338a8 100644 --- a/src/test/ui/consts/uninhabited-const-issue-61744.rs +++ b/src/test/ui/consts/uninhabited-const-issue-61744.rs @@ -1,11 +1,11 @@ // compile-fail pub const unsafe fn fake_type() -> T { - hint_unreachable() + hint_unreachable() //~ ERROR any use of this value will cause an error } pub const unsafe fn hint_unreachable() -> ! { - fake_type() //~ ERROR any use of this value will cause an error + fake_type() } trait Const { diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.stderr b/src/test/ui/consts/uninhabited-const-issue-61744.stderr index e317bdf103c36..f390676fda6d0 100644 --- a/src/test/ui/consts/uninhabited-const-issue-61744.stderr +++ b/src/test/ui/consts/uninhabited-const-issue-61744.stderr @@ -1,11 +1,60 @@ error: any use of this value will cause an error - --> $DIR/uninhabited-const-issue-61744.rs:8:5 + --> $DIR/uninhabited-const-issue-61744.rs:4:5 | -LL | fake_type() - | ^^^^^^^^^^^ +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ | | - | tried to call a function with return type T passing return place of type ! + | reached the configured maximum number of stack frames | inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:12:36 ... LL | const CONSTANT: i32 = unsafe { fake_type() }; diff --git a/src/test/ui/consts/validate_never_arrays.stderr b/src/test/ui/consts/validate_never_arrays.stderr index 7a7d816873350..c4c7a33718279 100644 --- a/src/test/ui/consts/validate_never_arrays.stderr +++ b/src/test/ui/consts/validate_never_arrays.stderr @@ -4,7 +4,7 @@ error[E0080]: it is undefined behavior to use this value LL | const FOO: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at . | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: aborting due to previous error diff --git a/src/test/ui/consts/zst_no_llvm_alloc.rs b/src/test/ui/consts/zst_no_llvm_alloc.rs new file mode 100644 index 0000000000000..5d779355400cc --- /dev/null +++ b/src/test/ui/consts/zst_no_llvm_alloc.rs @@ -0,0 +1,19 @@ +// run-pass + +#[repr(align(4))] +struct Foo; + +static FOO: Foo = Foo; + +fn main() { + let x: &'static () = &(); + assert_eq!(x as *const () as usize, 1); + let x: &'static Foo = &Foo; + assert_eq!(x as *const Foo as usize, 4); + + // statics must have a unique address + assert_ne!(&FOO as *const Foo as usize, 4); + + assert_eq!(>::new().as_ptr(), <&[i32]>::default().as_ptr()); + assert_eq!(>::default().as_ptr(), (&[]).as_ptr()); +} diff --git a/src/test/ui/continue-after-missing-main.nll.stderr b/src/test/ui/continue-after-missing-main.nll.stderr index aceabf3316479..b94c365f2539a 100644 --- a/src/test/ui/continue-after-missing-main.nll.stderr +++ b/src/test/ui/continue-after-missing-main.nll.stderr @@ -1,6 +1,14 @@ error[E0601]: `main` function not found in crate `continue_after_missing_main` + --> $DIR/continue-after-missing-main.rs:1:1 | - = note: consider adding a `main` function to `$DIR/continue-after-missing-main.rs` +LL | / #![allow(dead_code)] +LL | | +LL | | // error-pattern:`main` function not found in crate +LL | | +... | +LL | | +LL | | } + | |_^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs` error: aborting due to previous error diff --git a/src/test/ui/continue-after-missing-main.stderr b/src/test/ui/continue-after-missing-main.stderr index cc5f87659079e..d764e7d860af6 100644 --- a/src/test/ui/continue-after-missing-main.stderr +++ b/src/test/ui/continue-after-missing-main.stderr @@ -1,6 +1,14 @@ error[E0601]: `main` function not found in crate `continue_after_missing_main` + --> $DIR/continue-after-missing-main.rs:1:1 | - = note: consider adding a `main` function to `$DIR/continue-after-missing-main.rs` +LL | / #![allow(dead_code)] +LL | | +LL | | // error-pattern:`main` function not found in crate +LL | | +... | +LL | | +LL | | } + | |_^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs` error[E0623]: lifetime mismatch --> $DIR/continue-after-missing-main.rs:30:56 diff --git a/src/test/ui/conversion-methods.stderr b/src/test/ui/conversion-methods.stderr index b9662e7607494..5c666afb89a33 100644 --- a/src/test/ui/conversion-methods.stderr +++ b/src/test/ui/conversion-methods.stderr @@ -41,7 +41,7 @@ LL | let _prove_piercing_earnest: Vec = &[1, 2, 3]; | ^^^^^^^^^^ | | | expected struct `std::vec::Vec`, found reference - | help: try using a conversion method: `&[1, 2, 3].to_vec()` + | help: try using a conversion method: `(&[1, 2, 3]).to_vec()` | = note: expected type `std::vec::Vec` found type `&[{integer}; 3]` diff --git a/src/test/ui/copy-a-resource.stderr b/src/test/ui/copy-a-resource.stderr index cceb9e328b676..054bd0914d31c 100644 --- a/src/test/ui/copy-a-resource.stderr +++ b/src/test/ui/copy-a-resource.stderr @@ -5,7 +5,7 @@ LL | struct Foo { | ---------- method `clone` not found for this ... LL | let _y = x.clone(); - | ^^^^^ + | ^^^^^ method not found in `Foo` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: diff --git a/src/test/ui/custom_attribute.rs b/src/test/ui/custom_attribute.rs index 13c873c3b7e48..4957184229da0 100644 --- a/src/test/ui/custom_attribute.rs +++ b/src/test/ui/custom_attribute.rs @@ -1,9 +1,9 @@ #![feature(stmt_expr_attributes)] -#[foo] //~ ERROR cannot find attribute macro `foo` in this scope +#[foo] //~ ERROR cannot find attribute `foo` in this scope fn main() { - #[foo] //~ ERROR cannot find attribute macro `foo` in this scope + #[foo] //~ ERROR cannot find attribute `foo` in this scope let x = (); - #[foo] //~ ERROR cannot find attribute macro `foo` in this scope + #[foo] //~ ERROR cannot find attribute `foo` in this scope x } diff --git a/src/test/ui/custom_attribute.stderr b/src/test/ui/custom_attribute.stderr index b4f9f3f49b235..4023892d29466 100644 --- a/src/test/ui/custom_attribute.stderr +++ b/src/test/ui/custom_attribute.stderr @@ -1,16 +1,16 @@ -error: cannot find attribute macro `foo` in this scope +error: cannot find attribute `foo` in this scope --> $DIR/custom_attribute.rs:3:3 | LL | #[foo] | ^^^ -error: cannot find attribute macro `foo` in this scope +error: cannot find attribute `foo` in this scope --> $DIR/custom_attribute.rs:5:7 | LL | #[foo] | ^^^ -error: cannot find attribute macro `foo` in this scope +error: cannot find attribute `foo` in this scope --> $DIR/custom_attribute.rs:7:7 | LL | #[foo] diff --git a/src/test/ui/dead-code-ret.stderr b/src/test/ui/dead-code-ret.stderr index 092a176f443b2..83841131599b2 100644 --- a/src/test/ui/dead-code-ret.stderr +++ b/src/test/ui/dead-code-ret.stderr @@ -1,8 +1,10 @@ error: unreachable statement --> $DIR/dead-code-ret.rs:7:5 | +LL | return; + | ------ any code following this expression is unreachable LL | println!("Paul is dead"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement | note: lint level defined here --> $DIR/dead-code-ret.rs:3:9 diff --git a/src/test/ui/defaulted-never-note.rs b/src/test/ui/defaulted-never-note.rs index cf1922ecc789f..d3fb8a09414ce 100644 --- a/src/test/ui/defaulted-never-note.rs +++ b/src/test/ui/defaulted-never-note.rs @@ -19,7 +19,8 @@ trait ImplementedForUnitButNotNever {} impl ImplementedForUnitButNotNever for () {} fn foo(_t: T) {} -//~^ NOTE required by `foo` +//~^ NOTE required by this bound in `foo` +//~| NOTE fn smeg() { let _x = return; diff --git a/src/test/ui/defaulted-never-note.stderr b/src/test/ui/defaulted-never-note.stderr index 45174c322947d..28c9da059edaa 100644 --- a/src/test/ui/defaulted-never-note.stderr +++ b/src/test/ui/defaulted-never-note.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `!: ImplementedForUnitButNotNever` is not satisfied - --> $DIR/defaulted-never-note.rs:26:5 + --> $DIR/defaulted-never-note.rs:27:5 | +LL | fn foo(_t: T) {} + | --- ----------------------------- required by this bound in `foo` +... LL | foo(_x); | ^^^ the trait `ImplementedForUnitButNotNever` is not implemented for `!` | = note: the trait is implemented for `()`. Possibly this error has been caused by changes to Rust's type-inference algorithm (see: https://github.com/rust-lang/rust/issues/48950 for more info). Consider whether you meant to use the type `()` here instead. -note: required by `foo` - --> $DIR/defaulted-never-note.rs:21:1 - | -LL | fn foo(_t: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/definition-reachable/auxiliary/field-method-macro.rs b/src/test/ui/definition-reachable/auxiliary/field-method-macro.rs new file mode 100644 index 0000000000000..30ba70bdfeb66 --- /dev/null +++ b/src/test/ui/definition-reachable/auxiliary/field-method-macro.rs @@ -0,0 +1,23 @@ +#![feature(decl_macro)] + +mod n { + pub struct B(pub(crate) p::C); + impl B { + pub fn new() -> Self { + B(p::C) + } + } + mod p { + pub struct C; + + impl C { + pub fn foo(&self) -> i32 { + 33 + } + } + } +} + +pub macro m() { + n::B::new().0.foo() +} diff --git a/src/test/ui/definition-reachable/auxiliary/nested-fn-macro.rs b/src/test/ui/definition-reachable/auxiliary/nested-fn-macro.rs new file mode 100644 index 0000000000000..a39e8c986c391 --- /dev/null +++ b/src/test/ui/definition-reachable/auxiliary/nested-fn-macro.rs @@ -0,0 +1,11 @@ +#![feature(decl_macro)] + +mod n { + pub(crate) mod p { + pub fn f() -> i32 { 12 } + } +} + +pub macro m() { + n::p::f() +} diff --git a/src/test/ui/definition-reachable/auxiliary/private-use-macro.rs b/src/test/ui/definition-reachable/auxiliary/private-use-macro.rs new file mode 100644 index 0000000000000..4f283d9c19c04 --- /dev/null +++ b/src/test/ui/definition-reachable/auxiliary/private-use-macro.rs @@ -0,0 +1,11 @@ +#![feature(decl_macro)] + +mod n { + pub static S: i32 = 57; +} + +use n::S; + +pub macro m() { + S +} diff --git a/src/test/ui/definition-reachable/field-method.rs b/src/test/ui/definition-reachable/field-method.rs new file mode 100644 index 0000000000000..60e895a2f9a07 --- /dev/null +++ b/src/test/ui/definition-reachable/field-method.rs @@ -0,0 +1,11 @@ +// Check that functions accessible through a field visible to a macro are +// considered reachable + +// aux-build:nested-fn-macro.rs +// run-pass + +extern crate nested_fn_macro; + +fn main() { + assert_eq!(nested_fn_macro::m!(), 12); +} diff --git a/src/test/ui/definition-reachable/nested-fn.rs b/src/test/ui/definition-reachable/nested-fn.rs new file mode 100644 index 0000000000000..b596ba8936a43 --- /dev/null +++ b/src/test/ui/definition-reachable/nested-fn.rs @@ -0,0 +1,11 @@ +// Check that functions visible to macros through paths with >2 segements are +// considered reachable + +// aux-build:field-method-macro.rs +// run-pass + +extern crate field_method_macro; + +fn main() { + assert_eq!(field_method_macro::m!(), 33); +} diff --git a/src/test/ui/definition-reachable/private-non-types.rs b/src/test/ui/definition-reachable/private-non-types.rs new file mode 100644 index 0000000000000..a601dabcb0b3f --- /dev/null +++ b/src/test/ui/definition-reachable/private-non-types.rs @@ -0,0 +1,21 @@ +// Check that we don't require stability annotations for private modules, +// imports and fields that are accessible to opaque macros. + +// check-pass + +#![feature(decl_macro, staged_api)] +#![stable(feature = "test", since = "1.0.0")] + +extern crate std as local_std; +use local_std::marker::Copy as LocalCopy; +mod private_mod { + #[stable(feature = "test", since = "1.0.0")] + pub struct A { + pub(crate) f: i32, + } +} + +#[stable(feature = "test", since = "1.0.0")] +pub macro m() {} + +fn main() {} diff --git a/src/test/ui/definition-reachable/private-types.rs b/src/test/ui/definition-reachable/private-types.rs new file mode 100644 index 0000000000000..02c1224f4e142 --- /dev/null +++ b/src/test/ui/definition-reachable/private-types.rs @@ -0,0 +1,19 @@ +// Check that type privacy is taken into account when considering reachability + +// check-pass + +#![feature(decl_macro, staged_api)] +#![stable(feature = "test", since = "1.0.0")] + +// Type privacy should prevent use of these in other crates, so we shouldn't +// need a stability annotation. +fn private_function() {} +struct PrivateStruct { f: () } +enum PrivateEnum { V } +union PrivateUnion { g: () } +trait PrivateTrait {} + +#[stable(feature = "test", since = "1.0.0")] +pub macro m() {} + +fn main() {} diff --git a/src/test/ui/definition-reachable/private-use.rs b/src/test/ui/definition-reachable/private-use.rs new file mode 100644 index 0000000000000..02cff0475e586 --- /dev/null +++ b/src/test/ui/definition-reachable/private-use.rs @@ -0,0 +1,10 @@ +// Check that private use statements can be used by + +// run-pass +// aux-build:private-use-macro.rs + +extern crate private_use_macro; + +fn main() { + assert_eq!(private_use_macro::m!(), 57); +} diff --git a/src/test/ui/deprecation/deprecation-in-future.rs b/src/test/ui/deprecation/deprecation-in-future.rs index c4f9fdce74907..464ddcc4cdb94 100644 --- a/src/test/ui/deprecation/deprecation-in-future.rs +++ b/src/test/ui/deprecation/deprecation-in-future.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![deny(deprecated_in_future)] diff --git a/src/test/ui/deprecation/deprecation-sanity.stderr b/src/test/ui/deprecation/deprecation-sanity.stderr index 7ff68a1038b1c..57143d6810554 100644 --- a/src/test/ui/deprecation/deprecation-sanity.stderr +++ b/src/test/ui/deprecation/deprecation-sanity.stderr @@ -54,5 +54,5 @@ LL | #[deprecated(since = "a", since = "b", note = "c")] error: aborting due to 9 previous errors -Some errors have detailed explanations: E0538, E0541, E0565. +Some errors have detailed explanations: E0538, E0541, E0550, E0551, E0565. For more information about an error, try `rustc --explain E0538`. diff --git a/src/test/ui/deprecation/derive_on_deprecated.rs b/src/test/ui/deprecation/derive_on_deprecated.rs index ed4055ecdd38c..ac771ac81d118 100644 --- a/src/test/ui/deprecation/derive_on_deprecated.rs +++ b/src/test/ui/deprecation/derive_on_deprecated.rs @@ -6,4 +6,10 @@ #[derive(Default)] struct X; +#[deprecated(note="Do not use this")] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash)] +pub struct Step { + _skip: Option, +} + fn main() {} diff --git a/src/test/ui/derive-uninhabited-enum-38885.rs b/src/test/ui/derive-uninhabited-enum-38885.rs index 2c4d64e4e6063..010464adf5bce 100644 --- a/src/test/ui/derive-uninhabited-enum-38885.rs +++ b/src/test/ui/derive-uninhabited-enum-38885.rs @@ -5,12 +5,15 @@ // when deriving Debug on an empty enum #[derive(Debug)] -enum Void {} //~ WARN never used +enum Void {} #[derive(Debug)] -enum Foo { //~ WARN never used +enum Foo { Bar(u8), - Void(Void), + Void(Void), //~ WARN never used } -fn main() {} +fn main() { + let x = Foo::Bar(42); + println!("{:?}", x); +} diff --git a/src/test/ui/derive-uninhabited-enum-38885.stderr b/src/test/ui/derive-uninhabited-enum-38885.stderr index 941c98b5506b2..a3ed6798a7039 100644 --- a/src/test/ui/derive-uninhabited-enum-38885.stderr +++ b/src/test/ui/derive-uninhabited-enum-38885.stderr @@ -1,14 +1,8 @@ -warning: enum is never used: `Void` - --> $DIR/derive-uninhabited-enum-38885.rs:8:1 +warning: variant is never constructed: `Void` + --> $DIR/derive-uninhabited-enum-38885.rs:13:5 | -LL | enum Void {} - | ^^^^^^^^^ +LL | Void(Void), + | ^^^^^^^^^^ | = note: `-W dead-code` implied by `-W unused` -warning: enum is never used: `Foo` - --> $DIR/derive-uninhabited-enum-38885.rs:11:1 - | -LL | enum Foo { - | ^^^^^^^^ - diff --git a/src/test/ui/derived-errors/issue-30580.stderr b/src/test/ui/derived-errors/issue-30580.stderr index 14c575f2699a6..7bd0eaf77a95d 100644 --- a/src/test/ui/derived-errors/issue-30580.stderr +++ b/src/test/ui/derived-errors/issue-30580.stderr @@ -2,7 +2,7 @@ error[E0609]: no field `c` on type `&Foo` --> $DIR/issue-30580.rs:12:11 | LL | b.c; - | ^ + | ^ help: a field with a similar name exists: `a` error: aborting due to previous error diff --git a/src/test/ui/derived-errors/issue-31997.rs b/src/test/ui/derived-errors/issue-31997.rs index cfdee26c5599c..ff619313afb5b 100644 --- a/src/test/ui/derived-errors/issue-31997.rs +++ b/src/test/ui/derived-errors/issue-31997.rs @@ -1,5 +1,6 @@ // Test that the resolve failure does not lead to downstream type errors. // See issue #31997. +#![allow(deprecated)] trait TheTrait { } diff --git a/src/test/ui/derived-errors/issue-31997.stderr b/src/test/ui/derived-errors/issue-31997.stderr index e9fe0d3971ee6..b53c0cda8de4d 100644 --- a/src/test/ui/derived-errors/issue-31997.stderr +++ b/src/test/ui/derived-errors/issue-31997.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find function `bar` in this scope - --> $DIR/issue-31997.rs:13:21 + --> $DIR/issue-31997.rs:14:21 | LL | try!(closure(|| bar(core::ptr::null_mut()))); | ^^^ not found in this scope diff --git a/src/test/ui/derives/derive-assoc-type-not-impl.stderr b/src/test/ui/derives/derive-assoc-type-not-impl.stderr index b9e175e43d1cf..038de80508ac2 100644 --- a/src/test/ui/derives/derive-assoc-type-not-impl.stderr +++ b/src/test/ui/derives/derive-assoc-type-not-impl.stderr @@ -5,7 +5,7 @@ LL | struct Bar { | ------------------ method `clone` not found for this ... LL | Bar:: { x: 1 }.clone(); - | ^^^^^ + | ^^^^^ method not found in `Bar` | = note: the method `clone` exists but the following trait bounds were not satisfied: `Bar : std::clone::Clone` diff --git a/src/test/ui/derives/derive-hygiene.rs b/src/test/ui/derives/derive-hygiene.rs new file mode 100644 index 0000000000000..4fa83c490383c --- /dev/null +++ b/src/test/ui/derives/derive-hygiene.rs @@ -0,0 +1,121 @@ +// Make sure that built-in derives don't rely on the user not declaring certain +// names to work properly. + +// check-pass + +#![allow(nonstandard_style)] +#![feature(decl_macro)] + +use std::prelude::v1::test as inline; + +static f: () = (); +static cmp: () = (); +static other: () = (); +static state: () = (); +static __self_0_0: () = (); +static __self_1_0: () = (); +static __self_vi: () = (); +static __arg_1_0: () = (); +static debug_trait_builder: () = (); + +struct isize; +trait i16 {} + +trait MethodsInDerives: Sized { + fn debug_tuple(self) {} + fn debug_struct(self) {} + fn field(self) {} + fn finish(self) {} + fn clone(self) {} + fn cmp(self) {} + fn partial_cmp(self) {} + fn eq(self) {} + fn ne(self) {} + fn le(self) {} + fn lt(self) {} + fn ge(self) {} + fn gt(self) {} + fn hash(self) {} +} + +trait GenericAny {} +impl GenericAny for S {} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +enum __H { V(i32), } + +#[repr(i16)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +enum W { A, B } + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)] +struct X>> { + A: A, +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)] +struct Y(B) +where + B: From; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +enum Z { + C(C), + B { C: C }, +} + +// Make sure that we aren't using `self::` in paths, since it doesn't work in +// non-module scopes. +const NON_MODULE: () = { + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] + enum __H { V(i32), } + + #[repr(i16)] + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] + enum W { A, B } + + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)] + struct X self::X> { + A: A, + } + + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)] + struct Y(B) + where + B: From; + + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] + enum Z { + C(C), + B { C: C }, + } +}; + +macro m() { + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] + enum __H { V(i32), } + + #[repr(i16)] + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] + enum W { A, B } + + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)] + struct X>> { + A: A, + } + + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)] + struct Y(B) + where + B: From; + + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] + enum Z { + C(C), + B { C: C }, + } +} + +m!(); + +fn main() {} diff --git a/src/test/ui/derives/derives-span-Hash-enum-struct-variant.rs b/src/test/ui/derives/derives-span-Hash-enum-struct-variant.rs index 3018a7b6d03ee..ed87360a0be9f 100644 --- a/src/test/ui/derives/derives-span-Hash-enum-struct-variant.rs +++ b/src/test/ui/derives/derives-span-Hash-enum-struct-variant.rs @@ -1,3 +1,5 @@ +// ignore-x86 +// ^ due to stderr output differences // This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' diff --git a/src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr index 417c720c63e99..708ebca9fb153 100644 --- a/src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr @@ -1,10 +1,13 @@ error[E0277]: the trait bound `Error: std::hash::Hash` is not satisfied - --> $DIR/derives-span-Hash-enum-struct-variant.rs:9:6 + --> $DIR/derives-span-Hash-enum-struct-variant.rs:11:6 | LL | x: Error | ^^^^^^^^ the trait `std::hash::Hash` is not implemented for `Error` + | + ::: $SRC_DIR/libcore/hash/mod.rs:LL:COL | - = note: required by `std::hash::Hash::hash` +LL | fn hash(&self, state: &mut H); + | - required by this bound in `std::hash::Hash::hash` error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Hash-enum.rs b/src/test/ui/derives/derives-span-Hash-enum.rs index bb656e5c2fe3c..5b3649c9826e6 100644 --- a/src/test/ui/derives/derives-span-Hash-enum.rs +++ b/src/test/ui/derives/derives-span-Hash-enum.rs @@ -1,3 +1,5 @@ +// ignore-x86 +// ^ due to stderr output differences // This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' diff --git a/src/test/ui/derives/derives-span-Hash-enum.stderr b/src/test/ui/derives/derives-span-Hash-enum.stderr index 25be8794889fc..dc171cbe5dd13 100644 --- a/src/test/ui/derives/derives-span-Hash-enum.stderr +++ b/src/test/ui/derives/derives-span-Hash-enum.stderr @@ -1,10 +1,13 @@ error[E0277]: the trait bound `Error: std::hash::Hash` is not satisfied - --> $DIR/derives-span-Hash-enum.rs:9:6 + --> $DIR/derives-span-Hash-enum.rs:11:6 | LL | Error | ^^^^^ the trait `std::hash::Hash` is not implemented for `Error` + | + ::: $SRC_DIR/libcore/hash/mod.rs:LL:COL | - = note: required by `std::hash::Hash::hash` +LL | fn hash(&self, state: &mut H); + | - required by this bound in `std::hash::Hash::hash` error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Hash-struct.rs b/src/test/ui/derives/derives-span-Hash-struct.rs index fa5e2af6be870..ead70861a0ad6 100644 --- a/src/test/ui/derives/derives-span-Hash-struct.rs +++ b/src/test/ui/derives/derives-span-Hash-struct.rs @@ -1,3 +1,5 @@ +// ignore-x86 +// ^ due to stderr output differences // This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' diff --git a/src/test/ui/derives/derives-span-Hash-struct.stderr b/src/test/ui/derives/derives-span-Hash-struct.stderr index c0574453a7a6b..429449b82bf64 100644 --- a/src/test/ui/derives/derives-span-Hash-struct.stderr +++ b/src/test/ui/derives/derives-span-Hash-struct.stderr @@ -1,10 +1,13 @@ error[E0277]: the trait bound `Error: std::hash::Hash` is not satisfied - --> $DIR/derives-span-Hash-struct.rs:8:5 + --> $DIR/derives-span-Hash-struct.rs:10:5 | LL | x: Error | ^^^^^^^^ the trait `std::hash::Hash` is not implemented for `Error` + | + ::: $SRC_DIR/libcore/hash/mod.rs:LL:COL | - = note: required by `std::hash::Hash::hash` +LL | fn hash(&self, state: &mut H); + | - required by this bound in `std::hash::Hash::hash` error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Hash-tuple-struct.rs b/src/test/ui/derives/derives-span-Hash-tuple-struct.rs index 3822bce1466ea..820f13ed18ef2 100644 --- a/src/test/ui/derives/derives-span-Hash-tuple-struct.rs +++ b/src/test/ui/derives/derives-span-Hash-tuple-struct.rs @@ -1,3 +1,5 @@ +// ignore-x86 +// ^ due to stderr output differences // This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' diff --git a/src/test/ui/derives/derives-span-Hash-tuple-struct.stderr b/src/test/ui/derives/derives-span-Hash-tuple-struct.stderr index 6339c38578eb8..a6c4c479b24d7 100644 --- a/src/test/ui/derives/derives-span-Hash-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Hash-tuple-struct.stderr @@ -1,10 +1,13 @@ error[E0277]: the trait bound `Error: std::hash::Hash` is not satisfied - --> $DIR/derives-span-Hash-tuple-struct.rs:8:5 + --> $DIR/derives-span-Hash-tuple-struct.rs:10:5 | LL | Error | ^^^^^ the trait `std::hash::Hash` is not implemented for `Error` + | + ::: $SRC_DIR/libcore/hash/mod.rs:LL:COL | - = note: required by `std::hash::Hash::hash` +LL | fn hash(&self, state: &mut H); + | - required by this bound in `std::hash::Hash::hash` error: aborting due to previous error diff --git a/src/test/ui/derives/deriving-bounds.stderr b/src/test/ui/derives/deriving-bounds.stderr index 99976da72da1d..b18df3511817d 100644 --- a/src/test/ui/derives/deriving-bounds.stderr +++ b/src/test/ui/derives/deriving-bounds.stderr @@ -1,15 +1,3 @@ -error: cannot find derive macro `Send` in this scope - --> $DIR/deriving-bounds.rs:1:10 - | -LL | #[derive(Send)] - | ^^^^ - | -note: unsafe traits like `Send` should be implemented explicitly - --> $DIR/deriving-bounds.rs:1:10 - | -LL | #[derive(Send)] - | ^^^^ - error: cannot find derive macro `Sync` in this scope --> $DIR/deriving-bounds.rs:5:10 | @@ -22,5 +10,17 @@ note: unsafe traits like `Sync` should be implemented explicitly LL | #[derive(Sync)] | ^^^^ +error: cannot find derive macro `Send` in this scope + --> $DIR/deriving-bounds.rs:1:10 + | +LL | #[derive(Send)] + | ^^^^ + | +note: unsafe traits like `Send` should be implemented explicitly + --> $DIR/deriving-bounds.rs:1:10 + | +LL | #[derive(Send)] + | ^^^^ + error: aborting due to 2 previous errors diff --git a/src/test/ui/derives/deriving-copyclone.stderr b/src/test/ui/derives/deriving-copyclone.stderr index e6060c269e10a..4cca14ae089e9 100644 --- a/src/test/ui/derives/deriving-copyclone.stderr +++ b/src/test/ui/derives/deriving-copyclone.stderr @@ -1,41 +1,35 @@ error[E0277]: the trait bound `C: std::marker::Copy` is not satisfied - --> $DIR/deriving-copyclone.rs:31:5 + --> $DIR/deriving-copyclone.rs:31:13 | +LL | fn is_copy(_: T) {} + | ------- ---- required by this bound in `is_copy` +... LL | is_copy(B { a: 1, b: C }); - | ^^^^^^^ the trait `std::marker::Copy` is not implemented for `C` + | ^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `C` | = note: required because of the requirements on the impl of `std::marker::Copy` for `B` -note: required by `is_copy` - --> $DIR/deriving-copyclone.rs:18:1 - | -LL | fn is_copy(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `C: std::clone::Clone` is not satisfied - --> $DIR/deriving-copyclone.rs:32:5 + --> $DIR/deriving-copyclone.rs:32:14 | +LL | fn is_clone(_: T) {} + | -------- ----- required by this bound in `is_clone` +... LL | is_clone(B { a: 1, b: C }); - | ^^^^^^^^ the trait `std::clone::Clone` is not implemented for `C` + | ^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `C` | = note: required because of the requirements on the impl of `std::clone::Clone` for `B` -note: required by `is_clone` - --> $DIR/deriving-copyclone.rs:19:1 - | -LL | fn is_clone(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `D: std::marker::Copy` is not satisfied - --> $DIR/deriving-copyclone.rs:35:5 + --> $DIR/deriving-copyclone.rs:35:13 | +LL | fn is_copy(_: T) {} + | ------- ---- required by this bound in `is_copy` +... LL | is_copy(B { a: 1, b: D }); - | ^^^^^^^ the trait `std::marker::Copy` is not implemented for `D` + | ^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `D` | = note: required because of the requirements on the impl of `std::marker::Copy` for `B` -note: required by `is_copy` - --> $DIR/deriving-copyclone.rs:18:1 - | -LL | fn is_copy(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr index cfb1da037dc07..1bd4543f2316c 100644 --- a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr +++ b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `i8: Foo` is not satisfied - --> $DIR/issue-39802-show-5-trait-impls.rs:24:5 + --> $DIR/issue-39802-show-5-trait-impls.rs:24:21 | +LL | fn bar(&self){} + | ------------- required by `Foo::bar` +... LL | Foo::::bar(&1i8); - | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i8` + | ^^^^ the trait `Foo` is not implemented for `i8` | = help: the following implementations were found: > @@ -10,34 +13,30 @@ LL | Foo::::bar(&1i8); > > > -note: required by `Foo::bar` - --> $DIR/issue-39802-show-5-trait-impls.rs:2:5 - | -LL | fn bar(&self){} - | ^^^^^^^^^^^^^ error[E0277]: the trait bound `u8: Foo` is not satisfied - --> $DIR/issue-39802-show-5-trait-impls.rs:25:5 + --> $DIR/issue-39802-show-5-trait-impls.rs:25:21 | +LL | fn bar(&self){} + | ------------- required by `Foo::bar` +... LL | Foo::::bar(&1u8); - | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `u8` + | ^^^^ the trait `Foo` is not implemented for `u8` | = help: the following implementations were found: > > > > -note: required by `Foo::bar` - --> $DIR/issue-39802-show-5-trait-impls.rs:2:5 - | -LL | fn bar(&self){} - | ^^^^^^^^^^^^^ error[E0277]: the trait bound `bool: Foo` is not satisfied - --> $DIR/issue-39802-show-5-trait-impls.rs:26:5 + --> $DIR/issue-39802-show-5-trait-impls.rs:26:21 | +LL | fn bar(&self){} + | ------------- required by `Foo::bar` +... LL | Foo::::bar(&true); - | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `bool` + | ^^^^^ the trait `Foo` is not implemented for `bool` | = help: the following implementations were found: > @@ -45,11 +44,6 @@ LL | Foo::::bar(&true); > > and 2 others -note: required by `Foo::bar` - --> $DIR/issue-39802-show-5-trait-impls.rs:2:5 - | -LL | fn bar(&self){} - | ^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr index 87e48cd1e1cd9..5b384045a486a 100644 --- a/src/test/ui/did_you_mean/issue-40006.stderr +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -61,8 +61,9 @@ error[E0038]: the trait `X` cannot be made into an object | LL | impl dyn X { | ^^^^^ the trait `X` cannot be made into an object - | - = note: method `xxx` has no receiver +... +LL | fn xxx() { ### } + | --- associated function `xxx` has no `self` parameter error: aborting due to 9 previous errors diff --git a/src/test/ui/did_you_mean/issue-40396.rs b/src/test/ui/did_you_mean/issue-40396.rs index 63eec50c2d29f..1893355205433 100644 --- a/src/test/ui/did_you_mean/issue-40396.rs +++ b/src/test/ui/did_you_mean/issue-40396.rs @@ -1,27 +1,8 @@ -fn foo() { +fn main() { (0..13).collect>(); //~^ ERROR chained comparison - //~| ERROR expected value, found struct `Vec` - //~| ERROR expected value, found builtin type `i32` - //~| ERROR attempted to take value of method `collect` -} - -fn bar() { Vec::new(); //~^ ERROR chained comparison - //~| ERROR expected value, found struct `Vec` - //~| ERROR expected value, found builtin type `i32` - //~| ERROR cannot find function `new` in the crate root -} - -fn qux() { (0..13).collect(); //~^ ERROR chained comparison - //~| ERROR chained comparison - //~| ERROR expected value, found struct `Vec` - //~| ERROR expected value, found builtin type `i32` - //~| ERROR attempted to take value of method `collect` - //~| ERROR mismatched types } - -fn main() {} diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr index fe517ee34949d..7fc7c2628c472 100644 --- a/src/test/ui/did_you_mean/issue-40396.stderr +++ b/src/test/ui/did_you_mean/issue-40396.stderr @@ -2,102 +2,31 @@ error: chained comparison operators require parentheses --> $DIR/issue-40396.rs:2:20 | LL | (0..13).collect>(); - | ^^^^^^^^ + | ^^^^^ +help: use `::<...>` instead of `<...>` to specify type arguments | - = help: use `::<...>` instead of `<...>` if you meant to specify type arguments - = help: or use `(...)` if you meant to specify fn arguments +LL | (0..13).collect::>(); + | ^^ error: chained comparison operators require parentheses - --> $DIR/issue-40396.rs:10:8 + --> $DIR/issue-40396.rs:4:8 | LL | Vec::new(); - | ^^^^^^^ + | ^^^^^ +help: use `::<...>` instead of `<...>` to specify type arguments | - = help: use `::<...>` instead of `<...>` if you meant to specify type arguments - = help: or use `(...)` if you meant to specify fn arguments +LL | Vec::::new(); + | ^^ error: chained comparison operators require parentheses - --> $DIR/issue-40396.rs:18:20 + --> $DIR/issue-40396.rs:6:20 | LL | (0..13).collect(); - | ^^^^^^^^ + | ^^^^^ +help: use `::<...>` instead of `<...>` to specify type arguments | - = help: use `::<...>` instead of `<...>` if you meant to specify type arguments - = help: or use `(...)` if you meant to specify fn arguments +LL | (0..13).collect::(); + | ^^ -error: chained comparison operators require parentheses - --> $DIR/issue-40396.rs:18:24 - | -LL | (0..13).collect(); - | ^^^^^^ - | - = help: use `::<...>` instead of `<...>` if you meant to specify type arguments - = help: or use `(...)` if you meant to specify fn arguments - -error[E0423]: expected value, found struct `Vec` - --> $DIR/issue-40396.rs:2:21 - | -LL | (0..13).collect>(); - | ^^^ did you mean `Vec { /* fields */ }`? - -error[E0423]: expected value, found builtin type `i32` - --> $DIR/issue-40396.rs:2:25 - | -LL | (0..13).collect>(); - | ^^^ not a value - -error[E0423]: expected value, found struct `Vec` - --> $DIR/issue-40396.rs:10:5 - | -LL | Vec::new(); - | ^^^ did you mean `Vec { /* fields */ }`? - -error[E0423]: expected value, found builtin type `i32` - --> $DIR/issue-40396.rs:10:9 - | -LL | Vec::new(); - | ^^^ not a value - -error[E0425]: cannot find function `new` in the crate root - --> $DIR/issue-40396.rs:10:15 - | -LL | Vec::new(); - | ^^^ not found in the crate root - -error[E0423]: expected value, found struct `Vec` - --> $DIR/issue-40396.rs:18:21 - | -LL | (0..13).collect(); - | ^^^ did you mean `Vec { /* fields */ }`? - -error[E0423]: expected value, found builtin type `i32` - --> $DIR/issue-40396.rs:18:25 - | -LL | (0..13).collect(); - | ^^^ not a value - -error[E0615]: attempted to take value of method `collect` on type `std::ops::Range<{integer}>` - --> $DIR/issue-40396.rs:2:13 - | -LL | (0..13).collect>(); - | ^^^^^^^ help: use parentheses to call the method: `collect()` - -error[E0615]: attempted to take value of method `collect` on type `std::ops::Range<{integer}>` - --> $DIR/issue-40396.rs:18:13 - | -LL | (0..13).collect(); - | ^^^^^^^ help: use parentheses to call the method: `collect()` - -error[E0308]: mismatched types - --> $DIR/issue-40396.rs:18:29 - | -LL | (0..13).collect(); - | ^^ expected bool, found () - | - = note: expected type `bool` - found type `()` - -error: aborting due to 14 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0308, E0423, E0425, E0615. -For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr index d02f30152d687..d8826d4072a9d 100644 --- a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr +++ b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr @@ -5,10 +5,10 @@ LL | let x = Option(1); | ^^^^^^ help: try using one of the enum's variants | -LL | let x = std::prelude::v1::Option::None(1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | let x = std::prelude::v1::Option::Some(1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let x = std::option::Option::None(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let x = std::option::Option::Some(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0532]: expected tuple struct/variant, found enum `Option` --> $DIR/issue-43871-enum-instead-of-variant.rs:21:12 @@ -17,10 +17,10 @@ LL | if let Option(_) = x { | ^^^^^^ help: try using one of the enum's variants | -LL | if let std::prelude::v1::Option::None(_) = x { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | if let std::prelude::v1::Option::Some(_) = x { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | if let std::option::Option::None(_) = x { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | if let std::option::Option::Some(_) = x { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0532]: expected tuple struct/variant, found enum `Example` --> $DIR/issue-43871-enum-instead-of-variant.rs:27:12 @@ -47,14 +47,14 @@ LL | let z = ManyVariants(); | ^^^^^^^^^^^^ help: try using one of the enum's variants | -LL | let z = ManyVariants::Eight(); +LL | let z = ManyVariants::One(); + | ^^^^^^^^^^^^^^^^^ +LL | let z = ManyVariants::Two(); + | ^^^^^^^^^^^^^^^^^ +LL | let z = ManyVariants::Three(); | ^^^^^^^^^^^^^^^^^^^ -LL | let z = ManyVariants::Five(); - | ^^^^^^^^^^^^^^^^^^ LL | let z = ManyVariants::Four(); | ^^^^^^^^^^^^^^^^^^ -LL | let z = ManyVariants::Nine(); - | ^^^^^^^^^^^^^^^^^^ and 6 other candidates error: aborting due to 5 previous errors diff --git a/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr b/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr index f1c93d5463767..f5edbe2a3af53 100644 --- a/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr +++ b/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr @@ -28,7 +28,10 @@ error: expected `{`, found `;` LL | if not // lack of braces is [sic] | -- this `if` statement has a condition, but no block LL | println!("Then when?"); - | ^ expected `{` + | ^ + | | + | expected `{` + | help: try placing this code inside a block: `{ ; }` error: unexpected `2` after identifier --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:26:24 diff --git a/src/test/ui/did_you_mean/multiple-pattern-typo.rs b/src/test/ui/did_you_mean/multiple-pattern-typo.rs deleted file mode 100644 index 14ad33d53b08c..0000000000000 --- a/src/test/ui/did_you_mean/multiple-pattern-typo.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - let x = 3; - match x { - 1 | 2 || 3 => (), //~ ERROR unexpected token `||` after pattern - _ => (), - } -} diff --git a/src/test/ui/did_you_mean/multiple-pattern-typo.stderr b/src/test/ui/did_you_mean/multiple-pattern-typo.stderr deleted file mode 100644 index a29fa584b2924..0000000000000 --- a/src/test/ui/did_you_mean/multiple-pattern-typo.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: unexpected token `||` after pattern - --> $DIR/multiple-pattern-typo.rs:4:15 - | -LL | 1 | 2 || 3 => (), - | ^^ help: use a single `|` to specify multiple patterns: `|` - -error: aborting due to previous error - diff --git a/src/test/ui/did_you_mean/recursion_limit.stderr b/src/test/ui/did_you_mean/recursion_limit.stderr index a646d98324e09..b05b92bf1e94b 100644 --- a/src/test/ui/did_you_mean/recursion_limit.stderr +++ b/src/test/ui/did_you_mean/recursion_limit.stderr @@ -1,6 +1,9 @@ error[E0275]: overflow evaluating the requirement `J: std::marker::Send` --> $DIR/recursion_limit.rs:34:5 | +LL | fn is_send() { } + | ------- ---- required by this bound in `is_send` +... LL | is_send::(); | ^^^^^^^^^^^^ | @@ -14,11 +17,6 @@ LL | is_send::(); = note: required because it appears within the type `C` = note: required because it appears within the type `B` = note: required because it appears within the type `A` -note: required by `is_send` - --> $DIR/recursion_limit.rs:31:1 - | -LL | fn is_send() { } - | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/drop/dropck_legal_cycles.rs b/src/test/ui/drop/dropck_legal_cycles.rs index a4f4c2666ac9a..fb13fd764bfaf 100644 --- a/src/test/ui/drop/dropck_legal_cycles.rs +++ b/src/test/ui/drop/dropck_legal_cycles.rs @@ -143,7 +143,7 @@ pub fn main() { v[0].descend_into_self(&mut c); assert!(!c.saw_prev_marked); // <-- different from below, b/c acyclic above - if PRINT { println!(""); } + if PRINT { println!(); } // Cycle 1: { v[0] -> v[1], v[1] -> v[0] }; // does not exercise `v` itself @@ -158,7 +158,7 @@ pub fn main() { v[0].descend_into_self(&mut c); assert!(c.saw_prev_marked); - if PRINT { println!(""); } + if PRINT { println!(); } // Cycle 2: { v[0] -> v, v[1] -> v } let v: V = Named::new("v"); @@ -171,7 +171,7 @@ pub fn main() { v.descend_into_self(&mut c); assert!(c.saw_prev_marked); - if PRINT { println!(""); } + if PRINT { println!(); } // Cycle 3: { hk0 -> hv0, hv0 -> hk0, hk1 -> hv1, hv1 -> hk1 }; // does not exercise `h` itself @@ -193,7 +193,7 @@ pub fn main() { assert!(c.saw_prev_marked); } - if PRINT { println!(""); } + if PRINT { println!(); } // Cycle 4: { h -> (hmk0,hmv0,hmk1,hmv1), {hmk0,hmv0,hmk1,hmv1} -> h } @@ -216,7 +216,7 @@ pub fn main() { // break; } - if PRINT { println!(""); } + if PRINT { println!(); } // Cycle 5: { vd[0] -> vd[1], vd[1] -> vd[0] }; // does not exercise vd itself @@ -232,7 +232,7 @@ pub fn main() { vd[0].descend_into_self(&mut c); assert!(c.saw_prev_marked); - if PRINT { println!(""); } + if PRINT { println!(); } // Cycle 6: { vd -> (vd0, vd1), {vd0, vd1} -> vd } let mut vd: VecDeque = VecDeque::new(); @@ -247,7 +247,7 @@ pub fn main() { vd[0].descend_into_self(&mut c); assert!(c.saw_prev_marked); - if PRINT { println!(""); } + if PRINT { println!(); } // Cycle 7: { vm -> (vm0, vm1), {vm0, vm1} -> vm } let mut vm: HashMap = HashMap::new(); @@ -262,7 +262,7 @@ pub fn main() { vm[&0].descend_into_self(&mut c); assert!(c.saw_prev_marked); - if PRINT { println!(""); } + if PRINT { println!(); } // Cycle 8: { ll -> (ll0, ll1), {ll0, ll1} -> ll } let mut ll: LinkedList = LinkedList::new(); @@ -282,7 +282,7 @@ pub fn main() { // break; } - if PRINT { println!(""); } + if PRINT { println!(); } // Cycle 9: { bh -> (bh0, bh1), {bh0, bh1} -> bh } let mut bh: BinaryHeap = BinaryHeap::new(); @@ -302,7 +302,7 @@ pub fn main() { // break; } - if PRINT { println!(""); } + if PRINT { println!(); } // Cycle 10: { btm -> (btk0, btv1), {bt0, bt1} -> btm } let mut btm: BTreeMap = BTreeMap::new(); @@ -323,7 +323,7 @@ pub fn main() { // break; } - if PRINT { println!(""); } + if PRINT { println!(); } // Cycle 10: { bts -> (bts0, bts1), {bts0, bts1} -> btm } let mut bts: BTreeSet = BTreeSet::new(); @@ -343,7 +343,7 @@ pub fn main() { // break; } - if PRINT { println!(""); } + if PRINT { println!(); } // Cycle 11: { rc0 -> (rc1, rc2), rc1 -> (), rc2 -> rc0 } let (rc0, rc1, rc2): (RCRC, RCRC, RCRC); @@ -361,7 +361,7 @@ pub fn main() { rc0.descend_into_self(&mut c); assert!(c.saw_prev_marked); - if PRINT { println!(""); } + if PRINT { println!(); } // We want to take the previous Rc case and generalize it to Arc. // @@ -395,7 +395,7 @@ pub fn main() { arc0.descend_into_self(&mut c); assert!(c.saw_prev_marked); - if PRINT { println!(""); } + if PRINT { println!(); } // Cycle 13: { arc0 -> (arc1, arc2), arc1 -> (), arc2 -> arc0 }, rwlocks let (arc0, arc1, arc2): (ARCRW, ARCRW, ARCRW); @@ -413,7 +413,7 @@ pub fn main() { arc0.descend_into_self(&mut c); assert!(c.saw_prev_marked); - if PRINT { println!(""); } + if PRINT { println!(); } // Cycle 14: { arc0 -> (arc1, arc2), arc1 -> (), arc2 -> arc0 }, mutexs let (arc0, arc1, arc2): (ARCM, ARCM, ARCM); diff --git a/src/test/ui/drop/dynamic-drop-async.rs b/src/test/ui/drop/dynamic-drop-async.rs index f3f5c382275fe..91063edf0f6c4 100644 --- a/src/test/ui/drop/dynamic-drop-async.rs +++ b/src/test/ui/drop/dynamic-drop-async.rs @@ -7,10 +7,8 @@ // edition:2018 // ignore-wasm32-bare compiled with panic=abort by default -#![allow(unused_assignments)] -#![allow(unused_variables)] #![feature(slice_patterns)] -#![feature(async_await)] +#![allow(unused)] use std::{ cell::{Cell, RefCell}, diff --git a/src/test/ui/dropck/dropck_trait_cycle_checked.polonius.stderr b/src/test/ui/dropck/dropck_trait_cycle_checked.polonius.stderr deleted file mode 100644 index dbcb0fcebb73d..0000000000000 --- a/src/test/ui/dropck/dropck_trait_cycle_checked.polonius.stderr +++ /dev/null @@ -1,74 +0,0 @@ -error[E0597]: `o2` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:111:13 - | -LL | o1.set0(&o2); - | ^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `o2` dropped here while still borrowed - | borrow might be used here, when `o2` is dropped and runs the destructor for type `std::boxed::Box>` - -error[E0597]: `o3` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:112:13 - | -LL | o1.set1(&o3); - | ^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `o3` dropped here while still borrowed - | borrow might be used here, when `o3` is dropped and runs the destructor for type `std::boxed::Box>` - -error[E0597]: `o2` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:113:13 - | -LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o2` is borrowed for `'static` -... -LL | o2.set0(&o2); - | ^^^ borrowed value does not live long enough -... -LL | } - | - `o2` dropped here while still borrowed - -error[E0597]: `o3` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:114:13 - | -LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o3` is borrowed for `'static` -... -LL | o2.set1(&o3); - | ^^^ borrowed value does not live long enough -... -LL | } - | - `o3` dropped here while still borrowed - -error[E0597]: `o1` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:115:13 - | -LL | o3.set0(&o1); - | ^^^ borrowed value does not live long enough -LL | o3.set1(&o2); -LL | } - | - - | | - | `o1` dropped here while still borrowed - | borrow might be used here, when `o1` is dropped and runs the destructor for type `std::boxed::Box>` - -error[E0597]: `o2` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:116:13 - | -LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o2` is borrowed for `'static` -... -LL | o3.set1(&o2); - | ^^^ borrowed value does not live long enough -LL | } - | - `o2` dropped here while still borrowed - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/dropck/dropck_trait_cycle_checked.stderr b/src/test/ui/dropck/dropck_trait_cycle_checked.stderr index 1e779208e58a5..dc3fbed593b79 100644 --- a/src/test/ui/dropck/dropck_trait_cycle_checked.stderr +++ b/src/test/ui/dropck/dropck_trait_cycle_checked.stderr @@ -2,7 +2,7 @@ error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:111:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o2` is borrowed for `'static` + | -------- cast requires that `o2` is borrowed for `'static` LL | o1.set0(&o2); | ^^^ borrowed value does not live long enough ... @@ -13,7 +13,7 @@ error[E0597]: `o3` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:112:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o3` is borrowed for `'static` + | -------- cast requires that `o3` is borrowed for `'static` LL | o1.set0(&o2); LL | o1.set1(&o3); | ^^^ borrowed value does not live long enough @@ -37,7 +37,7 @@ error[E0597]: `o3` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:114:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o3` is borrowed for `'static` + | -------- cast requires that `o3` is borrowed for `'static` ... LL | o2.set1(&o3); | ^^^ borrowed value does not live long enough @@ -49,7 +49,7 @@ error[E0597]: `o1` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:115:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o1` is borrowed for `'static` + | -------- cast requires that `o1` is borrowed for `'static` ... LL | o3.set0(&o1); | ^^^ borrowed value does not live long enough @@ -61,7 +61,7 @@ error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:116:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o2` is borrowed for `'static` + | -------- cast requires that `o2` is borrowed for `'static` ... LL | o3.set1(&o2); | ^^^ borrowed value does not live long enough diff --git a/src/test/ui/duplicate/duplicate-type-parameter.stderr b/src/test/ui/duplicate/duplicate-type-parameter.stderr index 8606479ff6863..6754574f0b953 100644 --- a/src/test/ui/duplicate/duplicate-type-parameter.stderr +++ b/src/test/ui/duplicate/duplicate-type-parameter.stderr @@ -1,4 +1,4 @@ -error[E0403]: the name `T` is already used for a generic parameter in this list of generic parameters +error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters --> $DIR/duplicate-type-parameter.rs:1:12 | LL | type Foo = Option; @@ -6,7 +6,7 @@ LL | type Foo = Option; | | | first use of `T` -error[E0403]: the name `T` is already used for a generic parameter in this list of generic parameters +error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters --> $DIR/duplicate-type-parameter.rs:4:14 | LL | struct Bar(T); @@ -14,7 +14,7 @@ LL | struct Bar(T); | | | first use of `T` -error[E0403]: the name `T` is already used for a generic parameter in this list of generic parameters +error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters --> $DIR/duplicate-type-parameter.rs:7:14 | LL | struct Baz { @@ -22,7 +22,7 @@ LL | struct Baz { | | | first use of `T` -error[E0403]: the name `T` is already used for a generic parameter in this list of generic parameters +error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters --> $DIR/duplicate-type-parameter.rs:12:12 | LL | enum Boo { @@ -30,7 +30,7 @@ LL | enum Boo { | | | first use of `T` -error[E0403]: the name `T` is already used for a generic parameter in this list of generic parameters +error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters --> $DIR/duplicate-type-parameter.rs:18:11 | LL | fn quux(x: T) {} @@ -38,7 +38,7 @@ LL | fn quux(x: T) {} | | | first use of `T` -error[E0403]: the name `T` is already used for a generic parameter in this list of generic parameters +error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters --> $DIR/duplicate-type-parameter.rs:21:13 | LL | trait Qux {} @@ -46,7 +46,7 @@ LL | trait Qux {} | | | first use of `T` -error[E0403]: the name `T` is already used for a generic parameter in this list of generic parameters +error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters --> $DIR/duplicate-type-parameter.rs:24:8 | LL | impl Qux for Option {} diff --git a/src/test/ui/duplicate_entry_error.stderr b/src/test/ui/duplicate_entry_error.stderr index 1892ad38a594b..02be11d1fd0e5 100644 --- a/src/test/ui/duplicate_entry_error.stderr +++ b/src/test/ui/duplicate_entry_error.stderr @@ -7,7 +7,7 @@ LL | | loop {} LL | | } | |_^ | - = note: first defined in crate `std`. + = note: first defined in crate `std` (which `duplicate_entry_error` depends on). error: aborting due to previous error diff --git a/src/test/ui/editions/edition-keywords-2015-2018-expansion.rs b/src/test/ui/editions/edition-keywords-2015-2018-expansion.rs index 2684c8e00b2e1..9f34a3887b7f1 100644 --- a/src/test/ui/editions/edition-keywords-2015-2018-expansion.rs +++ b/src/test/ui/editions/edition-keywords-2015-2018-expansion.rs @@ -5,7 +5,7 @@ extern crate edition_kw_macro_2018; mod one_async { - produces_async! {} //~ ERROR expected identifier, found reserved keyword + produces_async! {} //~ ERROR expected identifier, found keyword } mod two_async { produces_async_raw! {} // OK diff --git a/src/test/ui/editions/edition-keywords-2015-2018-expansion.stderr b/src/test/ui/editions/edition-keywords-2015-2018-expansion.stderr index 321545740cf48..04a70cf98302f 100644 --- a/src/test/ui/editions/edition-keywords-2015-2018-expansion.stderr +++ b/src/test/ui/editions/edition-keywords-2015-2018-expansion.stderr @@ -1,8 +1,8 @@ -error: expected identifier, found reserved keyword `async` +error: expected identifier, found keyword `async` --> $DIR/edition-keywords-2015-2018-expansion.rs:8:5 | LL | produces_async! {} - | ^^^^^^^^^^^^^^^^^^ expected identifier, found reserved keyword + | ^^^^^^^^^^^^^^^^^^ expected identifier, found keyword | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) help: you can escape reserved keywords to use them as identifiers diff --git a/src/test/ui/editions/edition-keywords-2018-2015-parsing.rs b/src/test/ui/editions/edition-keywords-2018-2015-parsing.rs index fb8e0cdb4c30f..dbc0465b08e77 100644 --- a/src/test/ui/editions/edition-keywords-2018-2015-parsing.rs +++ b/src/test/ui/editions/edition-keywords-2018-2015-parsing.rs @@ -5,7 +5,7 @@ extern crate edition_kw_macro_2015; pub fn check_async() { - let mut async = 1; //~ ERROR expected identifier, found reserved keyword `async` + let mut async = 1; //~ ERROR expected identifier, found keyword `async` let mut r#async = 1; // OK r#async = consumes_async!(async); // OK @@ -15,6 +15,6 @@ pub fn check_async() { if passes_ident!(async) == 1 {} if passes_ident!(r#async) == 1 {} // OK - module::async(); //~ ERROR expected identifier, found reserved keyword `async` + module::async(); //~ ERROR expected identifier, found keyword `async` module::r#async(); // OK } diff --git a/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr b/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr index 3c4a153353447..be991cd0c8128 100644 --- a/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr +++ b/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr @@ -1,18 +1,18 @@ -error: expected identifier, found reserved keyword `async` +error: expected identifier, found keyword `async` --> $DIR/edition-keywords-2018-2015-parsing.rs:8:13 | LL | let mut async = 1; - | ^^^^^ expected identifier, found reserved keyword + | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | LL | let mut r#async = 1; | ^^^^^^^ -error: expected identifier, found reserved keyword `async` +error: expected identifier, found keyword `async` --> $DIR/edition-keywords-2018-2015-parsing.rs:18:13 | LL | module::async(); - | ^^^^^ expected identifier, found reserved keyword + | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | LL | module::r#async(); diff --git a/src/test/ui/editions/edition-keywords-2018-2018-expansion.rs b/src/test/ui/editions/edition-keywords-2018-2018-expansion.rs index 6f766550d4734..a8e69fed6959e 100644 --- a/src/test/ui/editions/edition-keywords-2018-2018-expansion.rs +++ b/src/test/ui/editions/edition-keywords-2018-2018-expansion.rs @@ -5,7 +5,7 @@ extern crate edition_kw_macro_2018; mod one_async { - produces_async! {} //~ ERROR expected identifier, found reserved keyword `async` + produces_async! {} //~ ERROR expected identifier, found keyword `async` } mod two_async { produces_async_raw! {} // OK diff --git a/src/test/ui/editions/edition-keywords-2018-2018-expansion.stderr b/src/test/ui/editions/edition-keywords-2018-2018-expansion.stderr index 8942e3ce430a8..fb12051eed409 100644 --- a/src/test/ui/editions/edition-keywords-2018-2018-expansion.stderr +++ b/src/test/ui/editions/edition-keywords-2018-2018-expansion.stderr @@ -1,8 +1,8 @@ -error: expected identifier, found reserved keyword `async` +error: expected identifier, found keyword `async` --> $DIR/edition-keywords-2018-2018-expansion.rs:8:5 | LL | produces_async! {} - | ^^^^^^^^^^^^^^^^^^ expected identifier, found reserved keyword + | ^^^^^^^^^^^^^^^^^^ expected identifier, found keyword | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) help: you can escape reserved keywords to use them as identifiers diff --git a/src/test/ui/editions/edition-keywords-2018-2018-parsing.rs b/src/test/ui/editions/edition-keywords-2018-2018-parsing.rs index 88cebf45ad8ba..5aca0839f0f15 100644 --- a/src/test/ui/editions/edition-keywords-2018-2018-parsing.rs +++ b/src/test/ui/editions/edition-keywords-2018-2018-parsing.rs @@ -5,7 +5,7 @@ extern crate edition_kw_macro_2018; pub fn check_async() { - let mut async = 1; //~ ERROR expected identifier, found reserved keyword `async` + let mut async = 1; //~ ERROR expected identifier, found keyword `async` let mut r#async = 1; // OK r#async = consumes_async!(async); // OK @@ -15,6 +15,6 @@ pub fn check_async() { if passes_ident!(async) == 1 {} if passes_ident!(r#async) == 1 {} // OK - module::async(); //~ ERROR expected identifier, found reserved keyword `async` + module::async(); //~ ERROR expected identifier, found keyword `async` module::r#async(); // OK } diff --git a/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr b/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr index 46aa9ca34e17c..93a7627f88713 100644 --- a/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr +++ b/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr @@ -1,18 +1,18 @@ -error: expected identifier, found reserved keyword `async` +error: expected identifier, found keyword `async` --> $DIR/edition-keywords-2018-2018-parsing.rs:8:13 | LL | let mut async = 1; - | ^^^^^ expected identifier, found reserved keyword + | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | LL | let mut r#async = 1; | ^^^^^^^ -error: expected identifier, found reserved keyword `async` +error: expected identifier, found keyword `async` --> $DIR/edition-keywords-2018-2018-parsing.rs:18:13 | LL | module::async(); - | ^^^^^ expected identifier, found reserved keyword + | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | LL | module::r#async(); diff --git a/src/test/ui/elided-test.stderr b/src/test/ui/elided-test.stderr index d22eee4e8bde7..175bd033067bc 100644 --- a/src/test/ui/elided-test.stderr +++ b/src/test/ui/elided-test.stderr @@ -1,6 +1,10 @@ error[E0601]: `main` function not found in crate `elided_test` + --> $DIR/elided-test.rs:5:1 | - = note: consider adding a `main` function to `$DIR/elided-test.rs` +LL | / #[test] +LL | | fn main() { +LL | | } + | |_^ consider adding a `main` function to `$DIR/elided-test.rs` error: aborting due to previous error diff --git a/src/test/ui/empty/empty-macro-use.stderr b/src/test/ui/empty/empty-macro-use.stderr index 16300411c8cef..8e3e06896ee78 100644 --- a/src/test/ui/empty/empty-macro-use.stderr +++ b/src/test/ui/empty/empty-macro-use.stderr @@ -1,4 +1,4 @@ -error: cannot find macro `macro_two!` in this scope +error: cannot find macro `macro_two` in this scope --> $DIR/empty-macro-use.rs:7:5 | LL | macro_two!(); diff --git a/src/test/ui/empty/empty-never-array.rs b/src/test/ui/empty/empty-never-array.rs index ffd2545b291e2..f0ecea42f39c8 100644 --- a/src/test/ui/empty/empty-never-array.rs +++ b/src/test/ui/empty/empty-never-array.rs @@ -10,7 +10,7 @@ fn transmute(t: T) -> U { let Helper::U(u) = Helper::T(t, []); //~^ ERROR refutable pattern in local binding: `T(_, _)` not covered u - //~^ ERROR use of possibly uninitialized variable: `u` + //~^ ERROR use of possibly-uninitialized variable: `u` } fn main() { diff --git a/src/test/ui/empty/empty-never-array.stderr b/src/test/ui/empty/empty-never-array.stderr index 01ee1c3a4d7fa..7d59d553d88fd 100644 --- a/src/test/ui/empty/empty-never-array.stderr +++ b/src/test/ui/empty/empty-never-array.stderr @@ -3,6 +3,7 @@ error[E0005]: refutable pattern in local binding: `T(_, _)` not covered | LL | / enum Helper { LL | | T(T, [!; 0]), + | | - not covered LL | | #[allow(dead_code)] LL | | U(U), LL | | } @@ -11,11 +12,11 @@ LL | | } LL | let Helper::U(u) = Helper::T(t, []); | ^^^^^^^^^^^^ pattern `T(_, _)` not covered -error[E0381]: use of possibly uninitialized variable: `u` +error[E0381]: use of possibly-uninitialized variable: `u` --> $DIR/empty-never-array.rs:12:5 | LL | u - | ^ use of possibly uninitialized `u` + | ^ use of possibly-uninitialized `u` error: aborting due to 2 previous errors diff --git a/src/test/ui/empty/empty-struct-braces-expr.stderr b/src/test/ui/empty/empty-struct-braces-expr.stderr index b9681db87b67e..9712157552716 100644 --- a/src/test/ui/empty/empty-struct-braces-expr.stderr +++ b/src/test/ui/empty/empty-struct-braces-expr.stderr @@ -1,6 +1,9 @@ error[E0423]: expected value, found struct `Empty1` --> $DIR/empty-struct-braces-expr.rs:15:14 | +LL | struct Empty1 {} + | ---------------- `Empty1` defined here +... LL | let e1 = Empty1; | ^^^^^^ | | @@ -10,6 +13,9 @@ LL | let e1 = Empty1; error[E0423]: expected function, found struct `Empty1` --> $DIR/empty-struct-braces-expr.rs:16:14 | +LL | struct Empty1 {} + | ---------------- `Empty1` defined here +... LL | let e1 = Empty1(); | ^^^^^^ | | @@ -19,12 +25,18 @@ LL | let e1 = Empty1(); error[E0423]: expected value, found struct variant `E::Empty3` --> $DIR/empty-struct-braces-expr.rs:17:14 | +LL | Empty3 {} + | --------- `E::Empty3` defined here +... LL | let e3 = E::Empty3; | ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`? error[E0423]: expected function, found struct variant `E::Empty3` --> $DIR/empty-struct-braces-expr.rs:18:14 | +LL | Empty3 {} + | --------- `E::Empty3` defined here +... LL | let e3 = E::Empty3(); | ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`? diff --git a/src/test/ui/empty/empty-struct-braces-pat-1.stderr b/src/test/ui/empty/empty-struct-braces-pat-1.stderr index 6c361c703440c..271e811a2fd65 100644 --- a/src/test/ui/empty/empty-struct-braces-pat-1.stderr +++ b/src/test/ui/empty/empty-struct-braces-pat-1.stderr @@ -1,6 +1,9 @@ error[E0532]: expected unit struct/variant or constant, found struct variant `E::Empty3` --> $DIR/empty-struct-braces-pat-1.rs:24:9 | +LL | Empty3 {} + | --------- `E::Empty3` defined here +... LL | E::Empty3 => () | ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`? diff --git a/src/test/ui/empty/empty-struct-braces-pat-2.stderr b/src/test/ui/empty/empty-struct-braces-pat-2.stderr index 12047b5880c3e..3352473788894 100644 --- a/src/test/ui/empty/empty-struct-braces-pat-2.stderr +++ b/src/test/ui/empty/empty-struct-braces-pat-2.stderr @@ -1,6 +1,9 @@ error[E0532]: expected tuple struct/variant, found struct `Empty1` --> $DIR/empty-struct-braces-pat-2.rs:15:9 | +LL | struct Empty1 {} + | ---------------- `Empty1` defined here +... LL | Empty1() => () | ^^^^^^ | | @@ -19,6 +22,9 @@ LL | XEmpty1() => () error[E0532]: expected tuple struct/variant, found struct `Empty1` --> $DIR/empty-struct-braces-pat-2.rs:21:9 | +LL | struct Empty1 {} + | ---------------- `Empty1` defined here +... LL | Empty1(..) => () | ^^^^^^ | | diff --git a/src/test/ui/empty/empty-struct-braces-pat-3.stderr b/src/test/ui/empty/empty-struct-braces-pat-3.stderr index af8731b5f0596..aefdd772b1bfd 100644 --- a/src/test/ui/empty/empty-struct-braces-pat-3.stderr +++ b/src/test/ui/empty/empty-struct-braces-pat-3.stderr @@ -1,6 +1,9 @@ error[E0532]: expected tuple struct/variant, found struct variant `E::Empty3` --> $DIR/empty-struct-braces-pat-3.rs:17:9 | +LL | Empty3 {} + | --------- `E::Empty3` defined here +... LL | E::Empty3() => () | ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`? @@ -16,6 +19,9 @@ LL | XE::XEmpty3() => () error[E0532]: expected tuple struct/variant, found struct variant `E::Empty3` --> $DIR/empty-struct-braces-pat-3.rs:25:9 | +LL | Empty3 {} + | --------- `E::Empty3` defined here +... LL | E::Empty3(..) => () | ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`? diff --git a/src/test/ui/empty/empty-struct-tuple-pat.stderr b/src/test/ui/empty/empty-struct-tuple-pat.stderr index 777b9d4a4acd0..4b828c0d942e3 100644 --- a/src/test/ui/empty/empty-struct-tuple-pat.stderr +++ b/src/test/ui/empty/empty-struct-tuple-pat.stderr @@ -19,16 +19,20 @@ LL | XEmpty6 => () error[E0532]: expected unit struct/variant or constant, found tuple variant `E::Empty4` --> $DIR/empty-struct-tuple-pat.rs:29:9 | +LL | Empty4() + | -------- `E::Empty4` defined here +... LL | E::Empty4 => () - | ^^^^^^^^^ not a unit struct/variant or constant + | ^^^^^^^^^ did you mean `E::Empty4( /* fields */ )`? error[E0532]: expected unit struct/variant or constant, found tuple variant `XE::XEmpty5` --> $DIR/empty-struct-tuple-pat.rs:33:9 | LL | XE::XEmpty5 => (), | ^^^^------- - | | - | help: a unit variant with a similar name exists: `XEmpty4` + | | | + | | help: a unit variant with a similar name exists: `XEmpty4` + | did you mean `XE::XEmpty5( /* fields */ )`? error: aborting due to 4 previous errors diff --git a/src/test/ui/enums-pats-not-idents.stderr b/src/test/ui/enums-pats-not-idents.stderr index 3891d1eac487b..6b1e6046260a9 100644 --- a/src/test/ui/enums-pats-not-idents.stderr +++ b/src/test/ui/enums-pats-not-idents.stderr @@ -6,3 +6,4 @@ LL | let a(1) = 13; error: aborting due to previous error +For more information about this error, try `rustc --explain E0531`. diff --git a/src/test/ui/error-codes/E0008.rs b/src/test/ui/error-codes/E0008.rs deleted file mode 100644 index c87ef4cb8541f..0000000000000 --- a/src/test/ui/error-codes/E0008.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - match Some("hi".to_string()) { - Some(s) if s.len() == 0 => {}, - //~^ ERROR E0008 - _ => {}, - } -} diff --git a/src/test/ui/error-codes/E0008.stderr b/src/test/ui/error-codes/E0008.stderr deleted file mode 100644 index 6b45439c4b587..0000000000000 --- a/src/test/ui/error-codes/E0008.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0008]: cannot bind by-move into a pattern guard - --> $DIR/E0008.rs:3:14 - | -LL | Some(s) if s.len() == 0 => {}, - | ^ moves value into pattern guard - | - = help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0008`. diff --git a/src/test/ui/error-codes/E0023.rs b/src/test/ui/error-codes/E0023.rs index 2a97e9048a490..7ac22bb71092e 100644 --- a/src/test/ui/error-codes/E0023.rs +++ b/src/test/ui/error-codes/E0023.rs @@ -1,14 +1,17 @@ enum Fruit { Apple(String, String), Pear(u32), + Orange((String, String)), + Banana(()), } - fn main() { let x = Fruit::Apple(String::new(), String::new()); match x { Fruit::Apple(a) => {}, //~ ERROR E0023 Fruit::Apple(a, b, c) => {}, //~ ERROR E0023 Fruit::Pear(1, 2) => {}, //~ ERROR E0023 + Fruit::Orange(a, b) => {}, //~ ERROR E0023 + Fruit::Banana() => {}, //~ ERROR E0023 } } diff --git a/src/test/ui/error-codes/E0023.stderr b/src/test/ui/error-codes/E0023.stderr index 1bc90a995fe30..dbce6003a2bad 100644 --- a/src/test/ui/error-codes/E0023.stderr +++ b/src/test/ui/error-codes/E0023.stderr @@ -1,21 +1,56 @@ error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields - --> $DIR/E0023.rs:10:9 + --> $DIR/E0023.rs:11:9 | +LL | Apple(String, String), + | --------------------- tuple variant defined here +... LL | Fruit::Apple(a) => {}, | ^^^^^^^^^^^^^^^ expected 2 fields, found 1 error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields - --> $DIR/E0023.rs:11:9 + --> $DIR/E0023.rs:12:9 | +LL | Apple(String, String), + | --------------------- tuple variant defined here +... LL | Fruit::Apple(a, b, c) => {}, | ^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 3 error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 1 field - --> $DIR/E0023.rs:12:9 + --> $DIR/E0023.rs:13:9 | +LL | Pear(u32), + | --------- tuple variant defined here +... LL | Fruit::Pear(1, 2) => {}, | ^^^^^^^^^^^^^^^^^ expected 1 field, found 2 -error: aborting due to 3 previous errors +error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 1 field + --> $DIR/E0023.rs:14:9 + | +LL | Orange((String, String)), + | ------------------------ tuple variant defined here +... +LL | Fruit::Orange(a, b) => {}, + | ^^^^^^^^^^^^^^^^^^^ expected 1 field, found 2 +help: missing parenthesis + | +LL | Fruit::Orange((a, b)) => {}, + | ^ ^ + +error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 1 field + --> $DIR/E0023.rs:15:9 + | +LL | Banana(()), + | ---------- tuple variant defined here +... +LL | Fruit::Banana() => {}, + | ^^^^^^^^^^^^^^^ expected 1 field, found 0 +help: missing parenthesis + | +LL | Fruit::Banana(()) => {}, + | ^ ^ + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0023`. diff --git a/src/test/ui/error-codes/E0033-teach.rs b/src/test/ui/error-codes/E0033-teach.rs index 6a27b07fa8b77..1943965139423 100644 --- a/src/test/ui/error-codes/E0033-teach.rs +++ b/src/test/ui/error-codes/E0033-teach.rs @@ -1,14 +1,13 @@ // compile-flags: -Z teach trait SomeTrait { - fn foo(); + fn foo(); //~ associated function `foo` has no `self` parameter } fn main() { let trait_obj: &dyn SomeTrait = SomeTrait; //~^ ERROR expected value, found trait `SomeTrait` //~| ERROR E0038 - //~| method `foo` has no receiver let &invalid = trait_obj; //~^ ERROR E0033 diff --git a/src/test/ui/error-codes/E0033-teach.stderr b/src/test/ui/error-codes/E0033-teach.stderr index fb630de7fc147..80f3d4441bd9f 100644 --- a/src/test/ui/error-codes/E0033-teach.stderr +++ b/src/test/ui/error-codes/E0033-teach.stderr @@ -7,13 +7,14 @@ LL | let trait_obj: &dyn SomeTrait = SomeTrait; error[E0038]: the trait `SomeTrait` cannot be made into an object --> $DIR/E0033-teach.rs:8:20 | +LL | fn foo(); + | --- associated function `foo` has no `self` parameter +... LL | let trait_obj: &dyn SomeTrait = SomeTrait; | ^^^^^^^^^^^^^^ the trait `SomeTrait` cannot be made into an object - | - = note: method `foo` has no receiver error[E0033]: type `&dyn SomeTrait` cannot be dereferenced - --> $DIR/E0033-teach.rs:13:9 + --> $DIR/E0033-teach.rs:12:9 | LL | let &invalid = trait_obj; | ^^^^^^^^ type `&dyn SomeTrait` cannot be dereferenced diff --git a/src/test/ui/error-codes/E0033.rs b/src/test/ui/error-codes/E0033.rs index 582600e110ba0..e5f0530f45ff8 100644 --- a/src/test/ui/error-codes/E0033.rs +++ b/src/test/ui/error-codes/E0033.rs @@ -1,12 +1,11 @@ trait SomeTrait { - fn foo(); + fn foo(); //~ associated function `foo` has no `self` parameter } fn main() { let trait_obj: &dyn SomeTrait = SomeTrait; //~^ ERROR expected value, found trait `SomeTrait` //~| ERROR E0038 - //~| method `foo` has no receiver let &invalid = trait_obj; //~^ ERROR E0033 diff --git a/src/test/ui/error-codes/E0033.stderr b/src/test/ui/error-codes/E0033.stderr index fe9f45d86a6a0..c2843796cc851 100644 --- a/src/test/ui/error-codes/E0033.stderr +++ b/src/test/ui/error-codes/E0033.stderr @@ -7,13 +7,14 @@ LL | let trait_obj: &dyn SomeTrait = SomeTrait; error[E0038]: the trait `SomeTrait` cannot be made into an object --> $DIR/E0033.rs:6:20 | +LL | fn foo(); + | --- associated function `foo` has no `self` parameter +... LL | let trait_obj: &dyn SomeTrait = SomeTrait; | ^^^^^^^^^^^^^^ the trait `SomeTrait` cannot be made into an object - | - = note: method `foo` has no receiver error[E0033]: type `&dyn SomeTrait` cannot be dereferenced - --> $DIR/E0033.rs:11:9 + --> $DIR/E0033.rs:10:9 | LL | let &invalid = trait_obj; | ^^^^^^^^ type `&dyn SomeTrait` cannot be dereferenced diff --git a/src/test/ui/error-codes/E0038.stderr b/src/test/ui/error-codes/E0038.stderr index e3d7593e42a71..5c4d6d53c4626 100644 --- a/src/test/ui/error-codes/E0038.stderr +++ b/src/test/ui/error-codes/E0038.stderr @@ -1,10 +1,11 @@ error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/E0038.rs:5:1 | +LL | fn foo(&self) -> Self; + | --- method `foo` references the `Self` type in its parameters or return type +... LL | fn call_foo(x: Box) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` cannot be made into an object - | - = note: method `foo` references the `Self` type in its arguments or return type error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0044.rs b/src/test/ui/error-codes/E0044.rs index a5265e7dc1708..9eee9c31d3c38 100644 --- a/src/test/ui/error-codes/E0044.rs +++ b/src/test/ui/error-codes/E0044.rs @@ -1,7 +1,7 @@ extern { fn sqrt(f: T) -> T; //~^ ERROR foreign items may not have type parameters [E0044] - //~| HELP use specialization instead of type parameters by replacing them with concrete types + //~| HELP replace the type parameters with concrete types //~| NOTE can't have type parameters } diff --git a/src/test/ui/error-codes/E0044.stderr b/src/test/ui/error-codes/E0044.stderr index 57c21116b2856..e889c167b98d2 100644 --- a/src/test/ui/error-codes/E0044.stderr +++ b/src/test/ui/error-codes/E0044.stderr @@ -4,7 +4,7 @@ error[E0044]: foreign items may not have type parameters LL | fn sqrt(f: T) -> T; | ^^^^^^^^^^^^^^^^^^^^^^ can't have type parameters | - = help: use specialization instead of type parameters by replacing them with concrete types like `u32` + = help: replace the type parameters with concrete types like `u32` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0138.stderr b/src/test/ui/error-codes/E0138.stderr index 745dccfb17571..445053a4a89e3 100644 --- a/src/test/ui/error-codes/E0138.stderr +++ b/src/test/ui/error-codes/E0138.stderr @@ -1,4 +1,4 @@ -error[E0138]: multiple 'start' functions +error[E0138]: multiple `start` functions --> $DIR/E0138.rs:7:1 | LL | fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } diff --git a/src/test/ui/error-codes/E0152.stderr b/src/test/ui/error-codes/E0152.stderr index 26e6e2e1bce7e..d4b59a1148e60 100644 --- a/src/test/ui/error-codes/E0152.stderr +++ b/src/test/ui/error-codes/E0152.stderr @@ -4,7 +4,7 @@ error[E0152]: duplicate lang item found: `arc`. LL | struct Foo; | ^^^^^^^^^^^ | - = note: first defined in crate `alloc`. + = note: first defined in crate `alloc` (which `std` depends on). error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0194.rs b/src/test/ui/error-codes/E0194.rs index 71eff0e7465a5..8a43f38fcfd5f 100644 --- a/src/test/ui/error-codes/E0194.rs +++ b/src/test/ui/error-codes/E0194.rs @@ -1,7 +1,7 @@ trait Foo { fn do_something(&self) -> T; fn do_something_else(&self, bar: T); - //~^ ERROR E0194 + //~^ ERROR E0403 } fn main() { diff --git a/src/test/ui/error-codes/E0194.stderr b/src/test/ui/error-codes/E0194.stderr index ab4918a4e27d5..f2c908eea0bb0 100644 --- a/src/test/ui/error-codes/E0194.stderr +++ b/src/test/ui/error-codes/E0194.stderr @@ -1,12 +1,12 @@ -error[E0194]: type parameter `T` shadows another type parameter of the same name +error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters --> $DIR/E0194.rs:3:26 | LL | trait Foo { - | - first `T` declared here + | - first use of `T` LL | fn do_something(&self) -> T; LL | fn do_something_else(&self, bar: T); - | ^ shadows another type parameter + | ^ already used error: aborting due to previous error -For more information about this error, try `rustc --explain E0194`. +For more information about this error, try `rustc --explain E0403`. diff --git a/src/test/ui/error-codes/E0214.stderr b/src/test/ui/error-codes/E0214.stderr index a10f2c00578c6..bcbd3a91cb951 100644 --- a/src/test/ui/error-codes/E0214.stderr +++ b/src/test/ui/error-codes/E0214.stderr @@ -1,11 +1,11 @@ error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/E0214.rs:2:15 + --> $DIR/E0214.rs:2:12 | LL | let v: Vec(&str) = vec!["foo"]; - | ^^^^^^ - | | - | only `Fn` traits may use parentheses - | help: use angle brackets instead: `<&str>` + | ^^^^^^^^^ + | | + | only `Fn` traits may use parentheses + | help: use angle brackets instead: `Vec<&str>` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0267.stderr b/src/test/ui/error-codes/E0267.stderr index b14cfd1a52d47..1f8657373efec 100644 --- a/src/test/ui/error-codes/E0267.stderr +++ b/src/test/ui/error-codes/E0267.stderr @@ -2,7 +2,9 @@ error[E0267]: `break` inside of a closure --> $DIR/E0267.rs:2:18 | LL | let w = || { break; }; - | ^^^^^ cannot break inside of a closure + | -- ^^^^^ cannot `break` inside of a closure + | | + | enclosing closure error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0268.stderr b/src/test/ui/error-codes/E0268.stderr index 3c77e7f3df2be..c926f9e487494 100644 --- a/src/test/ui/error-codes/E0268.stderr +++ b/src/test/ui/error-codes/E0268.stderr @@ -1,8 +1,8 @@ -error[E0268]: `break` outside of loop +error[E0268]: `break` outside of a loop --> $DIR/E0268.rs:2:5 | LL | break; - | ^^^^^ cannot break outside of a loop + | ^^^^^ cannot `break` outside of a loop error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0271.stderr b/src/test/ui/error-codes/E0271.stderr index 16c3ab9d7425b..c56853f45a0b0 100644 --- a/src/test/ui/error-codes/E0271.stderr +++ b/src/test/ui/error-codes/E0271.stderr @@ -1,16 +1,14 @@ error[E0271]: type mismatch resolving `::AssociatedType == u32` --> $DIR/E0271.rs:10:5 | +LL | fn foo(t: T) where T: Trait { + | --- ------------------ required by this bound in `foo` +... LL | foo(3_i8); | ^^^ expected reference, found u32 | = note: expected type `&'static str` found type `u32` -note: required by `foo` - --> $DIR/E0271.rs:3:1 - | -LL | fn foo(t: T) where T: Trait { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0275.stderr b/src/test/ui/error-codes/E0275.stderr index 40991cb2297c9..f607a9fbbf269 100644 --- a/src/test/ui/error-codes/E0275.stderr +++ b/src/test/ui/error-codes/E0275.stderr @@ -1,6 +1,9 @@ error[E0275]: overflow evaluating the requirement `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` --> $DIR/E0275.rs:5:1 | +LL | trait Foo {} + | --------- required by `Foo` +... LL | impl Foo for T where Bar: Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -132,11 +135,6 @@ LL | impl Foo for T where Bar: Foo {} = note: required because of the requirements on the impl of `Foo` for `Bar>>` = note: required because of the requirements on the impl of `Foo` for `Bar>` = note: required because of the requirements on the impl of `Foo` for `Bar` -note: required by `Foo` - --> $DIR/E0275.rs:1:1 - | -LL | trait Foo {} - | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0277-2.stderr b/src/test/ui/error-codes/E0277-2.stderr index a4db1c8b09523..407e51e4f5f9c 100644 --- a/src/test/ui/error-codes/E0277-2.stderr +++ b/src/test/ui/error-codes/E0277-2.stderr @@ -1,6 +1,9 @@ error[E0277]: `*const u8` cannot be sent between threads safely --> $DIR/E0277-2.rs:16:5 | +LL | fn is_send() { } + | ------- ---- required by this bound in `is_send` +... LL | is_send::(); | ^^^^^^^^^^^^^^ `*const u8` cannot be sent between threads safely | @@ -8,11 +11,6 @@ LL | is_send::(); = note: required because it appears within the type `Baz` = note: required because it appears within the type `Bar` = note: required because it appears within the type `Foo` -note: required by `is_send` - --> $DIR/E0277-2.rs:13:1 - | -LL | fn is_send() { } - | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr index e5e416da883de..a069d048c8862 100644 --- a/src/test/ui/error-codes/E0277.stderr +++ b/src/test/ui/error-codes/E0277.stderr @@ -11,16 +11,13 @@ LL | fn f(p: Path) { } = help: unsized locals are gated as an unstable feature error[E0277]: the trait bound `i32: Foo` is not satisfied - --> $DIR/E0277.rs:17:5 - | -LL | some_func(5i32); - | ^^^^^^^^^ the trait `Foo` is not implemented for `i32` - | -note: required by `some_func` - --> $DIR/E0277.rs:9:1 + --> $DIR/E0277.rs:17:15 | LL | fn some_func(foo: T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | --------- --- required by this bound in `some_func` +... +LL | some_func(5i32); + | ^^^^ the trait `Foo` is not implemented for `i32` error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0282.stderr b/src/test/ui/error-codes/E0282.stderr index 3a5040eb6daa6..0f610a5e42f65 100644 --- a/src/test/ui/error-codes/E0282.stderr +++ b/src/test/ui/error-codes/E0282.stderr @@ -2,10 +2,7 @@ error[E0282]: type annotations needed --> $DIR/E0282.rs:2:9 | LL | let x = "hello".chars().rev().collect(); - | ^ - | | - | cannot infer type - | consider giving `x` a type + | ^ consider giving `x` a type error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0283.stderr b/src/test/ui/error-codes/E0283.stderr index e1f53e592fc85..aba649d83ec01 100644 --- a/src/test/ui/error-codes/E0283.stderr +++ b/src/test/ui/error-codes/E0283.stderr @@ -1,14 +1,11 @@ -error[E0283]: type annotations required: cannot resolve `_: Generator` +error[E0283]: type annotations needed: cannot resolve `_: Generator` --> $DIR/E0283.rs:18:21 | +LL | fn create() -> u32; + | ------------------- required by `Generator::create` +... LL | let cont: u32 = Generator::create(); | ^^^^^^^^^^^^^^^^^ - | -note: required by `Generator::create` - --> $DIR/E0283.rs:2:5 - | -LL | fn create() -> u32; - | ^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0301.rs b/src/test/ui/error-codes/E0301.rs deleted file mode 100644 index 3b451801c99df..0000000000000 --- a/src/test/ui/error-codes/E0301.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - match Some(()) { - None => { }, - option if option.take().is_none() => {}, //~ ERROR E0301 - Some(_) => { } //~^ ERROR E0596 - } -} diff --git a/src/test/ui/error-codes/E0301.stderr b/src/test/ui/error-codes/E0301.stderr deleted file mode 100644 index 4f12fd3850e33..0000000000000 --- a/src/test/ui/error-codes/E0301.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0301]: cannot mutably borrow in a pattern guard - --> $DIR/E0301.rs:4:19 - | -LL | option if option.take().is_none() => {}, - | ^^^^^^ borrowed mutably in pattern guard - | - = help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable - -error[E0596]: cannot borrow `option` as mutable, as it is immutable for the pattern guard - --> $DIR/E0301.rs:4:19 - | -LL | option if option.take().is_none() => {}, - | ^^^^^^ cannot borrow as mutable - | - = note: variables bound in patterns are immutable until the end of the pattern guard - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0301, E0596. -For more information about an error, try `rustc --explain E0301`. diff --git a/src/test/ui/error-codes/E0302.rs b/src/test/ui/error-codes/E0302.rs deleted file mode 100644 index 69f5953deb223..0000000000000 --- a/src/test/ui/error-codes/E0302.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - match Some(()) { - None => { }, - option if { option = None; false } => { }, //~ ERROR E0302 - //~^ ERROR cannot assign to `option`, as it is immutable for the pattern guard - Some(_) => { } - } -} diff --git a/src/test/ui/error-codes/E0302.stderr b/src/test/ui/error-codes/E0302.stderr deleted file mode 100644 index a077fcaea4101..0000000000000 --- a/src/test/ui/error-codes/E0302.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0302]: cannot assign in a pattern guard - --> $DIR/E0302.rs:4:21 - | -LL | option if { option = None; false } => { }, - | ^^^^^^^^^^^^^ assignment in pattern guard - -error[E0594]: cannot assign to `option`, as it is immutable for the pattern guard - --> $DIR/E0302.rs:4:21 - | -LL | option if { option = None; false } => { }, - | ^^^^^^^^^^^^^ cannot assign - | - = note: variables bound in patterns are immutable until the end of the pattern guard - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0302`. diff --git a/src/test/ui/error-codes/E0392.stderr b/src/test/ui/error-codes/E0392.stderr index d0b808df184c4..7b0bfe372757a 100644 --- a/src/test/ui/error-codes/E0392.stderr +++ b/src/test/ui/error-codes/E0392.stderr @@ -4,7 +4,7 @@ error[E0392]: parameter `T` is never used LL | enum Foo { Bar } | ^ unused parameter | - = help: consider removing `T` or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0401.rs b/src/test/ui/error-codes/E0401.rs index a120198b7284d..c30e5f4718871 100644 --- a/src/test/ui/error-codes/E0401.rs +++ b/src/test/ui/error-codes/E0401.rs @@ -8,7 +8,7 @@ fn foo(x: T) { W: Fn()> (y: T) { //~ ERROR E0401 } - bfnr(x); + bfnr(x); //~ ERROR type annotations needed } diff --git a/src/test/ui/error-codes/E0401.stderr b/src/test/ui/error-codes/E0401.stderr index 1d9dfe46722ec..485b76a09a3c4 100644 --- a/src/test/ui/error-codes/E0401.stderr +++ b/src/test/ui/error-codes/E0401.stderr @@ -32,6 +32,13 @@ LL | fn helper(sel: &Self) -> u8 { | use of generic parameter from outer function | use a type here instead -error: aborting due to 3 previous errors +error[E0282]: type annotations needed + --> $DIR/E0401.rs:11:5 + | +LL | bfnr(x); + | ^^^^ cannot infer type for `U` + +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0401`. +Some errors have detailed explanations: E0282, E0401. +For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/error-codes/E0403.stderr b/src/test/ui/error-codes/E0403.stderr index 2bd7de6c24614..d76a58a7c80de 100644 --- a/src/test/ui/error-codes/E0403.stderr +++ b/src/test/ui/error-codes/E0403.stderr @@ -1,4 +1,4 @@ -error[E0403]: the name `T` is already used for a generic parameter in this list of generic parameters +error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters --> $DIR/E0403.rs:1:11 | LL | fn foo(s: T, u: T) {} diff --git a/src/test/ui/error-codes/E0423.stderr b/src/test/ui/error-codes/E0423.stderr index ec240003f9182..ce631ca4bf786 100644 --- a/src/test/ui/error-codes/E0423.stderr +++ b/src/test/ui/error-codes/E0423.stderr @@ -27,6 +27,9 @@ LL | for _ in (std::ops::Range { start: 0, end: 10 }) {} error[E0423]: expected function, found struct `Foo` --> $DIR/E0423.rs:4:13 | +LL | struct Foo { a: bool }; + | ---------------------- `Foo` defined here +LL | LL | let f = Foo(); | ^^^ | | diff --git a/src/test/ui/error-codes/E0601.rs b/src/test/ui/error-codes/E0601.rs index 47feb7f836722..4380ddeac0aac 100644 --- a/src/test/ui/error-codes/E0601.rs +++ b/src/test/ui/error-codes/E0601.rs @@ -1 +1 @@ -// Test for main function not found. +//~ ERROR `main` function not found diff --git a/src/test/ui/error-codes/E0601.stderr b/src/test/ui/error-codes/E0601.stderr index cbc20db35da77..a687f575615d7 100644 --- a/src/test/ui/error-codes/E0601.stderr +++ b/src/test/ui/error-codes/E0601.stderr @@ -1,6 +1,8 @@ error[E0601]: `main` function not found in crate `E0601` + --> $DIR/E0601.rs:1:37 | - = note: consider adding a `main` function to `$DIR/E0601.rs` +LL | + | ^ consider adding a `main` function to `$DIR/E0601.rs` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0617.rs b/src/test/ui/error-codes/E0617.rs index 439c3db576864..c832e09ac1118 100644 --- a/src/test/ui/error-codes/E0617.rs +++ b/src/test/ui/error-codes/E0617.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - extern { fn printf(c: *const i8, ...); } @@ -22,7 +20,7 @@ fn main() { //~^ ERROR can't pass `u16` to variadic function //~| HELP cast the value to `c_uint` printf(::std::ptr::null(), printf); - //~^ ERROR can't pass `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...) {printf}` to variadic function - //~| HELP cast the value to `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...)` + //~^ ERROR can't pass `unsafe extern "C" fn(*const i8, ...) {printf}` to variadic function + //~| HELP cast the value to `unsafe extern "C" fn(*const i8, ...)` } } diff --git a/src/test/ui/error-codes/E0617.stderr b/src/test/ui/error-codes/E0617.stderr index d866320bbcdf7..7c4df099d0dd1 100644 --- a/src/test/ui/error-codes/E0617.stderr +++ b/src/test/ui/error-codes/E0617.stderr @@ -1,42 +1,42 @@ error[E0617]: can't pass `f32` to variadic function - --> $DIR/E0617.rs:9:36 + --> $DIR/E0617.rs:7:36 | LL | printf(::std::ptr::null(), 0f32); | ^^^^ help: cast the value to `c_double`: `0f32 as c_double` error[E0617]: can't pass `i8` to variadic function - --> $DIR/E0617.rs:12:36 + --> $DIR/E0617.rs:10:36 | LL | printf(::std::ptr::null(), 0i8); | ^^^ help: cast the value to `c_int`: `0i8 as c_int` error[E0617]: can't pass `i16` to variadic function - --> $DIR/E0617.rs:15:36 + --> $DIR/E0617.rs:13:36 | LL | printf(::std::ptr::null(), 0i16); | ^^^^ help: cast the value to `c_int`: `0i16 as c_int` error[E0617]: can't pass `u8` to variadic function - --> $DIR/E0617.rs:18:36 + --> $DIR/E0617.rs:16:36 | LL | printf(::std::ptr::null(), 0u8); | ^^^ help: cast the value to `c_uint`: `0u8 as c_uint` error[E0617]: can't pass `u16` to variadic function - --> $DIR/E0617.rs:21:36 + --> $DIR/E0617.rs:19:36 | LL | printf(::std::ptr::null(), 0u16); | ^^^^ help: cast the value to `c_uint`: `0u16 as c_uint` -error[E0617]: can't pass `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...) {printf}` to variadic function - --> $DIR/E0617.rs:24:36 +error[E0617]: can't pass `unsafe extern "C" fn(*const i8, ...) {printf}` to variadic function + --> $DIR/E0617.rs:22:36 | LL | printf(::std::ptr::null(), printf); | ^^^^^^ -help: cast the value to `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...)` +help: cast the value to `unsafe extern "C" fn(*const i8, ...)` | -LL | printf(::std::ptr::null(), printf as for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | printf(::std::ptr::null(), printf as unsafe extern "C" fn(*const i8, ...)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr index f50c64780118b..feca7f10b706b 100644 --- a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr +++ b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr @@ -27,3 +27,4 @@ LL | invoke(&x, |a, b| if a > b { a } else { b }); error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/error-codes/E0661.rs b/src/test/ui/error-codes/E0661.rs index 2440e3a446eb4..5ac0c415ae1b2 100644 --- a/src/test/ui/error-codes/E0661.rs +++ b/src/test/ui/error-codes/E0661.rs @@ -3,7 +3,7 @@ #![feature(asm)] fn main() { - let a; + let a; //~ ERROR type annotations needed asm!("nop" : "r"(a)); //~^ ERROR E0661 } diff --git a/src/test/ui/error-codes/E0661.stderr b/src/test/ui/error-codes/E0661.stderr index 58f7e7fa0f919..3537e0bc3a4c6 100644 --- a/src/test/ui/error-codes/E0661.stderr +++ b/src/test/ui/error-codes/E0661.stderr @@ -4,5 +4,12 @@ error[E0661]: output operand constraint lacks '=' or '+' LL | asm!("nop" : "r"(a)); | ^^^ -error: aborting due to previous error +error[E0282]: type annotations needed + --> $DIR/E0661.rs:6:9 + | +LL | let a; + | ^ consider giving `a` a type + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr index 8808e95d81b18..73571a375b5f6 100644 --- a/src/test/ui/error-festival.stderr +++ b/src/test/ui/error-festival.stderr @@ -24,7 +24,7 @@ error[E0599]: no method named `z` found for type `&str` in the current scope --> $DIR/error-festival.rs:16:7 | LL | x.z(); - | ^ + | ^ method not found in `&str` error[E0600]: cannot apply unary operator `!` to type `Question` --> $DIR/error-festival.rs:19:5 diff --git a/src/test/ui/error-should-say-copy-not-pod.stderr b/src/test/ui/error-should-say-copy-not-pod.stderr index 7143f8c914dd0..d0148f418e33b 100644 --- a/src/test/ui/error-should-say-copy-not-pod.stderr +++ b/src/test/ui/error-should-say-copy-not-pod.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied - --> $DIR/error-should-say-copy-not-pod.rs:6:5 - | -LL | check_bound("nocopy".to_string()); - | ^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` - | -note: required by `check_bound` - --> $DIR/error-should-say-copy-not-pod.rs:3:1 + --> $DIR/error-should-say-copy-not-pod.rs:6:17 | LL | fn check_bound(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ----------- ---- required by this bound in `check_bound` +... +LL | check_bound("nocopy".to_string()); + | ^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` error: aborting due to previous error diff --git a/src/test/ui/explicit/explicit-self-lifetime-mismatch.rs b/src/test/ui/explicit/explicit-self-lifetime-mismatch.rs index 82c64bcf6a767..9ab8e13893bc7 100644 --- a/src/test/ui/explicit/explicit-self-lifetime-mismatch.rs +++ b/src/test/ui/explicit/explicit-self-lifetime-mismatch.rs @@ -6,11 +6,11 @@ struct Foo<'a,'b> { impl<'a,'b> Foo<'a,'b> { fn bar(self: Foo<'b,'a> - //~^ ERROR mismatched method receiver + //~^ ERROR mismatched `self` parameter type //~| expected type `Foo<'a, 'b>` //~| found type `Foo<'b, 'a>` //~| lifetime mismatch - //~| ERROR mismatched method receiver + //~| ERROR mismatched `self` parameter type //~| expected type `Foo<'a, 'b>` //~| found type `Foo<'b, 'a>` //~| lifetime mismatch diff --git a/src/test/ui/explicit/explicit-self-lifetime-mismatch.stderr b/src/test/ui/explicit/explicit-self-lifetime-mismatch.stderr index e6f9eded9a4f3..4bf2d573d4f96 100644 --- a/src/test/ui/explicit/explicit-self-lifetime-mismatch.stderr +++ b/src/test/ui/explicit/explicit-self-lifetime-mismatch.stderr @@ -1,4 +1,4 @@ -error[E0308]: mismatched method receiver +error[E0308]: mismatched `self` parameter type --> $DIR/explicit-self-lifetime-mismatch.rs:8:12 | LL | Foo<'b,'a> @@ -17,7 +17,7 @@ note: ...does not necessarily outlive the lifetime 'a as defined on the impl at LL | impl<'a,'b> Foo<'a,'b> { | ^^ -error[E0308]: mismatched method receiver +error[E0308]: mismatched `self` parameter type --> $DIR/explicit-self-lifetime-mismatch.rs:8:12 | LL | Foo<'b,'a> diff --git a/src/test/ui/ext-nonexistent.stderr b/src/test/ui/ext-nonexistent.stderr index 3fbbb4952649f..f3aa83fd50806 100644 --- a/src/test/ui/ext-nonexistent.stderr +++ b/src/test/ui/ext-nonexistent.stderr @@ -1,4 +1,4 @@ -error: cannot find macro `iamnotanextensionthatexists!` in this scope +error: cannot find macro `iamnotanextensionthatexists` in this scope --> $DIR/ext-nonexistent.rs:2:13 | LL | fn main() { iamnotanextensionthatexists!(""); } diff --git a/src/test/ui/extenv/issue-55897.rs b/src/test/ui/extenv/issue-55897.rs index c3975f6b9255e..64c4107e89875 100644 --- a/src/test/ui/extenv/issue-55897.rs +++ b/src/test/ui/extenv/issue-55897.rs @@ -1,7 +1,7 @@ use prelude::*; //~ ERROR unresolved import `prelude` mod unresolved_env { - use env; + use env; //~ ERROR unresolved import `env` include!(concat!(env!("NON_EXISTENT"), "/data.rs")); //~^ ERROR cannot determine resolution for the macro `env` diff --git a/src/test/ui/extenv/issue-55897.stderr b/src/test/ui/extenv/issue-55897.stderr index 9d68131beabd7..c57a467cdba56 100644 --- a/src/test/ui/extenv/issue-55897.stderr +++ b/src/test/ui/extenv/issue-55897.stderr @@ -19,6 +19,12 @@ LL | use prelude::*; | unresolved import | help: a similar path exists: `std::prelude` +error[E0432]: unresolved import `env` + --> $DIR/issue-55897.rs:4:9 + | +LL | use env; + | ^^^ no `env` in the root + error: cannot determine resolution for the macro `env` --> $DIR/issue-55897.rs:6:22 | @@ -27,6 +33,6 @@ LL | include!(concat!(env!("NON_EXISTENT"), "/data.rs")); | = note: import resolution is stuck, try simplifying macro imports -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/extern/extern-crate-visibility.rs b/src/test/ui/extern/extern-crate-visibility.rs index b51e44390313b..e0a5cd5e98f4b 100644 --- a/src/test/ui/extern/extern-crate-visibility.rs +++ b/src/test/ui/extern/extern-crate-visibility.rs @@ -3,10 +3,10 @@ mod foo { } // Check that private crates can be used from outside their modules, albeit with warnings -use foo::core::cell; //~ ERROR extern crate `core` is private +use foo::core::cell; //~ ERROR crate `core` is private fn f() { - foo::core::cell::Cell::new(0); //~ ERROR extern crate `core` is private + foo::core::cell::Cell::new(0); //~ ERROR crate `core` is private use foo::*; mod core {} // Check that private crates are not glob imported diff --git a/src/test/ui/extern/extern-crate-visibility.stderr b/src/test/ui/extern/extern-crate-visibility.stderr index 8bc9f9a67e7ef..38c791ab83237 100644 --- a/src/test/ui/extern/extern-crate-visibility.stderr +++ b/src/test/ui/extern/extern-crate-visibility.stderr @@ -1,10 +1,10 @@ -error[E0603]: extern crate `core` is private +error[E0603]: crate `core` is private --> $DIR/extern-crate-visibility.rs:6:10 | LL | use foo::core::cell; | ^^^^ -error[E0603]: extern crate `core` is private +error[E0603]: crate `core` is private --> $DIR/extern-crate-visibility.rs:9:10 | LL | foo::core::cell::Cell::new(0); diff --git a/src/test/ui/extern/extern-types-not-sync-send.stderr b/src/test/ui/extern/extern-types-not-sync-send.stderr index bc9d96df776ed..c395f3875ea0e 100644 --- a/src/test/ui/extern/extern-types-not-sync-send.stderr +++ b/src/test/ui/extern/extern-types-not-sync-send.stderr @@ -1,28 +1,24 @@ error[E0277]: `A` cannot be shared between threads safely - --> $DIR/extern-types-not-sync-send.rs:13:5 + --> $DIR/extern-types-not-sync-send.rs:13:19 | +LL | fn assert_sync() { } + | ----------- ---- required by this bound in `assert_sync` +... LL | assert_sync::(); - | ^^^^^^^^^^^^^^^^ `A` cannot be shared between threads safely + | ^ `A` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `A` -note: required by `assert_sync` - --> $DIR/extern-types-not-sync-send.rs:9:1 - | -LL | fn assert_sync() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `A` cannot be sent between threads safely - --> $DIR/extern-types-not-sync-send.rs:16:5 + --> $DIR/extern-types-not-sync-send.rs:16:19 | +LL | fn assert_send() { } + | ----------- ---- required by this bound in `assert_send` +... LL | assert_send::(); - | ^^^^^^^^^^^^^^^^ `A` cannot be sent between threads safely + | ^ `A` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `A` -note: required by `assert_send` - --> $DIR/extern-types-not-sync-send.rs:10:1 - | -LL | fn assert_send() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/extern/extern-types-unsized.stderr b/src/test/ui/extern/extern-types-unsized.stderr index 4e4f5550fe833..0417186eed346 100644 --- a/src/test/ui/extern/extern-types-unsized.stderr +++ b/src/test/ui/extern/extern-types-unsized.stderr @@ -1,50 +1,47 @@ error[E0277]: the size for values of type `A` cannot be known at compilation time - --> $DIR/extern-types-unsized.rs:22:5 + --> $DIR/extern-types-unsized.rs:22:20 | +LL | fn assert_sized() { } + | ------------ - required by this bound in `assert_sized` +... LL | assert_sized::(); - | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `A` = note: to learn more, visit -note: required by `assert_sized` - --> $DIR/extern-types-unsized.rs:19:1 - | -LL | fn assert_sized() { } - | ^^^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `A` cannot be known at compilation time --> $DIR/extern-types-unsized.rs:25:5 | +LL | fn assert_sized() { } + | ------------ - required by this bound in `assert_sized` +... LL | assert_sized::(); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `A` = note: to learn more, visit = note: required because it appears within the type `Foo` -note: required by `assert_sized` - --> $DIR/extern-types-unsized.rs:19:1 - | -LL | fn assert_sized() { } - | ^^^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `A` cannot be known at compilation time --> $DIR/extern-types-unsized.rs:28:5 | +LL | fn assert_sized() { } + | ------------ - required by this bound in `assert_sized` +... LL | assert_sized::>(); | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `Bar`, the trait `std::marker::Sized` is not implemented for `A` = note: to learn more, visit = note: required because it appears within the type `Bar` -note: required by `assert_sized` - --> $DIR/extern-types-unsized.rs:19:1 - | -LL | fn assert_sized() { } - | ^^^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `A` cannot be known at compilation time --> $DIR/extern-types-unsized.rs:31:5 | +LL | fn assert_sized() { } + | ------------ - required by this bound in `assert_sized` +... LL | assert_sized::>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | @@ -52,11 +49,6 @@ LL | assert_sized::>>(); = note: to learn more, visit = note: required because it appears within the type `Bar` = note: required because it appears within the type `Bar>` -note: required by `assert_sized` - --> $DIR/extern-types-unsized.rs:19:1 - | -LL | fn assert_sized() { } - | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/extern/extern-wrong-value-type.stderr b/src/test/ui/extern/extern-wrong-value-type.stderr index dce33f3d6323d..9a6af8119a8c5 100644 --- a/src/test/ui/extern/extern-wrong-value-type.stderr +++ b/src/test/ui/extern/extern-wrong-value-type.stderr @@ -1,16 +1,14 @@ error[E0277]: expected a `std::ops::Fn<()>` closure, found `extern "C" fn() {f}` - --> $DIR/extern-wrong-value-type.rs:9:5 + --> $DIR/extern-wrong-value-type.rs:9:11 | +LL | fn is_fn(_: F) where F: Fn() {} + | ----- ---- required by this bound in `is_fn` +... LL | is_fn(f); - | ^^^^^ expected an `Fn<()>` closure, found `extern "C" fn() {f}` + | ^ expected an `Fn<()>` closure, found `extern "C" fn() {f}` | = help: the trait `std::ops::Fn<()>` is not implemented for `extern "C" fn() {f}` = note: wrap the `extern "C" fn() {f}` in a closure with no arguments: `|| { /* code */ } -note: required by `is_fn` - --> $DIR/extern-wrong-value-type.rs:4:1 - | -LL | fn is_fn(_: F) where F: Fn() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs b/src/test/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs new file mode 100644 index 0000000000000..ff10d412a110a --- /dev/null +++ b/src/test/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs @@ -0,0 +1,65 @@ +// run-pass +// ignore-wasm32-bare compiled with panic=abort by default +// ignore-emscripten no threads support + +// rust-lang/rust#64655: with panic=unwind, a panic from a subroutine +// should still run destructors as it unwinds the stack. However, +// bugs with how the nounwind LLVM attribute was applied led to this +// simple case being mishandled *if* you had fat LTO turned on. + +// Unlike issue-64655-extern-rust-must-allow-unwind.rs, the issue +// embodied in this test cropped up regardless of optimization level. +// Therefore it seemed worthy of being enshrined as a dedicated unit +// test. + +// LTO settings cannot be combined with -C prefer-dynamic +// no-prefer-dynamic + +// The revisions just enumerate lto settings (the opt-level appeared irrelevant in practice) + +// revisions: no thin fat +//[no]compile-flags: -C lto=no +//[thin]compile-flags: -C lto=thin +//[fat]compile-flags: -C lto=fat + +#![feature(core_panic)] + +// (For some reason, reproducing the LTO issue requires pulling in std +// explicitly this way.) +#![no_std] +extern crate std; + +fn main() { + use std::sync::atomic::{AtomicUsize, Ordering}; + use std::boxed::Box; + + static SHARED: AtomicUsize = AtomicUsize::new(0); + + assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 0); + + let old_hook = std::panic::take_hook(); + + std::panic::set_hook(Box::new(|_| { } )); // no-op on panic. + + let handle = std::thread::spawn(|| { + struct Droppable; + impl Drop for Droppable { + fn drop(&mut self) { + SHARED.fetch_add(1, Ordering::SeqCst); + } + } + + let _guard = Droppable; + let s = "issue-64655-allow-unwind-when-calling-panic-directly.rs"; + core::panicking::panic(&("???", s, 17, 4)); + }); + + let wait = handle.join(); + + // Reinstate handler to ease observation of assertion failures. + std::panic::set_hook(old_hook); + + assert!(wait.is_err()); + + assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 1); +} diff --git a/src/test/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs b/src/test/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs new file mode 100644 index 0000000000000..bc15fcb0e3996 --- /dev/null +++ b/src/test/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs @@ -0,0 +1,83 @@ +// run-pass +// ignore-wasm32-bare compiled with panic=abort by default +// ignore-emscripten no threads support + +// rust-lang/rust#64655: with panic=unwind, a panic from a subroutine +// should still run destructors as it unwinds the stack. However, +// bugs with how the nounwind LLVM attribute was applied led to this +// simple case being mishandled *if* you had optimization *and* fat +// LTO turned on. + +// This test is the closest thing to a "regression test" we can do +// without actually spawning subprocesses and comparing stderr +// results. +// +// This test takes the code from the above issue and adapts it to +// better fit our test infrastructure: +// +// * Instead of relying on `println!` to observe whether the destructor +// is run, we instead run the code in a spawned thread and +// communicate the destructor's operation via a synchronous atomic +// in static memory. +// +// * To keep the output from confusing a casual user, we override the +// panic hook to be a no-op (rather than printing a message to +// stderr). +// +// (pnkfelix has confirmed by hand that these additions do not mask +// the underlying bug.) + +// LTO settings cannot be combined with -C prefer-dynamic +// no-prefer-dynamic + +// The revisions combine each lto setting with each optimization +// setting; pnkfelix observed three differing behaviors at opt-levels +// 0/1/2+3 for this test, so it seems prudent to be thorough. + +// revisions: no0 no1 no2 no3 thin0 thin1 thin2 thin3 fat0 fat1 fat2 fat3 + +//[no0]compile-flags: -C opt-level=0 -C lto=no +//[no1]compile-flags: -C opt-level=1 -C lto=no +//[no2]compile-flags: -C opt-level=2 -C lto=no +//[no3]compile-flags: -C opt-level=3 -C lto=no +//[thin0]compile-flags: -C opt-level=0 -C lto=thin +//[thin1]compile-flags: -C opt-level=1 -C lto=thin +//[thin2]compile-flags: -C opt-level=2 -C lto=thin +//[thin3]compile-flags: -C opt-level=3 -C lto=thin +//[fat0]compile-flags: -C opt-level=0 -C lto=fat +//[fat1]compile-flags: -C opt-level=1 -C lto=fat +//[fat2]compile-flags: -C opt-level=2 -C lto=fat +//[fat3]compile-flags: -C opt-level=3 -C lto=fat + +fn main() { + use std::sync::atomic::{AtomicUsize, Ordering}; + + static SHARED: AtomicUsize = AtomicUsize::new(0); + + assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 0); + + let old_hook = std::panic::take_hook(); + + std::panic::set_hook(Box::new(|_| { } )); // no-op on panic. + + let handle = std::thread::spawn(|| { + struct Droppable; + impl Drop for Droppable { + fn drop(&mut self) { + SHARED.fetch_add(1, Ordering::SeqCst); + } + } + + let _guard = Droppable; + None::<()>.expect("???"); + }); + + let wait = handle.join(); + + // reinstate handler to ease observation of assertion failures. + std::panic::set_hook(old_hook); + + assert!(wait.is_err()); + + assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 1); +} diff --git a/src/test/ui/feature-gate-optimize_attribute.rs b/src/test/ui/feature-gate-optimize_attribute.rs index 7fc0fdde6fba8..15aa3a6af4ca9 100644 --- a/src/test/ui/feature-gate-optimize_attribute.rs +++ b/src/test/ui/feature-gate-optimize_attribute.rs @@ -1,17 +1,17 @@ #![crate_type="rlib"] -#![optimize(speed)] //~ ERROR `#[optimize]` attribute is an unstable feature +#![optimize(speed)] //~ ERROR the `#[optimize]` attribute is an experimental feature -#[optimize(size)] //~ ERROR `#[optimize]` attribute is an unstable feature +#[optimize(size)] //~ ERROR the `#[optimize]` attribute is an experimental feature mod module { -#[optimize(size)] //~ ERROR `#[optimize]` attribute is an unstable feature +#[optimize(size)] //~ ERROR the `#[optimize]` attribute is an experimental feature fn size() {} -#[optimize(speed)] //~ ERROR `#[optimize]` attribute is an unstable feature +#[optimize(speed)] //~ ERROR the `#[optimize]` attribute is an experimental feature fn speed() {} #[optimize(banana)] -//~^ ERROR `#[optimize]` attribute is an unstable feature +//~^ ERROR the `#[optimize]` attribute is an experimental feature //~| ERROR E0722 fn not_known() {} diff --git a/src/test/ui/feature-gate-optimize_attribute.stderr b/src/test/ui/feature-gate-optimize_attribute.stderr index 4ec512eaf39a4..3e3ad71c344ee 100644 --- a/src/test/ui/feature-gate-optimize_attribute.stderr +++ b/src/test/ui/feature-gate-optimize_attribute.stderr @@ -1,4 +1,4 @@ -error[E0658]: `#[optimize]` attribute is an unstable feature +error[E0658]: the `#[optimize]` attribute is an experimental feature --> $DIR/feature-gate-optimize_attribute.rs:7:1 | LL | #[optimize(size)] @@ -7,7 +7,7 @@ LL | #[optimize(size)] = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add `#![feature(optimize_attribute)]` to the crate attributes to enable -error[E0658]: `#[optimize]` attribute is an unstable feature +error[E0658]: the `#[optimize]` attribute is an experimental feature --> $DIR/feature-gate-optimize_attribute.rs:10:1 | LL | #[optimize(speed)] @@ -16,7 +16,7 @@ LL | #[optimize(speed)] = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add `#![feature(optimize_attribute)]` to the crate attributes to enable -error[E0658]: `#[optimize]` attribute is an unstable feature +error[E0658]: the `#[optimize]` attribute is an experimental feature --> $DIR/feature-gate-optimize_attribute.rs:13:1 | LL | #[optimize(banana)] @@ -25,7 +25,7 @@ LL | #[optimize(banana)] = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add `#![feature(optimize_attribute)]` to the crate attributes to enable -error[E0658]: `#[optimize]` attribute is an unstable feature +error[E0658]: the `#[optimize]` attribute is an experimental feature --> $DIR/feature-gate-optimize_attribute.rs:4:1 | LL | #[optimize(size)] @@ -34,7 +34,7 @@ LL | #[optimize(size)] = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add `#![feature(optimize_attribute)]` to the crate attributes to enable -error[E0658]: `#[optimize]` attribute is an unstable feature +error[E0658]: the `#[optimize]` attribute is an experimental feature --> $DIR/feature-gate-optimize_attribute.rs:2:1 | LL | #![optimize(speed)] diff --git a/src/test/ui/feature-gate/allow-features-empty.rs b/src/test/ui/feature-gate/allow-features-empty.rs index 784a1d2697d67..641e4b852e79f 100644 --- a/src/test/ui/feature-gate/allow-features-empty.rs +++ b/src/test/ui/feature-gate/allow-features-empty.rs @@ -1,8 +1,6 @@ // compile-flags: -Z allow_features= // Note: This test uses rustc internal flags because they will never stabilize. -#![feature(rustc_diagnostic_macros)] //~ ERROR - #![feature(rustc_const_unstable)] //~ ERROR #![feature(lang_items)] //~ ERROR diff --git a/src/test/ui/feature-gate/allow-features-empty.stderr b/src/test/ui/feature-gate/allow-features-empty.stderr index ab41422ed05b8..a87d105850327 100644 --- a/src/test/ui/feature-gate/allow-features-empty.stderr +++ b/src/test/ui/feature-gate/allow-features-empty.stderr @@ -1,27 +1,21 @@ -error[E0725]: the feature `rustc_diagnostic_macros` is not in the list of allowed features - --> $DIR/allow-features-empty.rs:4:12 - | -LL | #![feature(rustc_diagnostic_macros)] - | ^^^^^^^^^^^^^^^^^^^^^^^ - error[E0725]: the feature `rustc_const_unstable` is not in the list of allowed features - --> $DIR/allow-features-empty.rs:6:12 + --> $DIR/allow-features-empty.rs:4:12 | LL | #![feature(rustc_const_unstable)] | ^^^^^^^^^^^^^^^^^^^^ error[E0725]: the feature `lang_items` is not in the list of allowed features - --> $DIR/allow-features-empty.rs:8:12 + --> $DIR/allow-features-empty.rs:6:12 | LL | #![feature(lang_items)] | ^^^^^^^^^^ error[E0725]: the feature `unknown_stdlib_feature` is not in the list of allowed features - --> $DIR/allow-features-empty.rs:10:12 + --> $DIR/allow-features-empty.rs:8:12 | LL | #![feature(unknown_stdlib_feature)] | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0725`. diff --git a/src/test/ui/feature-gate/allow-features.rs b/src/test/ui/feature-gate/allow-features.rs index de3439a5b628f..de69e48a65fdf 100644 --- a/src/test/ui/feature-gate/allow-features.rs +++ b/src/test/ui/feature-gate/allow-features.rs @@ -1,8 +1,6 @@ -// compile-flags: -Z allow_features=rustc_diagnostic_macros,lang_items +// compile-flags: -Z allow_features=lang_items // Note: This test uses rustc internal flags because they will never stabilize. -#![feature(rustc_diagnostic_macros)] - #![feature(rustc_const_unstable)] //~ ERROR #![feature(lang_items)] diff --git a/src/test/ui/feature-gate/allow-features.stderr b/src/test/ui/feature-gate/allow-features.stderr index 5b39a6f053bde..157dddf06ad1d 100644 --- a/src/test/ui/feature-gate/allow-features.stderr +++ b/src/test/ui/feature-gate/allow-features.stderr @@ -1,11 +1,11 @@ error[E0725]: the feature `rustc_const_unstable` is not in the list of allowed features - --> $DIR/allow-features.rs:6:12 + --> $DIR/allow-features.rs:4:12 | LL | #![feature(rustc_const_unstable)] | ^^^^^^^^^^^^^^^^^^^^ error[E0725]: the feature `unknown_stdlib_feature` is not in the list of allowed features - --> $DIR/allow-features.rs:10:12 + --> $DIR/allow-features.rs:8:12 | LL | #![feature(unknown_stdlib_feature)] | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/feature-gate/feature-gate-static-nobundle-2.rs b/src/test/ui/feature-gate/feature-gate-static-nobundle-2.rs index 92844f9306d28..b6c8648a7d03d 100644 --- a/src/test/ui/feature-gate/feature-gate-static-nobundle-2.rs +++ b/src/test/ui/feature-gate/feature-gate-static-nobundle-2.rs @@ -1,4 +1,4 @@ -//~ ERROR kind="static-nobundle" is feature gated +//~ ERROR kind="static-nobundle" is unstable // Test the behavior of rustc when non-existent library is statically linked // compile-flags: -l static-nobundle=nonexistent diff --git a/src/test/ui/feature-gate/feature-gate-static-nobundle-2.stderr b/src/test/ui/feature-gate/feature-gate-static-nobundle-2.stderr index 059559dd92831..cfff4c36a6d7b 100644 --- a/src/test/ui/feature-gate/feature-gate-static-nobundle-2.stderr +++ b/src/test/ui/feature-gate/feature-gate-static-nobundle-2.stderr @@ -1,4 +1,4 @@ -error[E0658]: kind="static-nobundle" is feature gated +error[E0658]: kind="static-nobundle" is unstable | = note: for more information, see https://github.com/rust-lang/rust/issues/37403 = help: add `#![feature(static_nobundle)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs index 6d51bb3f8ada8..8c567ece1875b 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs @@ -32,9 +32,13 @@ // check-pass -#![feature(test)] +#![feature(test, plugin_registrar)] #![warn(unused_attributes, unknown_lints)] +// Exception, a gated and deprecated attribute. + +#![plugin_registrar] //~ WARN unused attribute + // UNGATED WHITE-LISTED BUILT-IN ATTRIBUTES #![warn(x5400)] //~ WARN unknown lint: `x5400` @@ -43,7 +47,6 @@ #![deny(x5100)] //~ WARN unknown lint: `x5100` #![macro_use] // (allowed if no argument; see issue-43160-gating-of-macro_use.rs) #![macro_export] //~ WARN unused attribute -#![plugin_registrar] //~ WARN unused attribute // skipping testing of cfg // skipping testing of cfg_attr #![main] //~ WARN unused attribute @@ -84,12 +87,12 @@ #![crate_name = "0900"] #![crate_type = "bin"] // cannot pass "0800" here -// For #![crate_id], see issue #43142. (I cannot bear to enshrine current behavior in a test) +#![crate_id = "10"] //~ WARN use of deprecated attribute // FIXME(#44232) we should warn that this isn't used. #![feature(rust1)] -// For #![no_start], see issue #43144. (I cannot bear to enshrine current behavior in a test) +#![no_start] //~ WARN use of deprecated attribute // (cannot easily gating state of crate-level #[no_main]; but non crate-level is below at "0400") #![no_builtins] diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr index 864df35a79fe3..62a6d97dfe83b 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr @@ -1,5 +1,5 @@ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:44:9 | LL | #![warn(x5400)] | ^^^^^ @@ -11,183 +11,233 @@ LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:41:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:10 | LL | #![allow(x5300)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:42:11 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:46:11 | LL | #![forbid(x5200)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:47:9 | LL | #![deny(x5100)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:101:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:104:8 | LL | #[warn(x5400)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:104:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:107:25 | LL | mod inner { #![warn(x5400)] } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:107:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:110:12 | LL | #[warn(x5400)] fn f() { } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:110:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:113:12 | LL | #[warn(x5400)] struct S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:113:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:116:12 | LL | #[warn(x5400)] type T = S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:116:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:119:12 | LL | #[warn(x5400)] impl S { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:120:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:123:9 | LL | #[allow(x5300)] | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:123:26 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:126:26 | LL | mod inner { #![allow(x5300)] } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:126:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:129:13 | LL | #[allow(x5300)] fn f() { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:129:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:132:13 | LL | #[allow(x5300)] struct S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:132:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:135:13 | LL | #[allow(x5300)] type T = S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:135:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:138:13 | LL | #[allow(x5300)] impl S { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:139:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:142:10 | LL | #[forbid(x5200)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:142:27 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:145:27 | LL | mod inner { #![forbid(x5200)] } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:145:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:148:14 | LL | #[forbid(x5200)] fn f() { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:148:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:151:14 | LL | #[forbid(x5200)] struct S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:151:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:154:14 | LL | #[forbid(x5200)] type T = S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:154:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:157:14 | LL | #[forbid(x5200)] impl S { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:158:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:161:8 | LL | #[deny(x5100)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:161:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:164:25 | LL | mod inner { #![deny(x5100)] } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:164:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:167:12 | LL | #[deny(x5100)] fn f() { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:167:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:170:12 | LL | #[deny(x5100)] struct S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:170:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:173:12 | LL | #[deny(x5100)] type T = S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:173:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:12 | LL | #[deny(x5100)] impl S { } | ^^^^^ warning: macro_escape is a deprecated synonym for macro_use - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:457:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:460:1 | LL | #[macro_escape] | ^^^^^^^^^^^^^^^ warning: macro_escape is a deprecated synonym for macro_use - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:460:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:463:17 | LL | mod inner { #![macro_escape] } | ^^^^^^^^^^^^^^^^ | = help: consider an outer attribute, `#[macro_use]` mod ... +warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:219:17 + | +LL | mod inner { #![plugin_registrar] } + | ^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + +warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:224:5 + | +LL | #[plugin_registrar] struct S; + | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute + +warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:5 + | +LL | #[plugin_registrar] type T = S; + | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute + +warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:230:5 + | +LL | #[plugin_registrar] impl S { } + | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute + +warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:216:1 + | +LL | #[plugin_registrar] + | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute + +warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:1 + | +LL | #![plugin_registrar] + | ^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + +warning: use of deprecated attribute `crate_id`: no longer used. + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:90:1 + | +LL | #![crate_id = "10"] + | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute + +warning: use of deprecated attribute `no_start`: no longer used. + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:95:1 + | +LL | #![no_start] + | ^^^^^^^^^^^^ help: remove this attribute + warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:90:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:93:12 | LL | #![feature(rust1)] | ^^^^^ @@ -195,7 +245,7 @@ LL | #![feature(rust1)] = note: `#[warn(stable_features)]` on by default warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:181:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:184:5 | LL | #[macro_use] fn f() { } | ^^^^^^^^^^^^ @@ -207,925 +257,919 @@ LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:184:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:187:5 | LL | #[macro_use] struct S; | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:187:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:190:5 | LL | #[macro_use] type T = S; | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:190:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:193:5 | LL | #[macro_use] impl S { } | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:197:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:200:17 | LL | mod inner { #![macro_export] } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:200:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:203:5 | LL | #[macro_export] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:203:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:206:5 | LL | #[macro_export] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:206:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:209:5 | LL | #[macro_export] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:209:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:212:5 | LL | #[macro_export] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:194:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:197:1 | LL | #[macro_export] | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:216:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:219:17 | LL | mod inner { #![plugin_registrar] } | ^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:224:5 | LL | #[plugin_registrar] struct S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:224:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:5 | LL | #[plugin_registrar] type T = S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:230:5 | LL | #[plugin_registrar] impl S { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:213:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:216:1 | LL | #[plugin_registrar] | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:234:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:237:17 | LL | mod inner { #![main] } | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:239:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:242:5 | LL | #[main] struct S; | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:242:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:245:5 | LL | #[main] type T = S; | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:245:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:248:5 | LL | #[main] impl S { } | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:231:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:234:1 | LL | #[main] | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:252:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:255:17 | LL | mod inner { #![start] } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:257:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:260:5 | LL | #[start] struct S; | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:260:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:263:5 | LL | #[start] type T = S; | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:263:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:266:5 | LL | #[start] impl S { } | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:249:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:252:1 | LL | #[start] | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:316:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:319:5 | LL | #[path = "3800"] fn f() { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:319:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:322:5 | LL | #[path = "3800"] struct S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:322:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:325:5 | LL | #[path = "3800"] type T = S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:325:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:328:5 | LL | #[path = "3800"] impl S { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:335:17 | LL | mod inner { #![automatically_derived] } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:335:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:338:5 | LL | #[automatically_derived] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:338:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:5 | LL | #[automatically_derived] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:344:5 | LL | #[automatically_derived] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:344:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:5 | LL | #[automatically_derived] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:329:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:17 | LL | mod inner { #![no_link] } | ^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5 | LL | #[no_link] fn f() { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:5 | LL | #[no_link] struct S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:376:5 | LL | #[no_link]type T = S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:376:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:5 | LL | #[no_link] impl S { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:1 | LL | #[no_link] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:383:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:17 | LL | mod inner { #![should_panic] } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:5 | LL | #[should_panic] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:392:5 | LL | #[should_panic] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:392:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:395:5 | LL | #[should_panic] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:395:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:5 | LL | #[should_panic] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:383:1 | LL | #[should_panic] | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:402:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:405:17 | LL | mod inner { #![ignore] } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:405:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:5 | LL | #[ignore] fn f() { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:5 | LL | #[ignore] struct S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5 | LL | #[ignore] type T = S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:5 | LL | #[ignore] impl S { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:399:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:402:1 | LL | #[ignore] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:424:17 | LL | mod inner { #![no_implicit_prelude] } | ^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:424:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:5 | LL | #[no_implicit_prelude] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:5 | LL | #[no_implicit_prelude] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5 | LL | #[no_implicit_prelude] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:436:5 | LL | #[no_implicit_prelude] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:418:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:1 | LL | #[no_implicit_prelude] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:440:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:443:17 | LL | mod inner { #![reexport_test_harness_main="2900"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:443:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:446:5 | LL | #[reexport_test_harness_main = "2900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:446:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:449:5 | LL | #[reexport_test_harness_main = "2900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:449:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:452:5 | LL | #[reexport_test_harness_main = "2900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:452:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:455:5 | LL | #[reexport_test_harness_main = "2900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:437:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:440:1 | LL | #[reexport_test_harness_main = "2900"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:463:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:5 | LL | #[macro_escape] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:469:5 | LL | #[macro_escape] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:469:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:472:5 | LL | #[macro_escape] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:472:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:475:5 | LL | #[macro_escape] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:480:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:483:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:480:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:483:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:484:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:484:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:491:5 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:491:5 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:495:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:495:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:1 | LL | #[no_std] | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:1 | LL | #[no_std] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:639:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:642:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:639:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:642:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:643:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:643:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:647:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:647:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:651:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:651:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:631:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:634:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:631:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:634:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:664:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:664:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:668:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:668:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:672:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:672:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:656:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:656:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:689:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:689:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:711:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:714:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:711:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:714:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:715:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:715:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:719:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:719:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:723:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:723:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:727:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:730:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:727:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:730:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:1 | LL | #[no_main] | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:1 | LL | #[no_main] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:749:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:752:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:749:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:752:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:757:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:760:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:757:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:760:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:768:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:768:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:748:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:748:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:774:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:777:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:774:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:777:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:778:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:778:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:790:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:790:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:1 - | -LL | #![macro_export] - | ^^^^^^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:46:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:1 | LL | #![plugin_registrar] | ^^^^^^^^^^^^^^^^^^^^ @@ -1133,53 +1177,59 @@ LL | #![plugin_registrar] warning: unused attribute --> $DIR/issue-43106-gating-of-builtin-attrs.rs:49:1 | +LL | #![macro_export] + | ^^^^^^^^^^^^^^^^ + +warning: unused attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:52:1 + | LL | #![main] | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:50:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1 | LL | #![start] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:56:1 | LL | #![repr()] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:55:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:58:1 | LL | #![path = "3800"] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:56:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1 | LL | #![automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:58:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:61:1 | LL | #![no_link] | ^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:63:1 | LL | #![should_panic] | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:61:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1 | LL | #![ignore] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:67:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:70:1 | LL | #![proc_macro_derive()] | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-derive-2.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-derive-2.stderr index be3536aa789c1..f14591c85e62e 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-derive-2.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-derive-2.stderr @@ -1,5 +1,5 @@ error: cannot find derive macro `x3300` in this scope - --> $DIR/issue-43106-gating-of-derive-2.rs:4:14 + --> $DIR/issue-43106-gating-of-derive-2.rs:12:14 | LL | #[derive(x3300)] | ^^^^^ @@ -11,7 +11,7 @@ LL | #[derive(x3300)] | ^^^^^ error: cannot find derive macro `x3300` in this scope - --> $DIR/issue-43106-gating-of-derive-2.rs:12:14 + --> $DIR/issue-43106-gating-of-derive-2.rs:4:14 | LL | #[derive(x3300)] | ^^^^^ diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-derive.rs b/src/test/ui/feature-gate/issue-43106-gating-of-derive.rs index 1397412988491..c5d9e0db4d389 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-derive.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-derive.rs @@ -1,9 +1,6 @@ // `#![derive]` raises errors when it occurs at contexts other than ADT // definitions. -#![derive(Debug)] -//~^ ERROR `derive` may only be applied to structs, enums and unions - #[derive(Debug)] //~^ ERROR `derive` may only be applied to structs, enums and unions mod derive { diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr index 25f160983d3df..db29a2bddd35c 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr @@ -1,38 +1,32 @@ error: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:4:1 | -LL | #![derive(Debug)] - | ^^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Debug)]` - -error: `derive` may only be applied to structs, enums and unions - --> $DIR/issue-43106-gating-of-derive.rs:7:1 - | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions - --> $DIR/issue-43106-gating-of-derive.rs:10:17 + --> $DIR/issue-43106-gating-of-derive.rs:7:17 | LL | mod inner { #![derive(Debug)] } | ^^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Debug)]` error: `derive` may only be applied to structs, enums and unions - --> $DIR/issue-43106-gating-of-derive.rs:13:5 + --> $DIR/issue-43106-gating-of-derive.rs:10:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions - --> $DIR/issue-43106-gating-of-derive.rs:26:5 + --> $DIR/issue-43106-gating-of-derive.rs:23:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions - --> $DIR/issue-43106-gating-of-derive.rs:30:5 + --> $DIR/issue-43106-gating-of-derive.rs:27:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-rustc_deprecated.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-rustc_deprecated.stderr index 4eead36910356..8c6c26f7b2d81 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-rustc_deprecated.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-rustc_deprecated.stderr @@ -1,40 +1,40 @@ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:7:1 | LL | #![rustc_deprecated()] | ^^^^^^^^^^^^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:10:1 | LL | #[rustc_deprecated()] | ^^^^^^^^^^^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:13:17 | LL | mod inner { #![rustc_deprecated()] } | ^^^^^^^^^^^^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:16:5 | LL | #[rustc_deprecated()] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:19:5 | LL | #[rustc_deprecated()] struct S; | ^^^^^^^^^^^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:22:5 | LL | #[rustc_deprecated()] type T = S; | ^^^^^^^^^^^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:25:5 | LL | #[rustc_deprecated()] impl S { } @@ -42,3 +42,4 @@ LL | #[rustc_deprecated()] impl S { } error: aborting due to 7 previous errors +For more information about this error, try `rustc --explain E0734`. diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-stable.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-stable.stderr index 03410eabe3652..09dabd293ff97 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-stable.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-stable.stderr @@ -1,40 +1,40 @@ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-stable.rs:7:1 | LL | #![stable()] | ^^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-stable.rs:10:1 | LL | #[stable()] | ^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-stable.rs:13:17 | LL | mod inner { #![stable()] } | ^^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-stable.rs:16:5 | LL | #[stable()] fn f() { } | ^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-stable.rs:19:5 | LL | #[stable()] struct S; | ^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-stable.rs:22:5 | LL | #[stable()] type T = S; | ^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-stable.rs:25:5 | LL | #[stable()] impl S { } @@ -42,3 +42,4 @@ LL | #[stable()] impl S { } error: aborting due to 7 previous errors +For more information about this error, try `rustc --explain E0734`. diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-unstable.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-unstable.stderr index 5952b3836aac8..49da2c59580e7 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-unstable.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-unstable.stderr @@ -1,40 +1,40 @@ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-unstable.rs:7:1 | LL | #![unstable()] | ^^^^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-unstable.rs:10:1 | LL | #[unstable()] | ^^^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-unstable.rs:13:17 | LL | mod inner { #![unstable()] } | ^^^^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-unstable.rs:16:5 | LL | #[unstable()] fn f() { } | ^^^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-unstable.rs:19:5 | LL | #[unstable()] struct S; | ^^^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-unstable.rs:22:5 | LL | #[unstable()] type T = S; | ^^^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-unstable.rs:25:5 | LL | #[unstable()] impl S { } @@ -42,3 +42,4 @@ LL | #[unstable()] impl S { } error: aborting due to 7 previous errors +For more information about this error, try `rustc --explain E0734`. diff --git a/src/test/ui/feature-gates/bench.rs b/src/test/ui/feature-gates/bench.rs new file mode 100644 index 0000000000000..8de390becbe7d --- /dev/null +++ b/src/test/ui/feature-gates/bench.rs @@ -0,0 +1,9 @@ +// edition:2018 + +#[bench] //~ ERROR use of unstable library feature 'test' + //~| WARN this was previously accepted +fn bench() {} + +use bench as _; //~ ERROR use of unstable library feature 'test' + //~| WARN this was previously accepted +fn main() {} diff --git a/src/test/ui/feature-gates/bench.stderr b/src/test/ui/feature-gates/bench.stderr new file mode 100644 index 0000000000000..168ac92572437 --- /dev/null +++ b/src/test/ui/feature-gates/bench.stderr @@ -0,0 +1,21 @@ +error: use of unstable library feature 'test': `bench` is a part of custom test frameworks which are unstable + --> $DIR/bench.rs:3:3 + | +LL | #[bench] + | ^^^^^ + | + = note: `#[deny(soft_unstable)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #64266 + +error: use of unstable library feature 'test': `bench` is a part of custom test frameworks which are unstable + --> $DIR/bench.rs:7:5 + | +LL | use bench as _; + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #64266 + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/feature-gates/feature-gate-abi.rs b/src/test/ui/feature-gates/feature-gate-abi.rs index 41c9f79bfe3ed..61da38eea74b3 100644 --- a/src/test/ui/feature-gates/feature-gate-abi.rs +++ b/src/test/ui/feature-gates/feature-gate-abi.rs @@ -10,7 +10,9 @@ // Functions extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change +//~^ ERROR intrinsic must be in extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experimental +//~^ ERROR intrinsic must be in extern "vectorcall" fn f3() {} //~ ERROR vectorcall is experimental and subject to change extern "rust-call" fn f4() {} //~ ERROR rust-call ABI is subject to change extern "msp430-interrupt" fn f5() {} //~ ERROR msp430-interrupt ABI is experimental @@ -22,7 +24,9 @@ extern "amdgpu-kernel" fn f9() {} //~ ERROR amdgpu-kernel ABI is experimental an // Methods in trait definition trait Tr { extern "rust-intrinsic" fn m1(); //~ ERROR intrinsics are subject to change + //~^ ERROR intrinsic must be in extern "platform-intrinsic" fn m2(); //~ ERROR platform intrinsics are experimental + //~^ ERROR intrinsic must be in extern "vectorcall" fn m3(); //~ ERROR vectorcall is experimental and subject to change extern "rust-call" fn m4(); //~ ERROR rust-call ABI is subject to change extern "msp430-interrupt" fn m5(); //~ ERROR msp430-interrupt ABI is experimental @@ -31,8 +35,6 @@ trait Tr { extern "thiscall" fn m8(); //~ ERROR thiscall is experimental and subject to change extern "amdgpu-kernel" fn m9(); //~ ERROR amdgpu-kernel ABI is experimental and subject to change - extern "rust-intrinsic" fn dm1() {} //~ ERROR intrinsics are subject to change - extern "platform-intrinsic" fn dm2() {} //~ ERROR platform intrinsics are experimental extern "vectorcall" fn dm3() {} //~ ERROR vectorcall is experimental and subject to change extern "rust-call" fn dm4() {} //~ ERROR rust-call ABI is subject to change extern "msp430-interrupt" fn dm5() {} //~ ERROR msp430-interrupt ABI is experimental @@ -47,7 +49,9 @@ struct S; // Methods in trait impl impl Tr for S { extern "rust-intrinsic" fn m1() {} //~ ERROR intrinsics are subject to change + //~^ ERROR intrinsic must be in extern "platform-intrinsic" fn m2() {} //~ ERROR platform intrinsics are experimental + //~^ ERROR intrinsic must be in extern "vectorcall" fn m3() {} //~ ERROR vectorcall is experimental and subject to change extern "rust-call" fn m4() {} //~ ERROR rust-call ABI is subject to change extern "msp430-interrupt" fn m5() {} //~ ERROR msp430-interrupt ABI is experimental @@ -60,7 +64,9 @@ impl Tr for S { // Methods in inherent impl impl S { extern "rust-intrinsic" fn im1() {} //~ ERROR intrinsics are subject to change + //~^ ERROR intrinsic must be in extern "platform-intrinsic" fn im2() {} //~ ERROR platform intrinsics are experimental + //~^ ERROR intrinsic must be in extern "vectorcall" fn im3() {} //~ ERROR vectorcall is experimental and subject to change extern "rust-call" fn im4() {} //~ ERROR rust-call ABI is subject to change extern "msp430-interrupt" fn im5() {} //~ ERROR msp430-interrupt ABI is experimental diff --git a/src/test/ui/feature-gates/feature-gate-abi.stderr b/src/test/ui/feature-gates/feature-gate-abi.stderr index 88e0b8667be54..afda76dc2b0aa 100644 --- a/src/test/ui/feature-gates/feature-gate-abi.stderr +++ b/src/test/ui/feature-gates/feature-gate-abi.stderr @@ -7,7 +7,7 @@ LL | extern "rust-intrinsic" fn f1() {} = help: add `#![feature(intrinsics)]` to the crate attributes to enable error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:13:1 + --> $DIR/feature-gate-abi.rs:14:1 | LL | extern "platform-intrinsic" fn f2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | extern "platform-intrinsic" fn f2() {} = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:14:1 + --> $DIR/feature-gate-abi.rs:16:1 | LL | extern "vectorcall" fn f3() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | extern "vectorcall" fn f3() {} = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:15:1 + --> $DIR/feature-gate-abi.rs:17:1 | LL | extern "rust-call" fn f4() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | extern "rust-call" fn f4() {} = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: msp430-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:16:1 + --> $DIR/feature-gate-abi.rs:18:1 | LL | extern "msp430-interrupt" fn f5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,7 +42,7 @@ LL | extern "msp430-interrupt" fn f5() {} = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable error[E0658]: PTX ABIs are experimental and subject to change - --> $DIR/feature-gate-abi.rs:17:1 + --> $DIR/feature-gate-abi.rs:19:1 | LL | extern "ptx-kernel" fn f6() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -51,7 +51,7 @@ LL | extern "ptx-kernel" fn f6() {} = help: add `#![feature(abi_ptx)]` to the crate attributes to enable error[E0658]: x86-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:18:1 + --> $DIR/feature-gate-abi.rs:20:1 | LL | extern "x86-interrupt" fn f7() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | extern "x86-interrupt" fn f7() {} = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:19:1 + --> $DIR/feature-gate-abi.rs:21:1 | LL | extern "thiscall" fn f8() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL | extern "thiscall" fn f8() {} = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:20:1 + --> $DIR/feature-gate-abi.rs:22:1 | LL | extern "amdgpu-kernel" fn f9() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -77,7 +77,7 @@ LL | extern "amdgpu-kernel" fn f9() {} = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-abi.rs:24:5 + --> $DIR/feature-gate-abi.rs:26:5 | LL | extern "rust-intrinsic" fn m1(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | extern "rust-intrinsic" fn m1(); = help: add `#![feature(intrinsics)]` to the crate attributes to enable error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:25:5 + --> $DIR/feature-gate-abi.rs:28:5 | LL | extern "platform-intrinsic" fn m2(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -94,7 +94,7 @@ LL | extern "platform-intrinsic" fn m2(); = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:26:5 + --> $DIR/feature-gate-abi.rs:30:5 | LL | extern "vectorcall" fn m3(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -102,7 +102,7 @@ LL | extern "vectorcall" fn m3(); = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:27:5 + --> $DIR/feature-gate-abi.rs:31:5 | LL | extern "rust-call" fn m4(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -111,7 +111,7 @@ LL | extern "rust-call" fn m4(); = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: msp430-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:28:5 + --> $DIR/feature-gate-abi.rs:32:5 | LL | extern "msp430-interrupt" fn m5(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -120,7 +120,7 @@ LL | extern "msp430-interrupt" fn m5(); = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable error[E0658]: PTX ABIs are experimental and subject to change - --> $DIR/feature-gate-abi.rs:29:5 + --> $DIR/feature-gate-abi.rs:33:5 | LL | extern "ptx-kernel" fn m6(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -129,7 +129,7 @@ LL | extern "ptx-kernel" fn m6(); = help: add `#![feature(abi_ptx)]` to the crate attributes to enable error[E0658]: x86-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:30:5 + --> $DIR/feature-gate-abi.rs:34:5 | LL | extern "x86-interrupt" fn m7(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -138,7 +138,7 @@ LL | extern "x86-interrupt" fn m7(); = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:31:5 + --> $DIR/feature-gate-abi.rs:35:5 | LL | extern "thiscall" fn m8(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -146,7 +146,7 @@ LL | extern "thiscall" fn m8(); = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:32:5 + --> $DIR/feature-gate-abi.rs:36:5 | LL | extern "amdgpu-kernel" fn m9(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -154,25 +154,8 @@ LL | extern "amdgpu-kernel" fn m9(); = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable -error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-abi.rs:34:5 - | -LL | extern "rust-intrinsic" fn dm1() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(intrinsics)]` to the crate attributes to enable - -error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:35:5 - | -LL | extern "platform-intrinsic" fn dm2() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/27731 - = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable - error[E0658]: vectorcall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:36:5 + --> $DIR/feature-gate-abi.rs:38:5 | LL | extern "vectorcall" fn dm3() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -180,7 +163,7 @@ LL | extern "vectorcall" fn dm3() {} = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:37:5 + --> $DIR/feature-gate-abi.rs:39:5 | LL | extern "rust-call" fn dm4() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -189,7 +172,7 @@ LL | extern "rust-call" fn dm4() {} = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: msp430-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:38:5 + --> $DIR/feature-gate-abi.rs:40:5 | LL | extern "msp430-interrupt" fn dm5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -198,7 +181,7 @@ LL | extern "msp430-interrupt" fn dm5() {} = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable error[E0658]: PTX ABIs are experimental and subject to change - --> $DIR/feature-gate-abi.rs:39:5 + --> $DIR/feature-gate-abi.rs:41:5 | LL | extern "ptx-kernel" fn dm6() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -207,7 +190,7 @@ LL | extern "ptx-kernel" fn dm6() {} = help: add `#![feature(abi_ptx)]` to the crate attributes to enable error[E0658]: x86-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:40:5 + --> $DIR/feature-gate-abi.rs:42:5 | LL | extern "x86-interrupt" fn dm7() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -216,7 +199,7 @@ LL | extern "x86-interrupt" fn dm7() {} = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:41:5 + --> $DIR/feature-gate-abi.rs:43:5 | LL | extern "thiscall" fn dm8() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -224,7 +207,7 @@ LL | extern "thiscall" fn dm8() {} = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:42:5 + --> $DIR/feature-gate-abi.rs:44:5 | LL | extern "amdgpu-kernel" fn dm9() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -233,7 +216,7 @@ LL | extern "amdgpu-kernel" fn dm9() {} = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-abi.rs:49:5 + --> $DIR/feature-gate-abi.rs:51:5 | LL | extern "rust-intrinsic" fn m1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,7 +224,7 @@ LL | extern "rust-intrinsic" fn m1() {} = help: add `#![feature(intrinsics)]` to the crate attributes to enable error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:50:5 + --> $DIR/feature-gate-abi.rs:53:5 | LL | extern "platform-intrinsic" fn m2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -250,7 +233,7 @@ LL | extern "platform-intrinsic" fn m2() {} = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:51:5 + --> $DIR/feature-gate-abi.rs:55:5 | LL | extern "vectorcall" fn m3() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -258,7 +241,7 @@ LL | extern "vectorcall" fn m3() {} = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:52:5 + --> $DIR/feature-gate-abi.rs:56:5 | LL | extern "rust-call" fn m4() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -267,7 +250,7 @@ LL | extern "rust-call" fn m4() {} = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: msp430-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:53:5 + --> $DIR/feature-gate-abi.rs:57:5 | LL | extern "msp430-interrupt" fn m5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -276,7 +259,7 @@ LL | extern "msp430-interrupt" fn m5() {} = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable error[E0658]: PTX ABIs are experimental and subject to change - --> $DIR/feature-gate-abi.rs:54:5 + --> $DIR/feature-gate-abi.rs:58:5 | LL | extern "ptx-kernel" fn m6() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -285,7 +268,7 @@ LL | extern "ptx-kernel" fn m6() {} = help: add `#![feature(abi_ptx)]` to the crate attributes to enable error[E0658]: x86-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:55:5 + --> $DIR/feature-gate-abi.rs:59:5 | LL | extern "x86-interrupt" fn m7() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -294,7 +277,7 @@ LL | extern "x86-interrupt" fn m7() {} = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:56:5 + --> $DIR/feature-gate-abi.rs:60:5 | LL | extern "thiscall" fn m8() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -302,7 +285,7 @@ LL | extern "thiscall" fn m8() {} = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:57:5 + --> $DIR/feature-gate-abi.rs:61:5 | LL | extern "amdgpu-kernel" fn m9() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -311,7 +294,7 @@ LL | extern "amdgpu-kernel" fn m9() {} = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-abi.rs:62:5 + --> $DIR/feature-gate-abi.rs:66:5 | LL | extern "rust-intrinsic" fn im1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -319,7 +302,7 @@ LL | extern "rust-intrinsic" fn im1() {} = help: add `#![feature(intrinsics)]` to the crate attributes to enable error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:63:5 + --> $DIR/feature-gate-abi.rs:68:5 | LL | extern "platform-intrinsic" fn im2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -328,7 +311,7 @@ LL | extern "platform-intrinsic" fn im2() {} = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:64:5 + --> $DIR/feature-gate-abi.rs:70:5 | LL | extern "vectorcall" fn im3() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -336,7 +319,7 @@ LL | extern "vectorcall" fn im3() {} = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:65:5 + --> $DIR/feature-gate-abi.rs:71:5 | LL | extern "rust-call" fn im4() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -345,7 +328,7 @@ LL | extern "rust-call" fn im4() {} = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: msp430-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:66:5 + --> $DIR/feature-gate-abi.rs:72:5 | LL | extern "msp430-interrupt" fn im5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -354,7 +337,7 @@ LL | extern "msp430-interrupt" fn im5() {} = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable error[E0658]: PTX ABIs are experimental and subject to change - --> $DIR/feature-gate-abi.rs:67:5 + --> $DIR/feature-gate-abi.rs:73:5 | LL | extern "ptx-kernel" fn im6() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -363,7 +346,7 @@ LL | extern "ptx-kernel" fn im6() {} = help: add `#![feature(abi_ptx)]` to the crate attributes to enable error[E0658]: x86-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:68:5 + --> $DIR/feature-gate-abi.rs:74:5 | LL | extern "x86-interrupt" fn im7() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -372,7 +355,7 @@ LL | extern "x86-interrupt" fn im7() {} = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:69:5 + --> $DIR/feature-gate-abi.rs:75:5 | LL | extern "thiscall" fn im8() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -380,7 +363,7 @@ LL | extern "thiscall" fn im8() {} = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:70:5 + --> $DIR/feature-gate-abi.rs:76:5 | LL | extern "amdgpu-kernel" fn im9() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -389,7 +372,7 @@ LL | extern "amdgpu-kernel" fn im9() {} = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-abi.rs:74:11 + --> $DIR/feature-gate-abi.rs:80:11 | LL | type A1 = extern "rust-intrinsic" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -397,7 +380,7 @@ LL | type A1 = extern "rust-intrinsic" fn(); = help: add `#![feature(intrinsics)]` to the crate attributes to enable error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:75:11 + --> $DIR/feature-gate-abi.rs:81:11 | LL | type A2 = extern "platform-intrinsic" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -406,7 +389,7 @@ LL | type A2 = extern "platform-intrinsic" fn(); = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:76:11 + --> $DIR/feature-gate-abi.rs:82:11 | LL | type A3 = extern "vectorcall" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -414,7 +397,7 @@ LL | type A3 = extern "vectorcall" fn(); = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:77:11 + --> $DIR/feature-gate-abi.rs:83:11 | LL | type A4 = extern "rust-call" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -423,7 +406,7 @@ LL | type A4 = extern "rust-call" fn(); = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: msp430-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:78:11 + --> $DIR/feature-gate-abi.rs:84:11 | LL | type A5 = extern "msp430-interrupt" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -432,7 +415,7 @@ LL | type A5 = extern "msp430-interrupt" fn(); = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable error[E0658]: PTX ABIs are experimental and subject to change - --> $DIR/feature-gate-abi.rs:79:11 + --> $DIR/feature-gate-abi.rs:85:11 | LL | type A6 = extern "ptx-kernel" fn (); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -441,7 +424,7 @@ LL | type A6 = extern "ptx-kernel" fn (); = help: add `#![feature(abi_ptx)]` to the crate attributes to enable error[E0658]: x86-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:80:11 + --> $DIR/feature-gate-abi.rs:86:11 | LL | type A7 = extern "x86-interrupt" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -450,7 +433,7 @@ LL | type A7 = extern "x86-interrupt" fn(); = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:81:11 + --> $DIR/feature-gate-abi.rs:87:11 | LL | type A8 = extern "thiscall" fn(); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -458,7 +441,7 @@ LL | type A8 = extern "thiscall" fn(); = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:82:11 + --> $DIR/feature-gate-abi.rs:88:11 | LL | type A9 = extern "amdgpu-kernel" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -467,7 +450,7 @@ LL | type A9 = extern "amdgpu-kernel" fn(); = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-abi.rs:85:1 + --> $DIR/feature-gate-abi.rs:91:1 | LL | extern "rust-intrinsic" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -475,7 +458,7 @@ LL | extern "rust-intrinsic" {} = help: add `#![feature(intrinsics)]` to the crate attributes to enable error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:86:1 + --> $DIR/feature-gate-abi.rs:92:1 | LL | extern "platform-intrinsic" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -484,7 +467,7 @@ LL | extern "platform-intrinsic" {} = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:87:1 + --> $DIR/feature-gate-abi.rs:93:1 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^^^^^^^^^^^ @@ -492,7 +475,7 @@ LL | extern "vectorcall" {} = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:88:1 + --> $DIR/feature-gate-abi.rs:94:1 | LL | extern "rust-call" {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -501,7 +484,7 @@ LL | extern "rust-call" {} = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: msp430-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:89:1 + --> $DIR/feature-gate-abi.rs:95:1 | LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -510,7 +493,7 @@ LL | extern "msp430-interrupt" {} = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable error[E0658]: PTX ABIs are experimental and subject to change - --> $DIR/feature-gate-abi.rs:90:1 + --> $DIR/feature-gate-abi.rs:96:1 | LL | extern "ptx-kernel" {} | ^^^^^^^^^^^^^^^^^^^^^^ @@ -519,7 +502,7 @@ LL | extern "ptx-kernel" {} = help: add `#![feature(abi_ptx)]` to the crate attributes to enable error[E0658]: x86-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:91:1 + --> $DIR/feature-gate-abi.rs:97:1 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -528,7 +511,7 @@ LL | extern "x86-interrupt" {} = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:92:1 + --> $DIR/feature-gate-abi.rs:98:1 | LL | extern "thiscall" {} | ^^^^^^^^^^^^^^^^^^^^ @@ -536,7 +519,7 @@ LL | extern "thiscall" {} = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:93:1 + --> $DIR/feature-gate-abi.rs:99:1 | LL | extern "amdgpu-kernel" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -544,6 +527,54 @@ LL | extern "amdgpu-kernel" {} = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable -error: aborting due to 63 previous errors +error: intrinsic must be in `extern "rust-intrinsic" { ... }` block + --> $DIR/feature-gate-abi.rs:26:32 + | +LL | extern "rust-intrinsic" fn m1(); + | ^^ + +error: intrinsic must be in `extern "rust-intrinsic" { ... }` block + --> $DIR/feature-gate-abi.rs:28:36 + | +LL | extern "platform-intrinsic" fn m2(); + | ^^ + +error: intrinsic must be in `extern "rust-intrinsic" { ... }` block + --> $DIR/feature-gate-abi.rs:12:33 + | +LL | extern "rust-intrinsic" fn f1() {} + | ^^ + +error: intrinsic must be in `extern "rust-intrinsic" { ... }` block + --> $DIR/feature-gate-abi.rs:14:37 + | +LL | extern "platform-intrinsic" fn f2() {} + | ^^ + +error: intrinsic must be in `extern "rust-intrinsic" { ... }` block + --> $DIR/feature-gate-abi.rs:51:37 + | +LL | extern "rust-intrinsic" fn m1() {} + | ^^ + +error: intrinsic must be in `extern "rust-intrinsic" { ... }` block + --> $DIR/feature-gate-abi.rs:53:41 + | +LL | extern "platform-intrinsic" fn m2() {} + | ^^ + +error: intrinsic must be in `extern "rust-intrinsic" { ... }` block + --> $DIR/feature-gate-abi.rs:66:38 + | +LL | extern "rust-intrinsic" fn im1() {} + | ^^ + +error: intrinsic must be in `extern "rust-intrinsic" { ... }` block + --> $DIR/feature-gate-abi.rs:68:42 + | +LL | extern "platform-intrinsic" fn im2() {} + | ^^ + +error: aborting due to 69 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-alloc-error-handler.rs b/src/test/ui/feature-gates/feature-gate-alloc-error-handler.rs index 17b4f775ad4de..ad89096183080 100644 --- a/src/test/ui/feature-gates/feature-gate-alloc-error-handler.rs +++ b/src/test/ui/feature-gates/feature-gate-alloc-error-handler.rs @@ -5,7 +5,7 @@ use core::alloc::Layout; -#[alloc_error_handler] //~ ERROR `#[alloc_error_handler]` is an unstable feature +#[alloc_error_handler] //~ ERROR the `#[alloc_error_handler]` attribute is an experimental feature fn oom(info: Layout) -> ! { loop {} } diff --git a/src/test/ui/feature-gates/feature-gate-alloc-error-handler.stderr b/src/test/ui/feature-gates/feature-gate-alloc-error-handler.stderr index d18cc09ffe777..79e44bf0d8ec1 100644 --- a/src/test/ui/feature-gates/feature-gate-alloc-error-handler.stderr +++ b/src/test/ui/feature-gates/feature-gate-alloc-error-handler.stderr @@ -1,4 +1,4 @@ -error[E0658]: `#[alloc_error_handler]` is an unstable feature +error[E0658]: the `#[alloc_error_handler]` attribute is an experimental feature --> $DIR/feature-gate-alloc-error-handler.rs:8:1 | LL | #[alloc_error_handler] diff --git a/src/test/ui/feature-gates/feature-gate-allow_fail.rs b/src/test/ui/feature-gates/feature-gate-allow_fail.rs index f9ad48551410c..287d4ccf18010 100644 --- a/src/test/ui/feature-gates/feature-gate-allow_fail.rs +++ b/src/test/ui/feature-gates/feature-gate-allow_fail.rs @@ -1,6 +1,6 @@ // check that #[allow_fail] is feature-gated -#[allow_fail] //~ ERROR allow_fail attribute is currently unstable +#[allow_fail] //~ ERROR the `#[allow_fail]` attribute is an experimental feature fn ok_to_fail() { assert!(false); } diff --git a/src/test/ui/feature-gates/feature-gate-allow_fail.stderr b/src/test/ui/feature-gates/feature-gate-allow_fail.stderr index 37bf3a262aaa0..0f60a2de3a4e5 100644 --- a/src/test/ui/feature-gates/feature-gate-allow_fail.stderr +++ b/src/test/ui/feature-gates/feature-gate-allow_fail.stderr @@ -1,4 +1,4 @@ -error[E0658]: allow_fail attribute is currently unstable +error[E0658]: the `#[allow_fail]` attribute is an experimental feature --> $DIR/feature-gate-allow_fail.rs:3:1 | LL | #[allow_fail] diff --git a/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.rs b/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.rs deleted file mode 100644 index 801aeb82aa266..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.rs +++ /dev/null @@ -1,9 +0,0 @@ -// edition:2015 - -async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition - //~^ ERROR async fn is unstable - -fn main() { - let _ = async {}; //~ ERROR cannot find struct, variant or union type `async` - let _ = async || { true }; //~ ERROR cannot find value `async` in this scope -} diff --git a/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.stderr b/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.stderr deleted file mode 100644 index 0157ed5534423..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/feature-gate-async-await-2015-edition.rs:3:1 - | -LL | async fn foo() {} - | ^^^^^ - -error[E0422]: cannot find struct, variant or union type `async` in this scope - --> $DIR/feature-gate-async-await-2015-edition.rs:7:13 - | -LL | let _ = async {}; - | ^^^^^ not found in this scope - -error[E0425]: cannot find value `async` in this scope - --> $DIR/feature-gate-async-await-2015-edition.rs:8:13 - | -LL | let _ = async || { true }; - | ^^^^^ not found in this scope - -error[E0658]: async fn is unstable - --> $DIR/feature-gate-async-await-2015-edition.rs:3:1 - | -LL | async fn foo() {} - | ^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/50547 - = help: add `#![feature(async_await)]` to the crate attributes to enable - -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0422, E0425, E0658, E0670. -For more information about an error, try `rustc --explain E0422`. diff --git a/src/test/ui/feature-gates/feature-gate-async-await.rs b/src/test/ui/feature-gates/feature-gate-async-await.rs deleted file mode 100644 index 78391c0e104cc..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-async-await.rs +++ /dev/null @@ -1,18 +0,0 @@ -// edition:2018 - -struct S; - -impl S { - async fn foo() {} //~ ERROR async fn is unstable -} - -trait T { - async fn foo(); //~ ERROR trait fns cannot be declared `async` - //~^ ERROR async fn is unstable -} - -async fn foo() {} //~ ERROR async fn is unstable - -fn main() { - let _ = async {}; //~ ERROR async blocks are unstable -} diff --git a/src/test/ui/feature-gates/feature-gate-async-await.stderr b/src/test/ui/feature-gates/feature-gate-async-await.stderr deleted file mode 100644 index 9f4a90157a495..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-async-await.stderr +++ /dev/null @@ -1,45 +0,0 @@ -error[E0706]: trait fns cannot be declared `async` - --> $DIR/feature-gate-async-await.rs:10:5 - | -LL | async fn foo(); - | ^^^^^^^^^^^^^^^ - -error[E0658]: async fn is unstable - --> $DIR/feature-gate-async-await.rs:6:5 - | -LL | async fn foo() {} - | ^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/50547 - = help: add `#![feature(async_await)]` to the crate attributes to enable - -error[E0658]: async fn is unstable - --> $DIR/feature-gate-async-await.rs:10:5 - | -LL | async fn foo(); - | ^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/50547 - = help: add `#![feature(async_await)]` to the crate attributes to enable - -error[E0658]: async fn is unstable - --> $DIR/feature-gate-async-await.rs:14:1 - | -LL | async fn foo() {} - | ^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/50547 - = help: add `#![feature(async_await)]` to the crate attributes to enable - -error[E0658]: async blocks are unstable - --> $DIR/feature-gate-async-await.rs:17:13 - | -LL | let _ = async {}; - | ^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/50547 - = help: add `#![feature(async_await)]` to the crate attributes to enable - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs new file mode 100644 index 0000000000000..1ab11ce3b4423 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs @@ -0,0 +1,9 @@ +struct ConstFn; +//~^ ERROR const generics are unstable +//~^^ ERROR using function pointers as const generic parameters is unstable + +struct ConstPtr; +//~^ ERROR const generics are unstable +//~^^ ERROR using raw pointers as const generic parameters is unstable + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr new file mode 100644 index 0000000000000..935f84b9163d3 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr @@ -0,0 +1,39 @@ +error[E0658]: const generics are unstable + --> $DIR/feature-gate-const_generics-ptr.rs:1:22 + | +LL | struct ConstFn; + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/44580 + = help: add `#![feature(const_generics)]` to the crate attributes to enable + +error[E0658]: const generics are unstable + --> $DIR/feature-gate-const_generics-ptr.rs:5:23 + | +LL | struct ConstPtr; + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/44580 + = help: add `#![feature(const_generics)]` to the crate attributes to enable + +error[E0658]: using function pointers as const generic parameters is unstable + --> $DIR/feature-gate-const_generics-ptr.rs:1:25 + | +LL | struct ConstFn; + | ^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53020 + = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable + +error[E0658]: using raw pointers as const generic parameters is unstable + --> $DIR/feature-gate-const_generics-ptr.rs:5:26 + | +LL | struct ConstPtr; + | ^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53020 + = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute.rs b/src/test/ui/feature-gates/feature-gate-custom_attribute.rs index d34936b42a6ff..936cab268d2c9 100644 --- a/src/test/ui/feature-gates/feature-gate-custom_attribute.rs +++ b/src/test/ui/feature-gates/feature-gate-custom_attribute.rs @@ -1,18 +1,18 @@ // Check that literals in attributes parse just fine. -#[fake_attr] //~ ERROR cannot find attribute macro `fake_attr` in this scope -#[fake_attr(100)] //~ ERROR cannot find attribute macro `fake_attr` in this scope -#[fake_attr(1, 2, 3)] //~ ERROR cannot find attribute macro `fake_attr` in this scope -#[fake_attr("hello")] //~ ERROR cannot find attribute macro `fake_attr` in this scope -#[fake_attr(name = "hello")] //~ ERROR cannot find attribute macro `fake_attr` in this scope -#[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR cannot find attribute macro `fake_attr` in th -#[fake_attr(key = "hello", val = 10)] //~ ERROR cannot find attribute macro `fake_attr` in this scop -#[fake_attr(key("hello"), val(10))] //~ ERROR cannot find attribute macro `fake_attr` in this scope -#[fake_attr(enabled = true, disabled = false)] //~ ERROR cannot find attribute macro `fake_attr` in -#[fake_attr(true)] //~ ERROR cannot find attribute macro `fake_attr` in this scope -#[fake_attr(pi = 3.14159)] //~ ERROR cannot find attribute macro `fake_attr` in this scope -#[fake_attr(b"hi")] //~ ERROR cannot find attribute macro `fake_attr` in this scope -#[fake_doc(r"doc")] //~ ERROR cannot find attribute macro `fake_doc` in this scope +#[fake_attr] //~ ERROR cannot find attribute `fake_attr` in this scope +#[fake_attr(100)] //~ ERROR cannot find attribute `fake_attr` in this scope +#[fake_attr(1, 2, 3)] //~ ERROR cannot find attribute `fake_attr` in this scope +#[fake_attr("hello")] //~ ERROR cannot find attribute `fake_attr` in this scope +#[fake_attr(name = "hello")] //~ ERROR cannot find attribute `fake_attr` in this scope +#[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR cannot find attribute `fake_attr` in th +#[fake_attr(key = "hello", val = 10)] //~ ERROR cannot find attribute `fake_attr` in this scop +#[fake_attr(key("hello"), val(10))] //~ ERROR cannot find attribute `fake_attr` in this scope +#[fake_attr(enabled = true, disabled = false)] //~ ERROR cannot find attribute `fake_attr` in +#[fake_attr(true)] //~ ERROR cannot find attribute `fake_attr` in this scope +#[fake_attr(pi = 3.14159)] //~ ERROR cannot find attribute `fake_attr` in this scope +#[fake_attr(b"hi")] //~ ERROR cannot find attribute `fake_attr` in this scope +#[fake_doc(r"doc")] //~ ERROR cannot find attribute `fake_doc` in this scope struct Q {} fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr b/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr index efdc2d1cd31ed..b7c45ec1fb7ea 100644 --- a/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr +++ b/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr @@ -1,76 +1,76 @@ -error: cannot find attribute macro `fake_attr` in this scope +error: cannot find attribute `fake_attr` in this scope --> $DIR/feature-gate-custom_attribute.rs:3:3 | LL | #[fake_attr] | ^^^^^^^^^ -error: cannot find attribute macro `fake_attr` in this scope +error: cannot find attribute `fake_attr` in this scope --> $DIR/feature-gate-custom_attribute.rs:4:3 | LL | #[fake_attr(100)] | ^^^^^^^^^ -error: cannot find attribute macro `fake_attr` in this scope +error: cannot find attribute `fake_attr` in this scope --> $DIR/feature-gate-custom_attribute.rs:5:3 | LL | #[fake_attr(1, 2, 3)] | ^^^^^^^^^ -error: cannot find attribute macro `fake_attr` in this scope +error: cannot find attribute `fake_attr` in this scope --> $DIR/feature-gate-custom_attribute.rs:6:3 | LL | #[fake_attr("hello")] | ^^^^^^^^^ -error: cannot find attribute macro `fake_attr` in this scope +error: cannot find attribute `fake_attr` in this scope --> $DIR/feature-gate-custom_attribute.rs:7:3 | LL | #[fake_attr(name = "hello")] | ^^^^^^^^^ -error: cannot find attribute macro `fake_attr` in this scope +error: cannot find attribute `fake_attr` in this scope --> $DIR/feature-gate-custom_attribute.rs:8:3 | LL | #[fake_attr(1, "hi", key = 12, true, false)] | ^^^^^^^^^ -error: cannot find attribute macro `fake_attr` in this scope +error: cannot find attribute `fake_attr` in this scope --> $DIR/feature-gate-custom_attribute.rs:9:3 | LL | #[fake_attr(key = "hello", val = 10)] | ^^^^^^^^^ -error: cannot find attribute macro `fake_attr` in this scope +error: cannot find attribute `fake_attr` in this scope --> $DIR/feature-gate-custom_attribute.rs:10:3 | LL | #[fake_attr(key("hello"), val(10))] | ^^^^^^^^^ -error: cannot find attribute macro `fake_attr` in this scope +error: cannot find attribute `fake_attr` in this scope --> $DIR/feature-gate-custom_attribute.rs:11:3 | LL | #[fake_attr(enabled = true, disabled = false)] | ^^^^^^^^^ -error: cannot find attribute macro `fake_attr` in this scope +error: cannot find attribute `fake_attr` in this scope --> $DIR/feature-gate-custom_attribute.rs:12:3 | LL | #[fake_attr(true)] | ^^^^^^^^^ -error: cannot find attribute macro `fake_attr` in this scope +error: cannot find attribute `fake_attr` in this scope --> $DIR/feature-gate-custom_attribute.rs:13:3 | LL | #[fake_attr(pi = 3.14159)] | ^^^^^^^^^ -error: cannot find attribute macro `fake_attr` in this scope +error: cannot find attribute `fake_attr` in this scope --> $DIR/feature-gate-custom_attribute.rs:14:3 | LL | #[fake_attr(b"hi")] | ^^^^^^^^^ -error: cannot find attribute macro `fake_doc` in this scope +error: cannot find attribute `fake_doc` in this scope --> $DIR/feature-gate-custom_attribute.rs:15:3 | LL | #[fake_doc(r"doc")] diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute2.rs b/src/test/ui/feature-gates/feature-gate-custom_attribute2.rs index 8fe11cb02a021..e4c80141aa2a5 100644 --- a/src/test/ui/feature-gates/feature-gate-custom_attribute2.rs +++ b/src/test/ui/feature-gates/feature-gate-custom_attribute2.rs @@ -4,54 +4,54 @@ // gate-test-custom_attribute struct StLt<#[lt_struct] 'a>(&'a u32); -//~^ ERROR the attribute `lt_struct` is currently unknown to the compiler +//~^ ERROR cannot find attribute `lt_struct` in this scope struct StTy<#[ty_struct] I>(I); -//~^ ERROR the attribute `ty_struct` is currently unknown to the compiler +//~^ ERROR cannot find attribute `ty_struct` in this scope enum EnLt<#[lt_enum] 'b> { A(&'b u32), B } -//~^ ERROR the attribute `lt_enum` is currently unknown to the compiler +//~^ ERROR cannot find attribute `lt_enum` in this scope enum EnTy<#[ty_enum] J> { A(J), B } -//~^ ERROR the attribute `ty_enum` is currently unknown to the compiler +//~^ ERROR cannot find attribute `ty_enum` in this scope trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } -//~^ ERROR the attribute `lt_trait` is currently unknown to the compiler +//~^ ERROR cannot find attribute `lt_trait` in this scope trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); } -//~^ ERROR the attribute `ty_trait` is currently unknown to the compiler +//~^ ERROR cannot find attribute `ty_trait` in this scope type TyLt<#[lt_type] 'd> = &'d u32; -//~^ ERROR the attribute `lt_type` is currently unknown to the compiler +//~^ ERROR cannot find attribute `lt_type` in this scope type TyTy<#[ty_type] L> = (L, ); -//~^ ERROR the attribute `ty_type` is currently unknown to the compiler +//~^ ERROR cannot find attribute `ty_type` in this scope impl<#[lt_inherent] 'e> StLt<'e> { } -//~^ ERROR the attribute `lt_inherent` is currently unknown to the compiler +//~^ ERROR cannot find attribute `lt_inherent` in this scope impl<#[ty_inherent] M> StTy { } -//~^ ERROR the attribute `ty_inherent` is currently unknown to the compiler +//~^ ERROR cannot find attribute `ty_inherent` in this scope impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> { - //~^ ERROR the attribute `lt_impl_for` is currently unknown to the compiler + //~^ ERROR cannot find attribute `lt_impl_for` in this scope fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } } } impl<#[ty_impl_for] N> TrTy for StTy { - //~^ ERROR the attribute `ty_impl_for` is currently unknown to the compiler + //~^ ERROR cannot find attribute `ty_impl_for` in this scope fn foo(&self, _: N) { } } fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } -//~^ ERROR the attribute `lt_fn` is currently unknown to the compiler +//~^ ERROR cannot find attribute `lt_fn` in this scope fn f_ty<#[ty_fn] O>(_: O) { } -//~^ ERROR the attribute `ty_fn` is currently unknown to the compiler +//~^ ERROR cannot find attribute `ty_fn` in this scope impl StTy { fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } - //~^ ERROR the attribute `lt_meth` is currently unknown to the compiler + //~^ ERROR cannot find attribute `lt_meth` in this scope fn m_ty<#[ty_meth] P>(_: P) { } - //~^ ERROR the attribute `ty_meth` is currently unknown to the compiler + //~^ ERROR cannot find attribute `ty_meth` in this scope } fn hof_lt(_: Q) where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 - //~^ ERROR the attribute `lt_hof` is currently unknown to the compiler + //~^ ERROR cannot find attribute `lt_hof` in this scope { } diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr b/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr index 15e0c41b90637..bc89caddb4439 100644 --- a/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr +++ b/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr @@ -1,156 +1,104 @@ -error[E0658]: the attribute `lt_struct` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/feature-gate-custom_attribute2.rs:6:13 +error: cannot find attribute `lt_hof` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:53:21 | -LL | struct StLt<#[lt_struct] 'a>(&'a u32); - | ^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 + | ^^^^^^ -error[E0658]: the attribute `ty_struct` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/feature-gate-custom_attribute2.rs:8:13 +error: cannot find attribute `ty_meth` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:48:15 | -LL | struct StTy<#[ty_struct] I>(I); - | ^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | fn m_ty<#[ty_meth] P>(_: P) { } + | ^^^^^^^ -error[E0658]: the attribute `lt_enum` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/feature-gate-custom_attribute2.rs:11:11 +error: cannot find attribute `lt_meth` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:46:15 | -LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B } - | ^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } + | ^^^^^^^ -error[E0658]: the attribute `ty_enum` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/feature-gate-custom_attribute2.rs:13:11 - | -LL | enum EnTy<#[ty_enum] J> { A(J), B } - | ^^^^^^^^^^ +error: cannot find attribute `ty_fn` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:42:11 | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | fn f_ty<#[ty_fn] O>(_: O) { } + | ^^^^^ -error[E0658]: the attribute `lt_trait` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/feature-gate-custom_attribute2.rs:16:12 +error: cannot find attribute `lt_fn` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:40:11 | -LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } - | ^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } + | ^^^^^ -error[E0658]: the attribute `ty_trait` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/feature-gate-custom_attribute2.rs:18:12 - | -LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); } - | ^^^^^^^^^^^ +error: cannot find attribute `ty_impl_for` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:35:8 | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | impl<#[ty_impl_for] N> TrTy for StTy { + | ^^^^^^^^^^^ -error[E0658]: the attribute `lt_type` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/feature-gate-custom_attribute2.rs:21:11 - | -LL | type TyLt<#[lt_type] 'd> = &'d u32; - | ^^^^^^^^^^ +error: cannot find attribute `lt_impl_for` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:31:8 | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> { + | ^^^^^^^^^^^ -error[E0658]: the attribute `ty_type` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/feature-gate-custom_attribute2.rs:23:11 - | -LL | type TyTy<#[ty_type] L> = (L, ); - | ^^^^^^^^^^ +error: cannot find attribute `ty_inherent` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:28:8 | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | impl<#[ty_inherent] M> StTy { } + | ^^^^^^^^^^^ -error[E0658]: the attribute `lt_inherent` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/feature-gate-custom_attribute2.rs:26:6 +error: cannot find attribute `lt_inherent` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:26:8 | LL | impl<#[lt_inherent] 'e> StLt<'e> { } - | ^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable + | ^^^^^^^^^^^ -error[E0658]: the attribute `ty_inherent` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/feature-gate-custom_attribute2.rs:28:6 +error: cannot find attribute `ty_type` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:23:13 | -LL | impl<#[ty_inherent] M> StTy { } - | ^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | type TyTy<#[ty_type] L> = (L, ); + | ^^^^^^^ -error[E0658]: the attribute `lt_impl_for` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/feature-gate-custom_attribute2.rs:31:6 +error: cannot find attribute `lt_type` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:21:13 | -LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> { - | ^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | type TyLt<#[lt_type] 'd> = &'d u32; + | ^^^^^^^ -error[E0658]: the attribute `ty_impl_for` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/feature-gate-custom_attribute2.rs:35:6 +error: cannot find attribute `ty_trait` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:18:14 | -LL | impl<#[ty_impl_for] N> TrTy for StTy { - | ^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); } + | ^^^^^^^^ -error[E0658]: the attribute `lt_fn` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/feature-gate-custom_attribute2.rs:40:9 +error: cannot find attribute `lt_trait` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:16:14 | -LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } - | ^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } + | ^^^^^^^^ -error[E0658]: the attribute `ty_fn` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/feature-gate-custom_attribute2.rs:42:9 +error: cannot find attribute `ty_enum` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:13:13 | -LL | fn f_ty<#[ty_fn] O>(_: O) { } - | ^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | enum EnTy<#[ty_enum] J> { A(J), B } + | ^^^^^^^ -error[E0658]: the attribute `lt_meth` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/feature-gate-custom_attribute2.rs:46:13 +error: cannot find attribute `lt_enum` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:11:13 | -LL | fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } - | ^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B } + | ^^^^^^^ -error[E0658]: the attribute `ty_meth` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/feature-gate-custom_attribute2.rs:48:13 +error: cannot find attribute `ty_struct` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:8:15 | -LL | fn m_ty<#[ty_meth] P>(_: P) { } - | ^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | struct StTy<#[ty_struct] I>(I); + | ^^^^^^^^^ -error[E0658]: the attribute `lt_hof` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/feature-gate-custom_attribute2.rs:53:19 +error: cannot find attribute `lt_struct` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:6:15 | -LL | where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 - | ^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add `#![feature(custom_attribute)]` to the crate attributes to enable +LL | struct StLt<#[lt_struct] 'a>(&'a u32); + | ^^^^^^^^^ error: aborting due to 17 previous errors -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-doc_alias.rs b/src/test/ui/feature-gates/feature-gate-doc_alias.rs index adb6fc217a329..c95722102d9b6 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_alias.rs +++ b/src/test/ui/feature-gates/feature-gate-doc_alias.rs @@ -1,4 +1,4 @@ -#[doc(alias = "foo")] //~ ERROR: `#[doc(alias = "...")]` is experimental +#[doc(alias = "foo")] //~ ERROR: `#[doc(alias)]` is experimental pub struct Foo; fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-doc_alias.stderr b/src/test/ui/feature-gates/feature-gate-doc_alias.stderr index dddaa45de8ff8..540b1f5ccbe43 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_alias.stderr +++ b/src/test/ui/feature-gates/feature-gate-doc_alias.stderr @@ -1,4 +1,4 @@ -error[E0658]: `#[doc(alias = "...")]` is experimental +error[E0658]: `#[doc(alias)]` is experimental --> $DIR/feature-gate-doc_alias.rs:1:1 | LL | #[doc(alias = "foo")] diff --git a/src/test/ui/feature-gates/feature-gate-doc_cfg.rs b/src/test/ui/feature-gates/feature-gate-doc_cfg.rs index bb3846e7f6b55..b12b8a1057182 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_cfg.rs +++ b/src/test/ui/feature-gates/feature-gate-doc_cfg.rs @@ -1,2 +1,2 @@ -#[doc(cfg(unix))] //~ ERROR: `#[doc(cfg(...))]` is experimental +#[doc(cfg(unix))] //~ ERROR: `#[doc(cfg)]` is experimental fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr b/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr index 7b0a231df4c3e..eaa908d0037ae 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr +++ b/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr @@ -1,4 +1,4 @@ -error[E0658]: `#[doc(cfg(...))]` is experimental +error[E0658]: `#[doc(cfg)]` is experimental --> $DIR/feature-gate-doc_cfg.rs:1:1 | LL | #[doc(cfg(unix))] diff --git a/src/test/ui/feature-gates/feature-gate-doc_keyword.rs b/src/test/ui/feature-gates/feature-gate-doc_keyword.rs index 6cdcfa67c3a9b..4bb9a40deb0dd 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_keyword.rs +++ b/src/test/ui/feature-gates/feature-gate-doc_keyword.rs @@ -1,4 +1,4 @@ -#[doc(keyword = "match")] //~ ERROR: `#[doc(keyword = "...")]` is experimental +#[doc(keyword = "match")] //~ ERROR: `#[doc(keyword)]` is experimental /// wonderful mod foo{} diff --git a/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr b/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr index abde0bea9b230..15a41d9ffa4ea 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr +++ b/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr @@ -1,4 +1,4 @@ -error[E0658]: `#[doc(keyword = "...")]` is experimental +error[E0658]: `#[doc(keyword)]` is experimental --> $DIR/feature-gate-doc_keyword.rs:1:1 | LL | #[doc(keyword = "match")] diff --git a/src/test/ui/feature-gates/feature-gate-external_doc.rs b/src/test/ui/feature-gates/feature-gate-external_doc.rs index dec3fa185791c..9d68d3ec4f52a 100644 --- a/src/test/ui/feature-gates/feature-gate-external_doc.rs +++ b/src/test/ui/feature-gates/feature-gate-external_doc.rs @@ -1,2 +1,2 @@ -#[doc(include="asdf.md")] //~ ERROR: `#[doc(include = "...")]` is experimental +#[doc(include="asdf.md")] //~ ERROR: `#[doc(include)]` is experimental fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-external_doc.stderr b/src/test/ui/feature-gates/feature-gate-external_doc.stderr index a5a874374d1eb..683c0ad217426 100644 --- a/src/test/ui/feature-gates/feature-gate-external_doc.stderr +++ b/src/test/ui/feature-gates/feature-gate-external_doc.stderr @@ -1,4 +1,4 @@ -error[E0658]: `#[doc(include = "...")]` is experimental +error[E0658]: `#[doc(include)]` is experimental --> $DIR/feature-gate-external_doc.rs:1:1 | LL | #[doc(include="asdf.md")] diff --git a/src/test/ui/feature-gates/feature-gate-generators.rs b/src/test/ui/feature-gates/feature-gate-generators.rs index cee930fd785b9..382d891feed84 100644 --- a/src/test/ui/feature-gates/feature-gate-generators.rs +++ b/src/test/ui/feature-gates/feature-gate-generators.rs @@ -2,3 +2,9 @@ fn main() { yield true; //~ ERROR yield syntax is experimental //~^ ERROR yield statement outside of generator literal } + +#[cfg(FALSE)] +fn foo() { + yield; //~ ERROR yield syntax is experimental + yield 0; //~ ERROR yield syntax is experimental +} diff --git a/src/test/ui/feature-gates/feature-gate-generators.stderr b/src/test/ui/feature-gates/feature-gate-generators.stderr index cdb056012542b..24b814b410c9d 100644 --- a/src/test/ui/feature-gates/feature-gate-generators.stderr +++ b/src/test/ui/feature-gates/feature-gate-generators.stderr @@ -7,12 +7,30 @@ LL | yield true; = note: for more information, see https://github.com/rust-lang/rust/issues/43122 = help: add `#![feature(generators)]` to the crate attributes to enable +error[E0658]: yield syntax is experimental + --> $DIR/feature-gate-generators.rs:8:5 + | +LL | yield; + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/43122 + = help: add `#![feature(generators)]` to the crate attributes to enable + +error[E0658]: yield syntax is experimental + --> $DIR/feature-gate-generators.rs:9:5 + | +LL | yield 0; + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/43122 + = help: add `#![feature(generators)]` to the crate attributes to enable + error[E0627]: yield statement outside of generator literal --> $DIR/feature-gate-generators.rs:2:5 | LL | yield true; | ^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-intrinsics.rs b/src/test/ui/feature-gates/feature-gate-intrinsics.rs index d1da94338283b..e0dc3cc579d79 100644 --- a/src/test/ui/feature-gates/feature-gate-intrinsics.rs +++ b/src/test/ui/feature-gates/feature-gate-intrinsics.rs @@ -3,5 +3,6 @@ extern "rust-intrinsic" { //~ ERROR intrinsics are subject to change } extern "rust-intrinsic" fn baz() {} //~ ERROR intrinsics are subject to change +//~^ ERROR intrinsic must be in fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-intrinsics.stderr b/src/test/ui/feature-gates/feature-gate-intrinsics.stderr index 09843f05af1b9..101a10e8df71f 100644 --- a/src/test/ui/feature-gates/feature-gate-intrinsics.stderr +++ b/src/test/ui/feature-gates/feature-gate-intrinsics.stderr @@ -22,7 +22,13 @@ error[E0093]: unrecognized intrinsic function: `bar` LL | fn bar(); | ^^^^^^^^^ unrecognized intrinsic -error: aborting due to 3 previous errors +error: intrinsic must be in `extern "rust-intrinsic" { ... }` block + --> $DIR/feature-gate-intrinsics.rs:5:34 + | +LL | extern "rust-intrinsic" fn baz() {} + | ^^ + +error: aborting due to 4 previous errors Some errors have detailed explanations: E0093, E0658. For more information about an error, try `rustc --explain E0093`. diff --git a/src/test/ui/feature-gates/feature-gate-is_sorted.rs b/src/test/ui/feature-gates/feature-gate-is_sorted.rs index 078ecc577610b..359ed835bcbb2 100644 --- a/src/test/ui/feature-gates/feature-gate-is_sorted.rs +++ b/src/test/ui/feature-gates/feature-gate-is_sorted.rs @@ -1,11 +1,11 @@ fn main() { - // Assert `Iterator` methods are feature gated + // Assert `Iterator` methods are unstable assert!([1, 2, 2, 9].iter().is_sorted()); //~^ ERROR: use of unstable library feature 'is_sorted': new API assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs())); //~^ ERROR: use of unstable library feature 'is_sorted': new API - // Assert `[T]` methods are feature gated + // Assert `[T]` methods are unstable assert!([1, 2, 2, 9].is_sorted()); //~^ ERROR: use of unstable library feature 'is_sorted': new API assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); diff --git a/src/test/ui/feature-gates/feature-gate-link_cfg.rs b/src/test/ui/feature-gates/feature-gate-link_cfg.rs index 1905346e2b5d7..27ec2e98eb68b 100644 --- a/src/test/ui/feature-gates/feature-gate-link_cfg.rs +++ b/src/test/ui/feature-gates/feature-gate-link_cfg.rs @@ -1,5 +1,5 @@ #[link(name = "foo", cfg(foo))] -//~^ ERROR: is feature gated +//~^ ERROR: is unstable extern {} fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-link_cfg.stderr b/src/test/ui/feature-gates/feature-gate-link_cfg.stderr index 58aa4ed7497ce..f6c5061546438 100644 --- a/src/test/ui/feature-gates/feature-gate-link_cfg.stderr +++ b/src/test/ui/feature-gates/feature-gate-link_cfg.stderr @@ -1,4 +1,4 @@ -error[E0658]: is feature gated +error[E0658]: is unstable --> $DIR/feature-gate-link_cfg.rs:1:1 | LL | #[link(name = "foo", cfg(foo))] diff --git a/src/test/ui/feature-gates/feature-gate-macros_in_extern.rs b/src/test/ui/feature-gates/feature-gate-macros_in_extern.rs deleted file mode 100644 index 125af64fef05c..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-macros_in_extern.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![feature(decl_macro)] - -macro_rules! returns_isize( - ($ident:ident) => ( - fn $ident() -> isize; - ) -); - -macro takes_u32_returns_u32($ident:ident) { - fn $ident (arg: u32) -> u32; -} - -macro_rules! emits_nothing( - () => () -); - -#[link(name = "rust_test_helpers", kind = "static")] -extern { - returns_isize!(rust_get_test_int); - //~^ ERROR macro invocations in `extern {}` blocks are experimental - takes_u32_returns_u32!(rust_dbg_extern_identity_u32); - //~^ ERROR macro invocations in `extern {}` blocks are experimental - emits_nothing!(); - //~^ ERROR macro invocations in `extern {}` blocks are experimental -} - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr b/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr deleted file mode 100644 index e8b3ab5dda20d..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/feature-gate-macros_in_extern.rs:19:5 - | -LL | returns_isize!(rust_get_test_int); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/feature-gate-macros_in_extern.rs:21:5 - | -LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/feature-gate-macros_in_extern.rs:23:5 - | -LL | emits_nothing!(); - | ^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs index ea06c775b1a60..5050c4792b064 100644 --- a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs +++ b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs @@ -1,7 +1,7 @@ use std::fmt::{Debug, Display}; #[marker] trait ExplicitMarker {} -//~^ ERROR marker traits is an experimental feature +//~^ ERROR the `#[marker]` attribute is an experimental feature impl ExplicitMarker for T {} impl ExplicitMarker for T {} diff --git a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr index 94dfaf9206d14..304c081c5aace 100644 --- a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr +++ b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr @@ -1,4 +1,4 @@ -error[E0658]: marker traits is an experimental feature +error[E0658]: the `#[marker]` attribute is an experimental feature --> $DIR/feature-gate-marker_trait_attr.rs:3:1 | LL | #[marker] trait ExplicitMarker {} diff --git a/src/test/ui/feature-gates/feature-gate-nll.rs b/src/test/ui/feature-gates/feature-gate-nll.rs index 8ec752409ab00..fd6c5b67ef69e 100644 --- a/src/test/ui/feature-gates/feature-gate-nll.rs +++ b/src/test/ui/feature-gates/feature-gate-nll.rs @@ -1,20 +1,18 @@ // There isn't a great way to test feature(nll), since it just disables migrate -// mode and changes some error messages. We just test for migrate mode. +// mode and changes some error messages. + +// FIXME(Centril): This test is probably obsolete now and `nll` should become +// `accepted`. // Don't use compare-mode=nll, since that turns on NLL. // ignore-compare-mode-nll // ignore-compare-mode-polonius -#![feature(rustc_attrs)] - -#[rustc_error] -fn main() { //~ ERROR compilation successful +fn main() { let mut x = (33, &0); let m = &mut x; let p = &*x.1; - //~^ WARNING cannot borrow - //~| WARNING this error has been downgraded to a warning - //~| WARNING this warning will become a hard error in the future + //~^ ERROR cannot borrow m; } diff --git a/src/test/ui/feature-gates/feature-gate-nll.stderr b/src/test/ui/feature-gates/feature-gate-nll.stderr index e5b28bbfa2477..edfc22c32c936 100644 --- a/src/test/ui/feature-gates/feature-gate-nll.stderr +++ b/src/test/ui/feature-gates/feature-gate-nll.stderr @@ -1,29 +1,13 @@ -warning[E0502]: cannot borrow `*x.1` as immutable because it is also borrowed as mutable +error[E0502]: cannot borrow `*x.1` as immutable because it is also borrowed as mutable --> $DIR/feature-gate-nll.rs:15:13 | LL | let m = &mut x; | ------ mutable borrow occurs here LL | let p = &*x.1; | ^^^^^ immutable borrow occurs here -... +LL | LL | m; | - mutable borrow later used here - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future - = note: for more information, try `rustc --explain E0729` - -error: compilation successful - --> $DIR/feature-gate-nll.rs:11:1 - | -LL | / fn main() { -LL | | let mut x = (33, &0); -LL | | -LL | | let m = &mut x; -... | -LL | | m; -LL | | } - | |_^ error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-no_core.rs b/src/test/ui/feature-gates/feature-gate-no_core.rs index 40178edd74b8d..706efd7867211 100644 --- a/src/test/ui/feature-gates/feature-gate-no_core.rs +++ b/src/test/ui/feature-gates/feature-gate-no_core.rs @@ -1,5 +1,5 @@ #![crate_type = "rlib"] -#![no_core] //~ ERROR no_core is experimental +#![no_core] //~ ERROR the `#[no_core]` attribute is an experimental feature pub struct S {} diff --git a/src/test/ui/feature-gates/feature-gate-no_core.stderr b/src/test/ui/feature-gates/feature-gate-no_core.stderr index 4d4ca96544e56..a80b3cbba25b1 100644 --- a/src/test/ui/feature-gates/feature-gate-no_core.stderr +++ b/src/test/ui/feature-gates/feature-gate-no_core.stderr @@ -1,4 +1,4 @@ -error[E0658]: no_core is experimental +error[E0658]: the `#[no_core]` attribute is an experimental feature --> $DIR/feature-gate-no_core.rs:3:1 | LL | #![no_core] diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs b/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs index aca214d1935e2..950f170f4fd41 100644 --- a/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs +++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs @@ -1,6 +1,6 @@ //#![feature(non_exhaustive)] -#[non_exhaustive] //~ERROR non exhaustive is an experimental feature +#[non_exhaustive] //~ERROR the `#[non_exhaustive]` attribute is an experimental feature pub enum NonExhaustiveEnum { Unit, Tuple(u32), diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr b/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr index 8a01aa9eb6a9a..482332b8d706c 100644 --- a/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr +++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr @@ -1,4 +1,4 @@ -error[E0658]: non exhaustive is an experimental feature +error[E0658]: the `#[non_exhaustive]` attribute is an experimental feature --> $DIR/feature-gate-non_exhaustive.rs:3:1 | LL | #[non_exhaustive] diff --git a/src/test/ui/feature-gates/feature-gate-plugin.rs b/src/test/ui/feature-gates/feature-gate-plugin.rs index 977a5556899ba..8904ec0448ada 100644 --- a/src/test/ui/feature-gates/feature-gate-plugin.rs +++ b/src/test/ui/feature-gates/feature-gate-plugin.rs @@ -1,6 +1,7 @@ // Test that `#![plugin(...)]` attribute is gated by `plugin` feature gate #![plugin(foo)] -//~^ ERROR compiler plugins are experimental and possibly buggy +//~^ ERROR compiler plugins are deprecated +//~| WARN use of deprecated attribute `plugin`: compiler plugins are deprecated fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-plugin.stderr b/src/test/ui/feature-gates/feature-gate-plugin.stderr index 0da9653c9af73..d1eee8cc58895 100644 --- a/src/test/ui/feature-gates/feature-gate-plugin.stderr +++ b/src/test/ui/feature-gates/feature-gate-plugin.stderr @@ -1,4 +1,4 @@ -error[E0658]: compiler plugins are experimental and possibly buggy +error[E0658]: compiler plugins are deprecated --> $DIR/feature-gate-plugin.rs:3:1 | LL | #![plugin(foo)] @@ -7,6 +7,14 @@ LL | #![plugin(foo)] = note: for more information, see https://github.com/rust-lang/rust/issues/29597 = help: add `#![feature(plugin)]` to the crate attributes to enable +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/feature-gate-plugin.rs:3:1 + | +LL | #![plugin(foo)] + | ^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + error: aborting due to previous error For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-plugin_registrar.rs b/src/test/ui/feature-gates/feature-gate-plugin_registrar.rs index 0e357f89d14a6..80e4aa76b4771 100644 --- a/src/test/ui/feature-gates/feature-gate-plugin_registrar.rs +++ b/src/test/ui/feature-gates/feature-gate-plugin_registrar.rs @@ -3,6 +3,9 @@ // the registration function isn't typechecked yet #[plugin_registrar] +//~^ ERROR compiler plugins are deprecated +//~| WARN use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated pub fn registrar() {} -//~^ ERROR compiler plugins are experimental +//~^ ERROR compiler plugins are experimental and possibly buggy + fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-plugin_registrar.stderr b/src/test/ui/feature-gates/feature-gate-plugin_registrar.stderr index 93473bfd27b45..1c4ccac1dcffb 100644 --- a/src/test/ui/feature-gates/feature-gate-plugin_registrar.stderr +++ b/src/test/ui/feature-gates/feature-gate-plugin_registrar.stderr @@ -1,5 +1,5 @@ error[E0658]: compiler plugins are experimental and possibly buggy - --> $DIR/feature-gate-plugin_registrar.rs:6:1 + --> $DIR/feature-gate-plugin_registrar.rs:8:1 | LL | pub fn registrar() {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -7,6 +7,23 @@ LL | pub fn registrar() {} = note: for more information, see https://github.com/rust-lang/rust/issues/29597 = help: add `#![feature(plugin_registrar)]` to the crate attributes to enable -error: aborting due to previous error +error[E0658]: compiler plugins are deprecated + --> $DIR/feature-gate-plugin_registrar.rs:5:1 + | +LL | #[plugin_registrar] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29597 + = help: add `#![feature(plugin_registrar)]` to the crate attributes to enable + +warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597 + --> $DIR/feature-gate-plugin_registrar.rs:5:1 + | +LL | #[plugin_registrar] + | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[warn(deprecated)]` on by default + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-repr-simd.stderr b/src/test/ui/feature-gates/feature-gate-repr-simd.stderr index dfaa85bc5f014..02c8400e03e82 100644 --- a/src/test/ui/feature-gates/feature-gate-repr-simd.stderr +++ b/src/test/ui/feature-gates/feature-gate-repr-simd.stderr @@ -26,4 +26,5 @@ LL | #[repr(simd)] error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0566, E0658. +For more information about an error, try `rustc --explain E0566`. diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs b/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs index 13983726c78de..c985298a30aed 100644 --- a/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs +++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs @@ -16,8 +16,8 @@ fn f() {} fn g() {} #[rustc_dummy] -//~^ ERROR used by the test suite +//~^ ERROR the `#[rustc_dummy]` attribute is just used for rustc unit tests #[rustc_unknown] //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler -//~| ERROR cannot find attribute macro `rustc_unknown` in this scope +//~| ERROR cannot find attribute `rustc_unknown` in this scope fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr index 23cf936ee8350..d6fdab2b0412d 100644 --- a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr +++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr @@ -37,13 +37,13 @@ LL | #[rustc_unknown] = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable -error: cannot find attribute macro `rustc_unknown` in this scope +error: cannot find attribute `rustc_unknown` in this scope --> $DIR/feature-gate-rustc-attrs.rs:20:3 | LL | #[rustc_unknown] | ^^^^^^^^^^^^^ -error[E0658]: used by the test suite +error[E0658]: the `#[rustc_dummy]` attribute is just used for rustc unit tests and will never be stable --> $DIR/feature-gate-rustc-attrs.rs:18:1 | LL | #[rustc_dummy] diff --git a/src/test/ui/feature-gates/feature-gate-rustc-diagnostic-macros.rs b/src/test/ui/feature-gates/feature-gate-rustc-diagnostic-macros.rs deleted file mode 100644 index 63c2c31fd30e6..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-rustc-diagnostic-macros.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Test that diagnostic macros are gated by `rustc_diagnostic_macros` feature -// gate - -__register_diagnostic!(E0001); -//~^ ERROR cannot find macro `__register_diagnostic!` in this scope - -fn main() { - __diagnostic_used!(E0001); - //~^ ERROR cannot find macro `__diagnostic_used!` in this scope -} - -__build_diagnostic_array!(DIAGNOSTICS); -//~^ ERROR cannot find macro `__build_diagnostic_array!` in this scope diff --git a/src/test/ui/feature-gates/feature-gate-rustc-diagnostic-macros.stderr b/src/test/ui/feature-gates/feature-gate-rustc-diagnostic-macros.stderr deleted file mode 100644 index 478bc09f29192..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-rustc-diagnostic-macros.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: cannot find macro `__build_diagnostic_array!` in this scope - --> $DIR/feature-gate-rustc-diagnostic-macros.rs:12:1 - | -LL | __build_diagnostic_array!(DIAGNOSTICS); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: cannot find macro `__register_diagnostic!` in this scope - --> $DIR/feature-gate-rustc-diagnostic-macros.rs:4:1 - | -LL | __register_diagnostic!(E0001); - | ^^^^^^^^^^^^^^^^^^^^^ - -error: cannot find macro `__diagnostic_used!` in this scope - --> $DIR/feature-gate-rustc-diagnostic-macros.rs:8:5 - | -LL | __diagnostic_used!(E0001); - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors - diff --git a/src/test/ui/feature-gates/feature-gate-staged_api.stderr b/src/test/ui/feature-gates/feature-gate-staged_api.stderr index f0db47fe8a875..a71d26ce16f5b 100644 --- a/src/test/ui/feature-gates/feature-gate-staged_api.stderr +++ b/src/test/ui/feature-gates/feature-gate-staged_api.stderr @@ -1,10 +1,10 @@ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/feature-gate-staged_api.rs:1:1 | LL | #![stable(feature = "a", since = "b")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: stability attributes may not be used outside of the standard library +error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/feature-gate-staged_api.rs:8:1 | LL | #[stable(feature = "a", since = "b")] @@ -12,3 +12,4 @@ LL | #[stable(feature = "a", since = "b")] error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0734`. diff --git a/src/test/ui/feature-gates/feature-gate-static-nobundle.rs b/src/test/ui/feature-gates/feature-gate-static-nobundle.rs index 1ce6c54aa4dc2..644b1f964a059 100644 --- a/src/test/ui/feature-gates/feature-gate-static-nobundle.rs +++ b/src/test/ui/feature-gates/feature-gate-static-nobundle.rs @@ -1,5 +1,5 @@ #[link(name="foo", kind="static-nobundle")] -//~^ ERROR: kind="static-nobundle" is feature gated +//~^ ERROR: kind="static-nobundle" is unstable extern {} fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr b/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr index f2e29cf0678ae..cc0d426d6cf9a 100644 --- a/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr +++ b/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr @@ -1,4 +1,4 @@ -error[E0658]: kind="static-nobundle" is feature gated +error[E0658]: kind="static-nobundle" is unstable --> $DIR/feature-gate-static-nobundle.rs:1:1 | LL | #[link(name="foo", kind="static-nobundle")] diff --git a/src/test/ui/feature-gates/feature-gate-track_caller.rs b/src/test/ui/feature-gates/feature-gate-track_caller.rs new file mode 100644 index 0000000000000..5865cf0a4f754 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-track_caller.rs @@ -0,0 +1,5 @@ +#[track_caller] +fn f() {} +//~^^ ERROR the `#[track_caller]` attribute is an experimental feature + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-track_caller.stderr b/src/test/ui/feature-gates/feature-gate-track_caller.stderr new file mode 100644 index 0000000000000..b890019ee4f3c --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-track_caller.stderr @@ -0,0 +1,12 @@ +error[E0658]: the `#[track_caller]` attribute is an experimental feature + --> $DIR/feature-gate-track_caller.rs:1:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/47809 + = help: add `#![feature(track_caller)]` 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-gates/feature-gate-type_ascription.rs b/src/test/ui/feature-gates/feature-gate-type_ascription.rs index e42e340550681..7a597157300ed 100644 --- a/src/test/ui/feature-gates/feature-gate-type_ascription.rs +++ b/src/test/ui/feature-gates/feature-gate-type_ascription.rs @@ -1,4 +1,4 @@ -// Type ascription is feature gated +// Type ascription is unstable fn main() { let a = 10: u8; //~ ERROR type ascription is experimental diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr index fc4317b316a37..c05379c71eeaf 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr @@ -44,10 +44,10 @@ LL | impl Fn<()> for Foo { = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0229]: associated type bindings are not allowed here - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:15:12 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:15:6 | LL | impl FnOnce() for Foo1 { - | ^^ associated type not allowed here + | ^^^^^^^^ associated type not allowed here error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:21:6 diff --git a/src/test/ui/feature-gates/feature-gate-unwind-attributes.rs b/src/test/ui/feature-gates/feature-gate-unwind-attributes.rs index 08e8ec9a56e51..6d8ac7e8f2911 100644 --- a/src/test/ui/feature-gates/feature-gate-unwind-attributes.rs +++ b/src/test/ui/feature-gates/feature-gate-unwind-attributes.rs @@ -8,7 +8,7 @@ extern { fn extern_fn(); // CHECK-NOT: Function Attrs: nounwind // CHECK: declare void @unwinding_extern_fn - #[unwind(allowed)] //~ ERROR `#[unwind]` is experimental + #[unwind(allowed)] //~ ERROR the `#[unwind]` attribute is an experimental feature fn unwinding_extern_fn(); } diff --git a/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr b/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr index 639b87e016214..10cc494213507 100644 --- a/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr +++ b/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr @@ -1,4 +1,4 @@ -error[E0658]: `#[unwind]` is experimental +error[E0658]: the `#[unwind]` attribute is an experimental feature --> $DIR/feature-gate-unwind-attributes.rs:11:5 | LL | #[unwind(allowed)] diff --git a/src/test/ui/fmt/send-sync.stderr b/src/test/ui/fmt/send-sync.stderr index 1f698c90cb9a4..be6e41afaf811 100644 --- a/src/test/ui/fmt/send-sync.stderr +++ b/src/test/ui/fmt/send-sync.stderr @@ -1,6 +1,9 @@ error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely --> $DIR/send-sync.rs:8:5 | +LL | fn send(_: T) {} + | ---- ---- required by this bound in `send` +... LL | send(format_args!("{:?}", c)); | ^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely | @@ -12,15 +15,13 @@ LL | send(format_args!("{:?}", c)); = note: required because it appears within the type `[std::fmt::ArgumentV1<'_>]` = note: required because of the requirements on the impl of `std::marker::Send` for `&[std::fmt::ArgumentV1<'_>]` = note: required because it appears within the type `std::fmt::Arguments<'_>` -note: required by `send` - --> $DIR/send-sync.rs:1:1 - | -LL | fn send(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely --> $DIR/send-sync.rs:9:5 | +LL | fn sync(_: T) {} + | ---- ---- required by this bound in `sync` +... LL | sync(format_args!("{:?}", c)); | ^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely | @@ -32,11 +33,6 @@ LL | sync(format_args!("{:?}", c)); = note: required because it appears within the type `[std::fmt::ArgumentV1<'_>]` = note: required because it appears within the type `&[std::fmt::ArgumentV1<'_>]` = note: required because it appears within the type `std::fmt::Arguments<'_>` -note: required by `sync` - --> $DIR/send-sync.rs:2:1 - | -LL | fn sync(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/fn/fn-trait-formatting.stderr b/src/test/ui/fn/fn-trait-formatting.stderr index 504bc2605ec38..f891b9c6439be 100644 --- a/src/test/ui/fn/fn-trait-formatting.stderr +++ b/src/test/ui/fn/fn-trait-formatting.stderr @@ -26,17 +26,15 @@ LL | let _: () = (box || -> isize { unimplemented!() }) as Box isize>` error[E0277]: expected a `std::ops::Fn<(isize,)>` closure, found `{integer}` - --> $DIR/fn-trait-formatting.rs:19:5 + --> $DIR/fn-trait-formatting.rs:19:14 | +LL | fn needs_fn(x: F) where F: Fn(isize) -> isize {} + | -------- ------------------ required by this bound in `needs_fn` +... LL | needs_fn(1); - | ^^^^^^^^ expected an `Fn<(isize,)>` closure, found `{integer}` + | ^ expected an `Fn<(isize,)>` closure, found `{integer}` | = help: the trait `std::ops::Fn<(isize,)>` is not implemented for `{integer}` -note: required by `needs_fn` - --> $DIR/fn-trait-formatting.rs:3:1 - | -LL | fn needs_fn(x: F) where F: Fn(isize) -> isize {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/for/for-c-in-str.rs b/src/test/ui/for/for-c-in-str.rs index 43b1a04c22d04..1871cf9d2386e 100644 --- a/src/test/ui/for/for-c-in-str.rs +++ b/src/test/ui/for/for-c-in-str.rs @@ -6,6 +6,9 @@ fn main() { //~| NOTE `&str` is not an iterator //~| HELP the trait `std::iter::Iterator` is not implemented for `&str` //~| NOTE required by `std::iter::IntoIterator::into_iter` - println!(""); + //~| NOTE in this expansion of desugaring of `for` loop + //~| NOTE in this expansion of desugaring of `for` loop + //~| NOTE in this expansion of desugaring of `for` loop + println!(); } } diff --git a/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr b/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr index 0d77fd4efdb82..14aea2dc27eea 100644 --- a/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr +++ b/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr @@ -1,8 +1,8 @@ -error[E0005]: refutable pattern in `for` loop binding: `&std::i32::MIN..=0i32` not covered +error[E0005]: refutable pattern in `for` loop binding: `&std::i32::MIN..=0i32` and `&2i32..=std::i32::MAX` not covered --> $DIR/for-loop-refutable-pattern-error-message.rs:2:9 | LL | for &1 in [1].iter() {} - | ^^ pattern `&std::i32::MIN..=0i32` not covered + | ^^ patterns `&std::i32::MIN..=0i32` and `&2i32..=std::i32::MAX` not covered error: aborting due to previous error diff --git a/src/test/ui/for/for-loop-unconstrained-element-type.stderr b/src/test/ui/for/for-loop-unconstrained-element-type.stderr index 02fdb808da449..0672014a92929 100644 --- a/src/test/ui/for/for-loop-unconstrained-element-type.stderr +++ b/src/test/ui/for/for-loop-unconstrained-element-type.stderr @@ -2,10 +2,7 @@ error[E0282]: type annotations needed --> $DIR/for-loop-unconstrained-element-type.rs:8:14 | LL | for i in Vec::new() { } - | ^^^^^^^^^^ - | | - | cannot infer type - | the element type for this iterator is not specified + | ^^^^^^^^^^ the element type for this iterator is not specified error: aborting due to previous error diff --git a/src/test/ui/format-hygiene.rs b/src/test/ui/format-hygiene.rs deleted file mode 100644 index 6bf5ae8beaddb..0000000000000 --- a/src/test/ui/format-hygiene.rs +++ /dev/null @@ -1,8 +0,0 @@ -// run-pass - -#![allow(non_upper_case_globals)] -pub const arg0: u8 = 1; - -pub fn main() { - format!("{}", 1); -} diff --git a/src/test/ui/gated-bad-feature.stderr b/src/test/ui/gated-bad-feature.stderr index ff6780e66a8ce..79e59f76311fd 100644 --- a/src/test/ui/gated-bad-feature.stderr +++ b/src/test/ui/gated-bad-feature.stderr @@ -30,4 +30,5 @@ LL | #![feature = "foo"] error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0557`. +Some errors have detailed explanations: E0556, E0557. +For more information about an error, try `rustc --explain E0556`. diff --git a/src/test/ui/generator-yielding-or-returning-itself.stderr b/src/test/ui/generator-yielding-or-returning-itself.stderr index 42591683fe4e3..c9a71e03858f1 100644 --- a/src/test/ui/generator-yielding-or-returning-itself.stderr +++ b/src/test/ui/generator-yielding-or-returning-itself.stderr @@ -16,20 +16,17 @@ LL | | }) error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _] as std::ops::Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _]` --> $DIR/generator-yielding-or-returning-itself.rs:28:5 | +LL | pub fn want_cyclic_generator_yield(_: T) + | --------------------------- +LL | where T: Generator + | --------- required by this bound in `want_cyclic_generator_yield` +... LL | want_cyclic_generator_yield(|| { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size | = note: closures cannot capture themselves or take themselves as argument; this error may be the result of a recent compiler bug-fix, see https://github.com/rust-lang/rust/issues/46062 for more details -note: required by `want_cyclic_generator_yield` - --> $DIR/generator-yielding-or-returning-itself.rs:22:1 - | -LL | / pub fn want_cyclic_generator_yield(_: T) -LL | | where T: Generator -LL | | { -LL | | } - | |_^ error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/auto-trait-regions.stderr b/src/test/ui/generator/auto-trait-regions.stderr index 92f92e2a32a36..dab4d348ceb60 100644 --- a/src/test/ui/generator/auto-trait-regions.stderr +++ b/src/test/ui/generator/auto-trait-regions.stderr @@ -1,20 +1,26 @@ error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:30:5 | +LL | auto trait Foo {} + | ----------------- trait `Foo` defined here +... LL | assert_foo(gen); - | ^^^^^^^^^^ + | ^^^^^^^^^^ implementation of `Foo` is not general enough | - = note: `Foo` would have to be implemented for the type `&'0 OnlyFooIfStaticRef`, for any lifetime `'0` - = note: but `Foo` is actually implemented for the type `&'1 OnlyFooIfStaticRef`, for some specific lifetime `'1` + = note: `Foo` would have to be implemented for the type `&'0 OnlyFooIfStaticRef`, for any lifetime `'0`... + = note: ...but `Foo` is actually implemented for the type `&'1 OnlyFooIfStaticRef`, for some specific lifetime `'1` error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:48:5 | +LL | auto trait Foo {} + | ----------------- trait `Foo` defined here +... LL | assert_foo(gen); - | ^^^^^^^^^^ + | ^^^^^^^^^^ implementation of `Foo` is not general enough | - = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1` - = note: but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2` + = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2` error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/issue-61442-stmt-expr-with-drop.rs b/src/test/ui/generator/issue-61442-stmt-expr-with-drop.rs index ce4642020f0f1..e3d19029348a5 100644 --- a/src/test/ui/generator/issue-61442-stmt-expr-with-drop.rs +++ b/src/test/ui/generator/issue-61442-stmt-expr-with-drop.rs @@ -4,7 +4,7 @@ // check-pass // edition:2018 -#![feature(async_await, generators, generator_trait)] +#![feature(generators, generator_trait)] use std::ops::Generator; diff --git a/src/test/ui/generator/issue-62506-two_awaits.rs b/src/test/ui/generator/issue-62506-two_awaits.rs index 774019b6a5bda..672e16b780d03 100644 --- a/src/test/ui/generator/issue-62506-two_awaits.rs +++ b/src/test/ui/generator/issue-62506-two_awaits.rs @@ -4,7 +4,6 @@ // check-pass // edition:2018 -#![feature(async_await)] use std::future::Future; pub trait T { diff --git a/src/test/run-pass/generator/niche-in-generator.rs b/src/test/ui/generator/niche-in-generator.rs similarity index 95% rename from src/test/run-pass/generator/niche-in-generator.rs rename to src/test/ui/generator/niche-in-generator.rs index 9a644ed44a670..42bee81f524c5 100644 --- a/src/test/run-pass/generator/niche-in-generator.rs +++ b/src/test/ui/generator/niche-in-generator.rs @@ -1,5 +1,7 @@ // Test that niche finding works with captured generator upvars. +// run-pass + #![feature(generators)] use std::mem::size_of_val; diff --git a/src/test/ui/generator/no-arguments-on-generators.stderr b/src/test/ui/generator/no-arguments-on-generators.stderr deleted file mode 100644 index 23ae21585fd38..0000000000000 --- a/src/test/ui/generator/no-arguments-on-generators.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error[E0628]: generators cannot have explicit arguments - --> $DIR/no-arguments-on-generators.rs:4:15 - | -LL | let gen = |start| { - | ^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/generator/no-arguments-on-generators.rs b/src/test/ui/generator/no-parameters-on-generators.rs similarity index 59% rename from src/test/ui/generator/no-arguments-on-generators.rs rename to src/test/ui/generator/no-parameters-on-generators.rs index 344c1179be90e..6b5a557933953 100644 --- a/src/test/ui/generator/no-arguments-on-generators.rs +++ b/src/test/ui/generator/no-parameters-on-generators.rs @@ -1,7 +1,8 @@ #![feature(generators)] fn main() { - let gen = |start| { //~ ERROR generators cannot have explicit arguments + let gen = |start| { //~ ERROR generators cannot have explicit parameters + //~^ ERROR type inside generator must be known in this context yield; }; } diff --git a/src/test/ui/generator/no-parameters-on-generators.stderr b/src/test/ui/generator/no-parameters-on-generators.stderr new file mode 100644 index 0000000000000..5e8e043a391ce --- /dev/null +++ b/src/test/ui/generator/no-parameters-on-generators.stderr @@ -0,0 +1,21 @@ +error[E0628]: generators cannot have explicit parameters + --> $DIR/no-parameters-on-generators.rs:4:15 + | +LL | let gen = |start| { + | ^^^^^^^ + +error[E0698]: type inside generator must be known in this context + --> $DIR/no-parameters-on-generators.rs:4:16 + | +LL | let gen = |start| { + | ^^^^^ cannot infer type + | +note: the type is part of the generator because of this `yield` + --> $DIR/no-parameters-on-generators.rs:6:9 + | +LL | yield; + | ^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0698`. diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr index 7ea9832c99a24..620db245d3e57 100644 --- a/src/test/ui/generator/not-send-sync.stderr +++ b/src/test/ui/generator/not-send-sync.stderr @@ -1,32 +1,28 @@ error[E0277]: `std::cell::Cell` cannot be shared between threads safely --> $DIR/not-send-sync.rs:16:5 | +LL | fn assert_send(_: T) {} + | ----------- ---- required by this bound in `main::assert_send` +... LL | assert_send(|| { | ^^^^^^^^^^^ `std::cell::Cell` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `std::cell::Cell` = note: required because of the requirements on the impl of `std::marker::Send` for `&std::cell::Cell` = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6 a:&std::cell::Cell _]` -note: required by `main::assert_send` - --> $DIR/not-send-sync.rs:7:5 - | -LL | fn assert_send(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `std::cell::Cell` cannot be shared between threads safely --> $DIR/not-send-sync.rs:9:5 | +LL | fn assert_sync(_: T) {} + | ----------- ---- required by this bound in `main::assert_sync` +... LL | assert_sync(|| { | ^^^^^^^^^^^ `std::cell::Cell` cannot be shared between threads safely | = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell, ()}]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell` = note: required because it appears within the type `{std::cell::Cell, ()}` = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell, ()}]` -note: required by `main::assert_sync` - --> $DIR/not-send-sync.rs:6:5 - | -LL | fn assert_sync(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/partial-initialization-across-yield.rs b/src/test/ui/generator/partial-initialization-across-yield.rs index 1e4593002cb9a..8b75721420351 100644 --- a/src/test/ui/generator/partial-initialization-across-yield.rs +++ b/src/test/ui/generator/partial-initialization-across-yield.rs @@ -10,7 +10,7 @@ fn test_tuple() { let _ = || { let mut t: (i32, i32); t.0 = 42; - //~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381] + //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] yield; t.1 = 88; let _ = t; @@ -21,7 +21,7 @@ fn test_tuple_struct() { let _ = || { let mut t: T; t.0 = 42; - //~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381] + //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] yield; t.1 = 88; let _ = t; @@ -32,7 +32,7 @@ fn test_struct() { let _ = || { let mut t: S; t.x = 42; - //~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381] + //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] yield; t.y = 88; let _ = t; diff --git a/src/test/ui/generator/partial-initialization-across-yield.stderr b/src/test/ui/generator/partial-initialization-across-yield.stderr index 8bf0037e07009..66b86488eaec7 100644 --- a/src/test/ui/generator/partial-initialization-across-yield.stderr +++ b/src/test/ui/generator/partial-initialization-across-yield.stderr @@ -1,20 +1,20 @@ -error[E0381]: assign to part of possibly uninitialized variable: `t` +error[E0381]: assign to part of possibly-uninitialized variable: `t` --> $DIR/partial-initialization-across-yield.rs:12:9 | LL | t.0 = 42; - | ^^^^^^^^ use of possibly uninitialized `t` + | ^^^^^^^^ use of possibly-uninitialized `t` -error[E0381]: assign to part of possibly uninitialized variable: `t` +error[E0381]: assign to part of possibly-uninitialized variable: `t` --> $DIR/partial-initialization-across-yield.rs:23:9 | LL | t.0 = 42; - | ^^^^^^^^ use of possibly uninitialized `t` + | ^^^^^^^^ use of possibly-uninitialized `t` -error[E0381]: assign to part of possibly uninitialized variable: `t` +error[E0381]: assign to part of possibly-uninitialized variable: `t` --> $DIR/partial-initialization-across-yield.rs:34:9 | LL | t.x = 42; - | ^^^^^^^^ use of possibly uninitialized `t` + | ^^^^^^^^ use of possibly-uninitialized `t` error: aborting due to 3 previous errors diff --git a/src/test/ui/generator/ref-escapes-but-not-over-yield.polonius.stderr b/src/test/ui/generator/ref-escapes-but-not-over-yield.polonius.stderr deleted file mode 100644 index 530bf368f676e..0000000000000 --- a/src/test/ui/generator/ref-escapes-but-not-over-yield.polonius.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0597]: `b` does not live long enough - --> $DIR/ref-escapes-but-not-over-yield.rs:11:13 - | -LL | let mut b = move || { - | _________________- -LL | | yield(); -LL | | let b = 5; -LL | | a = &b; - | | ^^ borrowed value does not live long enough -LL | | -LL | | }; - | | - - | | | - | | `b` dropped here while still borrowed - | |_____... and the borrow might be used here, when that temporary is dropped and runs the destructor for generator - | a temporary with access to the borrow is created here ... - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/generator/static-not-unpin.stderr b/src/test/ui/generator/static-not-unpin.stderr index 404d3069f79f3..f2b1078e2b532 100644 --- a/src/test/ui/generator/static-not-unpin.stderr +++ b/src/test/ui/generator/static-not-unpin.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]: std::marker::Unpin` is not satisfied - --> $DIR/static-not-unpin.rs:14:5 - | -LL | assert_unpin(generator); - | ^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]` - | -note: required by `assert_unpin` - --> $DIR/static-not-unpin.rs:7:1 + --> $DIR/static-not-unpin.rs:14:18 | LL | fn assert_unpin(_: T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------ ----- required by this bound in `assert_unpin` +... +LL | assert_unpin(generator); + | ^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]` error: aborting due to previous error diff --git a/src/test/ui/generic/generic-extern.stderr b/src/test/ui/generic/generic-extern.stderr index e7625abb1c831..c90215b612d4c 100644 --- a/src/test/ui/generic/generic-extern.stderr +++ b/src/test/ui/generic/generic-extern.stderr @@ -4,7 +4,7 @@ error[E0044]: foreign items may not have type parameters LL | fn foo(); | ^^^^^^^^^^^^ can't have type parameters | - = help: use specialization instead of type parameters by replacing them with concrete types like `u32` + = help: replace the type parameters with concrete types like `u32` error: aborting due to previous error diff --git a/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.rs b/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.rs new file mode 100644 index 0000000000000..cc93794e8fcdc --- /dev/null +++ b/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.rs @@ -0,0 +1,20 @@ +#![crate_type="lib"] + +// rust-lang/rust#61631: The use of `Self` in the defaults of generic +// types in a *trait* definition are allowed. +// +// It *must* be accepted; we have used this pattern extensively since +// Rust 1.0 (see e.g. `trait Add`). +trait Tnobound